Introduction
Introduction Statistics Contact Development Disclaimer Help
tex.c - neatvi - [fork] simple vi-type editor with UTF-8 support
git clone git://src.adamsgaard.dk/neatvi
Log
Files
Refs
README
---
tex.c (20738B)
---
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include "vi.h"
9
10 int xrow, xoff, xtop; /* current row, column, and top row…
11 int xleft; /* the first visible column */
12 int xquit; /* exit if set */
13 int xvis; /* visual mode */
14 int xai = 1; /* autoindent option */
15 int xic = 1; /* ignorecase option */
16 int xaw; /* autowrite option */
17 int xhl = 1; /* syntax highlight option */
18 int xhll; /* highlight current line */
19 int xled = 1; /* use the line editor */
20 int xtd = +1; /* current text direction */
21 int xshape = 1; /* perform letter shaping */
22 int xorder = 1; /* change the order of characters…
23 int xkmap = 0; /* the current keymap */
24 int xkmap_alt = 1; /* the alternate keymap */
25 int xlim = 256; /* do not process lines longer th…
26 static char xkwd[EXLEN]; /* the last searched keyword */
27 static char xrep[EXLEN]; /* the last replacement */
28 static int xkwddir; /* the last search direction */
29 static int xgdep; /* global command recursion depth */
30
31 static struct buf {
32 char ft[32]; /* file type */
33 char *path; /* file path */
34 struct lbuf *lb;
35 int row, off, top;
36 short id, td; /* buffer id and text direction */
37 long mtime; /* modification time */
38 } bufs[8];
39
40 static int bufs_cnt = 0; /* number of allocated buffers */
41
42 static int bufs_find(char *path)
43 {
44 int i;
45 for (i = 0; i < LEN(bufs); i++)
46 if (bufs[i].lb && !strcmp(bufs[i].path, path))
47 return i;
48 return -1;
49 }
50
51 static void bufs_free(int idx)
52 {
53 if (bufs[idx].lb) {
54 free(bufs[idx].path);
55 lbuf_free(bufs[idx].lb);
56 memset(&bufs[idx], 0, sizeof(bufs[idx]));
57 }
58 }
59
60 static long mtime(char *path)
61 {
62 struct stat st;
63 if (!stat(path, &st))
64 return st.st_mtime;
65 return -1;
66 }
67
68 static int bufs_open(char *path)
69 {
70 int i;
71 for (i = 0; i < LEN(bufs) - 1; i++)
72 if (!bufs[i].lb)
73 break;
74 bufs_free(i);
75 bufs[i].id = ++bufs_cnt;
76 bufs[i].path = uc_dup(path);
77 bufs[i].lb = lbuf_make();
78 bufs[i].row = 0;
79 bufs[i].off = 0;
80 bufs[i].top = 0;
81 bufs[i].td = +1;
82 bufs[i].mtime = -1;
83 strcpy(bufs[i].ft, syn_filetype(path));
84 return i;
85 }
86
87 static void bufs_switch(int idx)
88 {
89 struct buf tmp;
90 bufs[0].row = xrow;
91 bufs[0].off = xoff;
92 bufs[0].top = xtop;
93 bufs[0].td = xtd;
94 memcpy(&tmp, &bufs[idx], sizeof(tmp));
95 memmove(&bufs[1], &bufs[0], sizeof(tmp) * idx);
96 memcpy(&bufs[0], &tmp, sizeof(tmp));
97 xrow = bufs[0].row;
98 xoff = bufs[0].off;
99 xtop = bufs[0].top;
100 xtd = bufs[0].td;
101 }
102
103 char *ex_path(void)
104 {
105 return bufs[0].path;
106 }
107
108 struct lbuf *ex_lbuf(void)
109 {
110 return bufs[0].lb;
111 }
112
113 char *ex_filetype(void)
114 {
115 return bufs[0].ft;
116 }
117
118 /* replace % and # with current and alternate path names; returns a stat…
119 static char *ex_pathexpand(char *src, int spaceallowed)
120 {
121 static char buf[1024];
122 char *dst = buf;
123 char *end = dst + sizeof(buf);
124 while (dst + 1 < end && *src && *src != '\n' &&
125 (spaceallowed || (*src != ' ' && *src != '\t')))…
126 if (*src == '%' || *src == '#') {
127 int idx = *src == '#';
128 if (!bufs[idx].path || !bufs[idx].path[0]) {
129 ex_show("pathname \"%\" or \"#\" is not …
130 return NULL;
131 }
132 dst += snprintf(dst, end - dst, "%s", bufs[idx].…
133 src++;
134 } else {
135 if (*src == '\\' && src[1])
136 src++;
137 *dst++ = *src++;
138 }
139 }
140 if (dst + 1 >= end)
141 dst = end - 1;
142 *dst = '\0';
143 return buf;
144 }
145
146 /* the previous search keyword */
147 int ex_kwd(char **kwd, int *dir)
148 {
149 if (kwd)
150 *kwd = xkwd;
151 if (dir)
152 *dir = xkwddir;
153 return xkwddir == 0;
154 }
155
156 /* set the previous search keyword */
157 void ex_kwdset(char *kwd, int dir)
158 {
159 if (kwd) {
160 snprintf(xkwd, sizeof(xkwd), "%s", kwd);
161 reg_put('/', kwd, 0);
162 }
163 xkwddir = dir;
164 }
165
166 static int ex_search(char **pat)
167 {
168 struct sbuf *kw;
169 char *b = *pat;
170 char *e = b;
171 char *pat_re;
172 struct rstr *re;
173 int dir, row;
174 kw = sbuf_make();
175 while (*++e) {
176 if (*e == **pat)
177 break;
178 sbuf_chr(kw, (unsigned char) *e);
179 if (*e == '\\' && e[1])
180 e++;
181 }
182 if (sbuf_len(kw))
183 ex_kwdset(sbuf_buf(kw), **pat == '/' ? 1 : -1);
184 sbuf_free(kw);
185 *pat = *e ? e + 1 : e;
186 if (ex_kwd(&pat_re, &dir))
187 return -1;
188 re = rstr_make(pat_re, xic ? RE_ICASE : 0);
189 if (!re)
190 return -1;
191 row = xrow + dir;
192 while (row >= 0 && row < lbuf_len(xb)) {
193 if (rstr_find(re, lbuf_get(xb, row), 0, NULL, 0) >= 0)
194 break;
195 row += dir;
196 }
197 rstr_free(re);
198 return row >= 0 && row < lbuf_len(xb) ? row : -1;
199 }
200
201 static int ex_lineno(char **num)
202 {
203 int n = xrow;
204 switch ((unsigned char) **num) {
205 case '.':
206 *num += 1;
207 break;
208 case '$':
209 n = lbuf_len(xb) - 1;
210 *num += 1;
211 break;
212 case '\'':
213 if (lbuf_jump(xb, (unsigned char) *++(*num), &n, NULL))
214 return -1;
215 *num += 1;
216 break;
217 case '/':
218 case '?':
219 n = ex_search(num);
220 break;
221 default:
222 if (isdigit((unsigned char) **num)) {
223 n = atoi(*num) - 1;
224 while (isdigit((unsigned char) **num))
225 *num += 1;
226 }
227 }
228 while (**num == '-' || **num == '+') {
229 n += atoi((*num)++);
230 while (isdigit((unsigned char) **num))
231 (*num)++;
232 }
233 return n;
234 }
235
236 /* parse ex command addresses */
237 static int ex_region(char *loc, int *beg, int *end)
238 {
239 int naddr = 0;
240 if (!strcmp("%", loc)) {
241 *beg = 0;
242 *end = MAX(0, lbuf_len(xb));
243 return 0;
244 }
245 if (!*loc) {
246 *beg = xrow;
247 *end = xrow == lbuf_len(xb) ? xrow : xrow + 1;
248 return 0;
249 }
250 while (*loc) {
251 int end0 = *end;
252 *end = ex_lineno(&loc) + 1;
253 *beg = naddr++ ? end0 - 1 : *end - 1;
254 if (!naddr++)
255 *beg = *end - 1;
256 while (*loc && *loc != ';' && *loc != ',')
257 loc++;
258 if (!*loc)
259 break;
260 if (*loc == ';')
261 xrow = *end - 1;
262 loc++;
263 }
264 if (*beg < 0 && *end == 0)
265 *beg = 0;
266 if (*beg < 0 || *beg >= lbuf_len(xb))
267 return 1;
268 if (*end < *beg || *end > lbuf_len(xb))
269 return 1;
270 return 0;
271 }
272
273 static int ec_write(char *loc, char *cmd, char *arg);
274
275 static int ex_modifiedbuffer(char *msg)
276 {
277 if (!lbuf_modified(xb))
278 return 0;
279 if (xaw && ex_path()[0])
280 return ec_write("", "w", "");
281 if (msg)
282 ex_show(msg);
283 return 1;
284 }
285
286 static int ec_buffer(char *loc, char *cmd, char *arg)
287 {
288 char ln[128];
289 int id;
290 int i;
291 id = arg[0] ? atoi(arg) : 0;
292 for (i = 0; i < LEN(bufs) && bufs[i].lb; i++) {
293 if (id) {
294 if (id == bufs[i].id)
295 break;
296 } else {
297 char c = i < 2 ? "%#"[i] : ' ';
298 snprintf(ln, LEN(ln), "%i %c %s",
299 (int) bufs[i].id, c, bufs[i].pat…
300 ex_print(ln);
301 }
302 }
303 if (id) {
304 if (i < LEN(bufs) && bufs[i].lb)
305 bufs_switch(i);
306 else
307 ex_show("no such buffer\n");
308 }
309 return 0;
310 }
311
312 static int ec_quit(char *loc, char *cmd, char *arg)
313 {
314 if (!strchr(cmd, '!'))
315 if (ex_modifiedbuffer("buffer modified\n"))
316 return 1;
317 xquit = 1;
318 return 0;
319 }
320
321 static int ec_edit(char *loc, char *cmd, char *arg)
322 {
323 char msg[128];
324 char *path;
325 int fd;
326 if (!strchr(cmd, '!'))
327 if (xb && ex_modifiedbuffer("buffer modified\n"))
328 return 1;
329 if (!(path = ex_pathexpand(arg, 0)))
330 return 1;
331 if (path[0] && bufs_find(path) >= 0) {
332 bufs_switch(bufs_find(path));
333 return 0;
334 }
335 if (path[0] || !bufs[0].path)
336 bufs_switch(bufs_open(path));
337 fd = open(ex_path(), O_RDONLY);
338 if (fd >= 0) {
339 int rd = lbuf_rd(xb, fd, 0, lbuf_len(xb));
340 close(fd);
341 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
342 ex_path(), lbuf_len(xb));
343 if (rd)
344 ex_show("read failed\n");
345 else
346 ex_show(msg);
347 }
348 lbuf_saved(xb, path[0] != '\0');
349 bufs[0].mtime = mtime(ex_path());
350 xrow = MAX(0, MIN(xrow, lbuf_len(xb) - 1));
351 xoff = 0;
352 xtop = MAX(0, MIN(xtop, lbuf_len(xb) - 1));
353 return 0;
354 }
355
356 static int ec_read(char *loc, char *cmd, char *arg)
357 {
358 char msg[128];
359 int beg, end, pos;
360 char *path;
361 char *obuf;
362 int n = lbuf_len(xb);
363 path = arg[0] ? arg : ex_path();
364 if (ex_region(loc, &beg, &end))
365 return 1;
366 pos = lbuf_len(xb) ? end : 0;
367 if (arg[0] == '!') {
368 char *ecmd = ex_pathexpand(arg, 1);
369 if (!ecmd)
370 return 1;
371 obuf = cmd_pipe(ecmd + 1, NULL, 0, 1);
372 if (obuf)
373 lbuf_edit(xb, obuf, pos, pos);
374 free(obuf);
375 } else {
376 int fd = open(path, O_RDONLY);
377 if (fd < 0) {
378 ex_show("read failed\n");
379 return 1;
380 }
381 if (lbuf_rd(xb, fd, pos, pos)) {
382 ex_show("read failed\n");
383 close(fd);
384 return 1;
385 }
386 close(fd);
387 }
388 xrow = end + lbuf_len(xb) - n - 1;
389 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
390 path, lbuf_len(xb) - n);
391 ex_show(msg);
392 return 0;
393 }
394
395 static int ec_write(char *loc, char *cmd, char *arg)
396 {
397 char msg[128];
398 char *path;
399 char *ibuf;
400 int beg, end;
401 path = arg[0] ? arg : ex_path();
402 if (cmd[0] == 'x' && !lbuf_modified(xb))
403 return ec_quit("", cmd, "");
404 if (ex_region(loc, &beg, &end))
405 return 1;
406 if (!loc[0]) {
407 beg = 0;
408 end = lbuf_len(xb);
409 }
410 if (arg[0] == '!') {
411 char *ecmd = ex_pathexpand(arg, 1);
412 if (!ecmd)
413 return 1;
414 ibuf = lbuf_cp(xb, beg, end);
415 ex_print(NULL);
416 cmd_pipe(ecmd + 1, ibuf, 1, 0);
417 free(ibuf);
418 } else {
419 int fd;
420 if (!strchr(cmd, '!') && bufs[0].path &&
421 !strcmp(bufs[0].path, path) &&
422 mtime(bufs[0].path) > bufs[0].mtime) {
423 ex_show("write failed: file changed\n");
424 return 1;
425 }
426 if (!strchr(cmd, '!') && arg[0] && mtime(arg) >= 0) {
427 ex_show("write failed: file exists\n");
428 return 1;
429 }
430 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, conf_mode(…
431 if (fd < 0) {
432 ex_show("write failed: cannot create file\n");
433 return 1;
434 }
435 if (lbuf_wr(xb, fd, beg, end)) {
436 ex_show("write failed\n");
437 close(fd);
438 return 1;
439 }
440 close(fd);
441 }
442 snprintf(msg, sizeof(msg), "\"%s\" %d lines [w]\n",
443 path, end - beg);
444 ex_show(msg);
445 if (!ex_path()[0]) {
446 free(bufs[0].path);
447 bufs[0].path = uc_dup(path);
448 }
449 if (!strcmp(ex_path(), path))
450 lbuf_saved(xb, 0);
451 if (!strcmp(ex_path(), path))
452 bufs[0].mtime = mtime(path);
453 if (cmd[0] == 'x' || (cmd[0] == 'w' && cmd[1] == 'q'))
454 ec_quit("", cmd, "");
455 return 0;
456 }
457
458 static int ec_insert(char *loc, char *cmd, char *arg)
459 {
460 struct sbuf *sb;
461 char *s;
462 int beg, end;
463 int n;
464 if (ex_region(loc, &beg, &end) && (beg != 0 || end != 0))
465 return 1;
466 sb = sbuf_make();
467 while ((s = ex_read(""))) {
468 if (!strcmp(".", s)) {
469 free(s);
470 break;
471 }
472 sbuf_str(sb, s);
473 sbuf_chr(sb, '\n');
474 free(s);
475 }
476 if (cmd[0] == 'a')
477 if (beg + 1 <= lbuf_len(xb))
478 beg++;
479 if (cmd[0] != 'c')
480 end = beg;
481 n = lbuf_len(xb);
482 lbuf_edit(xb, sbuf_buf(sb), beg, end);
483 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
484 sbuf_free(sb);
485 return 0;
486 }
487
488 static int ec_print(char *loc, char *cmd, char *arg)
489 {
490 int beg, end;
491 int i;
492 if (!cmd[0] && !loc[0])
493 if (xrow >= lbuf_len(xb))
494 return 1;
495 if (ex_region(loc, &beg, &end))
496 return 1;
497 for (i = beg; i < end; i++)
498 ex_print(lbuf_get(xb, i));
499 xrow = end;
500 xoff = 0;
501 return 0;
502 }
503
504 static int ec_null(char *loc, char *cmd, char *arg)
505 {
506 int beg, end;
507 if (!xvis)
508 return ec_print(loc, cmd, arg);
509 if (ex_region(loc, &beg, &end))
510 return 1;
511 xrow = MAX(beg, end - 1);
512 xoff = 0;
513 return 0;
514 }
515
516 static void ex_yank(int reg, int beg, int end)
517 {
518 char *buf = lbuf_cp(xb, beg, end);
519 reg_put(reg, buf, 1);
520 free(buf);
521 }
522
523 static int ec_delete(char *loc, char *cmd, char *arg)
524 {
525 int beg, end;
526 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
527 return 1;
528 ex_yank(arg[0], beg, end);
529 lbuf_edit(xb, NULL, beg, end);
530 xrow = beg;
531 return 0;
532 }
533
534 static int ec_yank(char *loc, char *cmd, char *arg)
535 {
536 int beg, end;
537 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
538 return 1;
539 ex_yank(arg[0], beg, end);
540 return 0;
541 }
542
543 static int ec_put(char *loc, char *cmd, char *arg)
544 {
545 int beg, end;
546 int lnmode;
547 char *buf;
548 int n = lbuf_len(xb);
549 buf = reg_get(arg[0], &lnmode);
550 if (!buf || ex_region(loc, &beg, &end))
551 return 1;
552 lbuf_edit(xb, buf, end, end);
553 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
554 return 0;
555 }
556
557 static int ec_lnum(char *loc, char *cmd, char *arg)
558 {
559 char msg[128];
560 int beg, end;
561 if (ex_region(loc, &beg, &end))
562 return 1;
563 sprintf(msg, "%d\n", end);
564 ex_print(msg);
565 return 0;
566 }
567
568 static int ec_undo(char *loc, char *cmd, char *arg)
569 {
570 return lbuf_undo(xb);
571 }
572
573 static int ec_redo(char *loc, char *cmd, char *arg)
574 {
575 return lbuf_redo(xb);
576 }
577
578 static int ec_mark(char *loc, char *cmd, char *arg)
579 {
580 int beg, end;
581 if (ex_region(loc, &beg, &end))
582 return 1;
583 lbuf_mark(xb, arg[0], end - 1, 0);
584 return 0;
585 }
586
587 static void replace(struct sbuf *dst, char *rep, char *ln, int *offs)
588 {
589 while (rep[0]) {
590 if (rep[0] == '\\' && rep[1]) {
591 if (rep[1] >= '0' && rep[1] <= '9') {
592 int grp = (rep[1] - '0') * 2;
593 int len = offs[grp + 1] - offs[grp];
594 sbuf_mem(dst, ln + offs[grp], len);
595 } else {
596 sbuf_chr(dst, (unsigned char) rep[1]);
597 }
598 rep++;
599 } else {
600 sbuf_chr(dst, (unsigned char) rep[0]);
601 }
602 rep++;
603 }
604 }
605
606 static int ec_substitute(char *loc, char *cmd, char *arg)
607 {
608 struct rstr *re;
609 int offs[32];
610 int beg, end;
611 char *pat = NULL, *rep = NULL;
612 char *s = arg;
613 int i;
614 if (ex_region(loc, &beg, &end))
615 return 1;
616 pat = re_read(&s);
617 if (pat && pat[0])
618 ex_kwdset(pat, +1);
619 if (pat && *s) {
620 s--;
621 rep = re_read(&s);
622 }
623 if (pat || rep)
624 snprintf(xrep, sizeof(xrep), "%s", rep ? rep : "");
625 free(pat);
626 free(rep);
627 if (ex_kwd(&pat, NULL))
628 return 1;
629 re = rstr_make(pat, xic ? RE_ICASE : 0);
630 if (!re)
631 return 1;
632 for (i = beg; i < end; i++) {
633 char *ln = lbuf_get(xb, i);
634 struct sbuf *r = NULL;
635 while (rstr_find(re, ln, LEN(offs) / 2, offs, 0) >= 0) {
636 if (!r)
637 r = sbuf_make();
638 sbuf_mem(r, ln, offs[0]);
639 replace(r, xrep, ln, offs);
640 ln += offs[1];
641 if (offs[1] <= 0) /* zero-length match */
642 sbuf_chr(r, (unsigned char) *ln++);
643 if (!*ln || *ln == '\n' || !strchr(s, 'g'))
644 break;
645 }
646 if (r) {
647 sbuf_str(r, ln);
648 lbuf_edit(xb, sbuf_buf(r), i, i + 1);
649 sbuf_free(r);
650 }
651 }
652 rstr_free(re);
653 return 0;
654 }
655
656 static int ec_exec(char *loc, char *cmd, char *arg)
657 {
658 int beg, end;
659 char *text;
660 char *rep;
661 char *ecmd;
662 ex_modifiedbuffer(NULL);
663 if (!(ecmd = ex_pathexpand(arg, 1)))
664 return 1;
665 if (!loc[0]) {
666 ex_print(NULL);
667 return cmd_exec(ecmd);
668 }
669 if (ex_region(loc, &beg, &end))
670 return 1;
671 text = lbuf_cp(xb, beg, end);
672 rep = cmd_pipe(ecmd, text, 1, 1);
673 if (rep)
674 lbuf_edit(xb, rep, beg, end);
675 free(text);
676 free(rep);
677 return 0;
678 }
679
680 static int ec_make(char *loc, char *cmd, char *arg)
681 {
682 char make[EXLEN];
683 char *target;
684 ex_modifiedbuffer(NULL);
685 if (!(target = ex_pathexpand(arg, 0)))
686 return 1;
687 sprintf(make, "make %s", target);
688 ex_print(NULL);
689 if (cmd_exec(make))
690 return 1;
691 return 0;
692 }
693
694 static int ec_ft(char *loc, char *cmd, char *arg)
695 {
696 if (arg[0])
697 snprintf(bufs[0].ft, sizeof(bufs[0].ft), "%s", arg);
698 else
699 ex_print(ex_filetype());
700 return 0;
701 }
702
703 static int ec_cmap(char *loc, char *cmd, char *arg)
704 {
705 if (arg[0])
706 xkmap_alt = conf_kmapfind(arg);
707 else
708 ex_print(conf_kmap(xkmap)[0]);
709 if (arg[0] && !strchr(cmd, '!'))
710 xkmap = xkmap_alt;
711 return 0;
712 }
713
714 static int ex_exec(char *ln);
715
716 static int ec_glob(char *loc, char *cmd, char *arg)
717 {
718 struct rstr *re;
719 int offs[32];
720 int beg, end, not;
721 char *pat;
722 char *s = arg;
723 int i;
724 if (!loc[0] && !xgdep)
725 strcpy(loc, "%");
726 if (ex_region(loc, &beg, &end))
727 return 1;
728 not = strchr(cmd, '!') || cmd[0] == 'v';
729 pat = re_read(&s);
730 if (pat && pat[0])
731 ex_kwdset(pat, +1);
732 free(pat);
733 if (ex_kwd(&pat, NULL))
734 return 1;
735 if (!(re = rstr_make(pat, xic ? RE_ICASE : 0)))
736 return 1;
737 xgdep++;
738 for (i = beg + 1; i < end; i++)
739 lbuf_globset(xb, i, xgdep);
740 i = beg;
741 while (i < lbuf_len(xb)) {
742 char *ln = lbuf_get(xb, i);
743 if ((rstr_find(re, ln, LEN(offs) / 2, offs, 0) < 0) == n…
744 xrow = i;
745 if (ex_exec(s))
746 break;
747 i = MIN(i, xrow);
748 }
749 while (i < lbuf_len(xb) && !lbuf_globget(xb, i, xgdep))
750 i++;
751 }
752 for (i = 0; i < lbuf_len(xb); i++)
753 lbuf_globget(xb, i, xgdep);
754 xgdep--;
755 rstr_free(re);
756 return 0;
757 }
758
759 static struct option {
760 char *abbr;
761 char *name;
762 int *var;
763 } options[] = {
764 {"ai", "autoindent", &xai},
765 {"aw", "autowrite", &xaw},
766 {"ic", "ignorecase", &xic},
767 {"td", "textdirection", &xtd},
768 {"shape", "shape", &xshape},
769 {"order", "xorder", &xorder},
770 {"hl", "highlight", &xhl},
771 {"hll", "highlightline", &xhll},
772 {"lim", "linelimit", &xlim},
773 };
774
775 static char *cutword(char *s, char *d)
776 {
777 while (isspace(*s))
778 s++;
779 while (*s && !isspace(*s))
780 *d++ = *s++;
781 while (isspace(*s))
782 s++;
783 *d = '\0';
784 return s;
785 }
786
787 static int ec_set(char *loc, char *cmd, char *arg)
788 {
789 char tok[EXLEN];
790 char opt[EXLEN];
791 char *s = arg;
792 int val = 0;
793 int i;
794 if (*s) {
795 s = cutword(s, tok);
796 if (tok[0] == 'n' && tok[1] == 'o') {
797 strcpy(opt, tok + 2);
798 val = 0;
799 } else {
800 char *r = strchr(tok, '=');
801 if (r) {
802 *r = '\0';
803 strcpy(opt, tok);
804 val = atoi(r + 1);
805 } else {
806 strcpy(opt, tok);
807 val = 1;
808 }
809 }
810 for (i = 0; i < LEN(options); i++) {
811 struct option *o = &options[i];
812 if (!strcmp(o->abbr, opt) || !strcmp(o->name, op…
813 *o->var = val;
814 return 0;
815 }
816 }
817 ex_show("unknown option");
818 return 1;
819 }
820 return 0;
821 }
822
823 static struct excmd {
824 char *abbr;
825 char *name;
826 int (*ec)(char *loc, char *cmd, char *arg);
827 } excmds[] = {
828 {"b", "buffer", ec_buffer},
829 {"p", "print", ec_print},
830 {"a", "append", ec_insert},
831 {"i", "insert", ec_insert},
832 {"d", "delete", ec_delete},
833 {"c", "change", ec_insert},
834 {"e", "edit", ec_edit},
835 {"e!", "edit!", ec_edit},
836 {"g", "global", ec_glob},
837 {"g!", "global!", ec_glob},
838 {"=", "=", ec_lnum},
839 {"k", "mark", ec_mark},
840 {"pu", "put", ec_put},
841 {"q", "quit", ec_quit},
842 {"q!", "quit!", ec_quit},
843 {"r", "read", ec_read},
844 {"v", "vglobal", ec_glob},
845 {"w", "write", ec_write},
846 {"w!", "write!", ec_write},
847 {"wq", "wq", ec_write},
848 {"wq!", "wq!", ec_write},
849 {"u", "undo", ec_undo},
850 {"redo", "redo", ec_redo},
851 {"se", "set", ec_set},
852 {"s", "substitute", ec_substitute},
853 {"x", "xit", ec_write},
854 {"x!", "xit!", ec_write},
855 {"ya", "yank", ec_yank},
856 {"!", "!", ec_exec},
857 {"make", "make", ec_make},
858 {"ft", "filetype", ec_ft},
859 {"cm", "cmap", ec_cmap},
860 {"cm!", "cmap!", ec_cmap},
861 {"", "", ec_null},
862 };
863
864 static int ex_idx(char *cmd)
865 {
866 int i;
867 for (i = 0; i < LEN(excmds); i++)
868 if (!strcmp(excmds[i].abbr, cmd) || !strcmp(excmds[i].na…
869 return i;
870 return -1;
871 }
872
873 /* read ex command addresses */
874 static char *ex_loc(char *src, char *loc)
875 {
876 while (*src == ':' || *src == ' ' || *src == '\t')
877 src++;
878 while (*src && !isalpha((unsigned char) *src) && *src != '=' && …
879 if (*src == '\'')
880 *loc++ = *src++;
881 if (*src == '/' || *src == '?') {
882 int d = *src;
883 *loc++ = *src++;
884 while (*src && *src != d) {
885 if (*src == '\\' && src[1])
886 *loc++ = *src++;
887 *loc++ = *src++;
888 }
889 }
890 if (*src)
891 *loc++ = *src++;
892 }
893 *loc = '\0';
894 return src;
895 }
896
897 /* read ex command name */
898 static char *ex_cmd(char *src, char *cmd)
899 {
900 char *cmd0 = cmd;
901 while (*src == ' ' || *src == '\t')
902 src++;
903 while (isalpha((unsigned char) *src) && cmd < cmd0 + 16)
904 if ((*cmd++ = *src++) == 'k' && cmd == cmd0 + 1)
905 break;
906 if (*src == '!' || *src == '=')
907 *cmd++ = *src++;
908 *cmd = '\0';
909 return src;
910 }
911
912 /* read ex command argument for excmd command */
913 static char *ex_arg(char *src, char *dst, char *excmd)
914 {
915 int c0 = excmd[0];
916 int c1 = excmd[1];
917 while (*src == ' ' || *src == '\t')
918 src++;
919 if (c0 == '!' || c0 == 'g' || c0 == 'v' ||
920 ((c0 == 'r' || c0 == 'w') && src[0] == '!')) {
921 while (*src && *src != '\n') {
922 if (*src == '\\' && src[1])
923 *dst++ = *src++;
924 *dst++ = *src++;
925 }
926 } else if ((c0 == 's' && c1 != 'e') || c0 == '&' || c0 == '~') {
927 int delim = *src;
928 int cnt = 2;
929 *dst++ = *src++;
930 while (*src && *src != '\n' && cnt > 0) {
931 if (*src == delim)
932 cnt--;
933 if (*src == '\\' && src[1])
934 *dst++ = *src++;
935 *dst++ = *src++;
936 }
937 }
938 while (*src && *src != '\n' && *src != '|' && *src != '"') {
939 if (*src == '\\' && src[1])
940 *dst++ = *src++;
941 *dst++ = *src++;
942 }
943 if (*src == '"') {
944 while (*src != '\n')
945 src++;
946 }
947 if (*src == '\n' || *src == '|')
948 src++;
949 *dst = '\0';
950 return src;
951 }
952
953 /* execute a single ex command */
954 static int ex_exec(char *ln)
955 {
956 char loc[EXLEN], cmd[EXLEN], arg[EXLEN];
957 int ret = 0;
958 if (strlen(ln) >= EXLEN) {
959 ex_show("command too long");
960 return 1;
961 }
962 while (*ln) {
963 int idx;
964 ln = ex_loc(ln, loc);
965 ln = ex_cmd(ln, cmd);
966 idx = ex_idx(cmd);
967 ln = ex_arg(ln, arg, idx >= 0 ? excmds[idx].abbr : "unkn…
968 if (idx >= 0)
969 ret = excmds[idx].ec(loc, cmd, arg);
970 }
971 return ret;
972 }
973
974 /* execute a single ex command */
975 void ex_command(char *ln)
976 {
977 ex_exec(ln);
978 lbuf_modified(xb);
979 reg_put(':', ln, 0);
980 }
981
982 /* ex main loop */
983 void ex(void)
984 {
985 while (!xquit) {
986 char *ln = ex_read(":");
987 if (ln)
988 ex_command(ln);
989 free(ln);
990 }
991 }
992
993 int ex_init(char **files)
994 {
995 char arg[EXLEN];
996 char *s = arg;
997 char *r = files[0] ? files[0] : "";
998 while (*r && s + 2 < arg + sizeof(arg)) {
999 if (*r == ' ' || *r == '%' || *r == '#')
1000 *s++ = '\\';
1001 *s++ = *r++;
1002 }
1003 *s = '\0';
1004 if (ec_edit("", "e", arg))
1005 return 1;
1006 if (getenv("EXINIT"))
1007 ex_command(getenv("EXINIT"));
1008 return 0;
1009 }
1010
1011 void ex_done(void)
1012 {
1013 int i;
1014 for (i = 0; i < LEN(bufs); i++)
1015 bufs_free(i);
1016 }
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.