25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

346 satır
8.5KB

  1. /* vim.c - a small modal editor for the commodore 64, written for power c.
  2. *
  3. * Increment 2 edits: it reads a petscii SEQ file into one buffer, keeps a line
  4. * index, shows 24 lines plus a status row, and supports
  5. * move h j k l / arrows, 0 $ gg G
  6. * insert i a A I o O (RUN/STOP leaves insert mode, DEL backspaces)
  7. * change x dd p
  8. * colon :w :w name :wq :x :q :q!
  9. *
  10. * The buffer holds the file exactly as it sits on disk: petscii bytes with $0d
  11. * between lines. Keys are compared as numbers, never as character constants,
  12. * so nothing depends on how the compiler treats literals. (Unshifted letters
  13. * arrive as $41-$5a, so h = 72; shifted ones as $c1-$da, so G = 199.)
  14. */
  15. char *malloc();
  16. char *bfr; /* file text, $0d separated */
  17. unsigned blen; /* bytes used */
  18. unsigned lptr[600]; /* offset of each line start */
  19. int nlines;
  20. int cy, cx; /* cursor line and column */
  21. int top; /* first line on screen */
  22. int leftcol; /* horizontal scroll */
  23. char fname[24];
  24. int mode; /* 0 normal, 1 insert */
  25. int dirty; /* buffer changed since the last save */
  26. int pend; /* first key of a two key command: d or g */
  27. char *note; /* one-shot message for the status row */
  28. char ybuf[160]; /* the yanked line */
  29. int ylen, yok;
  30. /* screen rows are 0..23, the status row is 24 */
  31. /* shorten fname to what fits */
  32. shortn(n)
  33. int n;
  34. {
  35. int i;
  36. i = 0;
  37. while (fname[i] && i < n) i++;
  38. fname[i] = 0;
  39. return 0;
  40. }
  41. /* a message that waits for a key */
  42. msg(s)
  43. char *s;
  44. {
  45. sclr(24, 0, 40);
  46. sps(24, 0, s);
  47. skey();
  48. return 0;
  49. }
  50. /* read a line of lowercase petscii into s, echoed from column c of row 24 */
  51. getln(c, s, max)
  52. int c, max;
  53. char *s;
  54. {
  55. int n, k;
  56. n = 0;
  57. s[0] = 0;
  58. for (;;) {
  59. k = skey();
  60. if (k == 13) break;
  61. if (k == 3) {
  62. n = 0;
  63. s[0] = 0;
  64. break;
  65. }
  66. if (k == 20) {
  67. if (n > 0) {
  68. n--;
  69. s[n] = 0;
  70. }
  71. } else {
  72. if (k >= 0xc1 && k <= 0xda) k = k - 0x80;
  73. if (k >= 32 && k != 127 && n < max) {
  74. s[n] = k;
  75. n++;
  76. s[n] = 0;
  77. }
  78. }
  79. sclr(24, c, max);
  80. sps(24, c, s);
  81. }
  82. return n;
  83. }
  84. /* ask which file to open */
  85. askname()
  86. {
  87. sclr(24, 0, 40);
  88. sps(24, 0, "file: ");
  89. if (getln(6, fname, 20) == 0) fname[0] = 0;
  90. return 0;
  91. }
  92. /* read fname into bfr. 1 on success, 0 if it could not be opened */
  93. loadf()
  94. {
  95. int f, ch, prev, c;
  96. char on[28];
  97. int i;
  98. if (fname[0] == 0) return 1;
  99. i = 0;
  100. while (fname[i] && i < 20) {
  101. on[i] = fname[i];
  102. i++;
  103. }
  104. on[i++] = 44; /* , */
  105. on[i++] = 83; /* S (petscii, not ascii) */
  106. on[i++] = 44; /* , */
  107. on[i++] = 82; /* R */
  108. on[i] = 0;
  109. f = open(5, 8, 2, on);
  110. if (f == 0) return 0;
  111. blen = 0;
  112. prev = 0;
  113. for (;;) {
  114. ch = getc(5);
  115. if (ch < 0) break; /* end of file */
  116. if (ch == 26) break;
  117. if (ch == 10 && prev == 13) { /* crlf seen as two bytes */
  118. prev = ch;
  119. continue;
  120. }
  121. if (ch == 13) c = 13;
  122. else if (ch == 10) c = 13;
  123. else c = ch;
  124. if (blen < 18999) bfr[blen++] = c;
  125. prev = ch;
  126. }
  127. close(5);
  128. return 1;
  129. }
  130. /* find the start of every line */
  131. buildidx()
  132. {
  133. unsigned i;
  134. nlines = 1;
  135. lptr[0] = 0;
  136. for (i = 0; i < blen; i++) {
  137. if (bfr[i] == 13) {
  138. if (nlines < 599) {
  139. lptr[nlines] = i + 1;
  140. nlines++;
  141. }
  142. }
  143. }
  144. return 0;
  145. }
  146. /* the ":" command line. returns 1 when the editor should quit */
  147. doscmd()
  148. {
  149. int n, p, ok, qf;
  150. char cmd[24];
  151. sclr(24, 0, 40);
  152. spc(24, 0, 58); /* : */
  153. n = getln(1, cmd, 20);
  154. sclr(24, 0, 40);
  155. if (n == 0) return 0;
  156. if (cmd[0] == 81) { /* q, q! */
  157. if (cmd[1] == 33) return 1;
  158. if (dirty) {
  159. note = "unsaved - :q! quits";
  160. return 0;
  161. }
  162. return 1;
  163. }
  164. ok = 0;
  165. qf = 0;
  166. p = 1;
  167. if (cmd[0] == 87) ok = 1; /* w, wq, w name */
  168. if (cmd[0] == 88) { /* x */
  169. ok = 1;
  170. qf = 1;
  171. }
  172. if (ok == 0) {
  173. note = "unknown command";
  174. return 0;
  175. }
  176. if (cmd[0] == 87 && cmd[1] == 81) {
  177. qf = 1;
  178. p = 2;
  179. }
  180. while (cmd[p] == 32) p++;
  181. if (cmd[p]) {
  182. n = 0;
  183. while (cmd[p] && n < 20) fname[n++] = cmd[p++];
  184. fname[n] = 0;
  185. }
  186. if (fname[0] == 0) {
  187. note = "no file name";
  188. return 0;
  189. }
  190. if (savef()) {
  191. dirty = 0;
  192. note = "written";
  193. return qf;
  194. }
  195. note = "cannot write";
  196. return 0;
  197. }
  198. main()
  199. {
  200. int k, ok, p;
  201. sinit();
  202. mlinit(); /* machine code row painter */
  203. bfr = malloc(19000);
  204. if (bfr == 0) {
  205. sps(0, 0, "out of memory");
  206. skey();
  207. return;
  208. }
  209. blen = 0;
  210. nlines = 1;
  211. lptr[0] = 0;
  212. cy = 0;
  213. cx = 0;
  214. top = 0;
  215. leftcol = 0;
  216. fname[0] = 0;
  217. mode = 0;
  218. dirty = 0;
  219. pend = 0;
  220. note = 0;
  221. ylen = 0;
  222. yok = 0;
  223. askname();
  224. ok = loadf();
  225. shortn(20);
  226. buildidx();
  227. if (ok == 0) { /* keep the name: :w creates it */
  228. nlines = 1;
  229. blen = 0;
  230. note = "new file";
  231. }
  232. for (;;) {
  233. scroll();
  234. dall();
  235. k = skey();
  236. note = 0;
  237. if (mode) { /* ---- insert mode */
  238. if (k == 3) { /* RUN/STOP = Esc */
  239. mode = 0;
  240. if (cx > 0) cx--;
  241. } else if (k == 13) {
  242. newline();
  243. } else if (k == 20) {
  244. bkspace();
  245. } else if (arrow(k)) {
  246. cx = cx;
  247. } else if (k >= 32 && k < 128) {
  248. inschar(k);
  249. } else if (k >= 161) {
  250. inschar(k);
  251. }
  252. continue;
  253. }
  254. if (pend) { /* ---- second key of dd / gg */
  255. p = pend;
  256. pend = 0;
  257. if (p == 68 && k == 68) delline();
  258. if (p == 71 && k == 71) {
  259. cy = 0;
  260. cx = 0;
  261. }
  262. clampx();
  263. continue;
  264. }
  265. if (arrow(k)) {
  266. cx = cx;
  267. } else if (k == 72) { /* h */
  268. if (cx > 0) cx--;
  269. } else if (k == 76) { /* l */
  270. cx++;
  271. clampx();
  272. } else if (k == 74) { /* j */
  273. arrow(17);
  274. } else if (k == 75) { /* k */
  275. arrow(145);
  276. } else if (k == 48) { /* 0 */
  277. cx = 0;
  278. } else if (k == 36) { /* $ */
  279. cx = linend(cy) - lptr[cy];
  280. } else if (k == 199) { /* G */
  281. cy = nlines - 1;
  282. cx = 0;
  283. } else if (k == 68) { /* d.. */
  284. pend = 68;
  285. } else if (k == 71) { /* g.. */
  286. pend = 71;
  287. } else if (k == 88) { /* x */
  288. delchar();
  289. clampx();
  290. } else if (k == 80) { /* p */
  291. paste();
  292. } else if (k == 73) { /* i */
  293. mode = 1;
  294. } else if (k == 65) { /* a */
  295. cx++;
  296. clampx();
  297. mode = 1;
  298. } else if (k == 193) { /* A */
  299. cx = linend(cy) - lptr[cy];
  300. mode = 1;
  301. } else if (k == 201) { /* I */
  302. cx = 0;
  303. mode = 1;
  304. } else if (k == 79) { /* o */
  305. cx = linend(cy) - lptr[cy];
  306. newline();
  307. mode = 1;
  308. } else if (k == 207) { /* O */
  309. cx = 0;
  310. newline();
  311. cy--;
  312. mode = 1;
  313. } else if (k == 58) { /* : */
  314. if (doscmd() == 1) {
  315. sdone();
  316. return;
  317. }
  318. }
  319. }
  320. }

Powered by TurnKey Linux.