vi: explain when the screen is updated in vi()
[neatvi.git] / ex.c
blobca24c83e3c6d777b25c5efb821f74904f1f56921
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"
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 xled = 1; /* use the line editor */
19 int xtd = +1; /* current text direction */
20 int xshape = 1; /* perform letter shaping */
21 int xorder = 1; /* change the order of characters */
22 int xkmap = 0; /* the current keymap */
23 int xkmap_alt = 1; /* the alternate keymap */
24 static char xkwd[EXLEN]; /* the last searched keyword */
25 static char xrep[EXLEN]; /* the last replacement */
26 static int xkwddir; /* the last search direction */
27 static int xgdep; /* global command recursion depth */
29 static struct buf {
30 char ft[32];
31 char *path;
32 struct lbuf *lb;
33 int row, off, top;
34 long mtime; /* modification time */
35 } bufs[8];
37 static int bufs_find(char *path)
39 int i;
40 for (i = 0; i < LEN(bufs); i++)
41 if (bufs[i].lb && !strcmp(bufs[i].path, path))
42 return i;
43 return -1;
46 static void bufs_free(int idx)
48 if (bufs[idx].lb) {
49 free(bufs[idx].path);
50 lbuf_free(bufs[idx].lb);
51 memset(&bufs[idx], 0, sizeof(bufs[idx]));
55 static long mtime(char *path)
57 struct stat st;
58 if (!stat(path, &st))
59 return st.st_mtime;
60 return -1;
63 static int bufs_open(char *path)
65 int i;
66 for (i = 0; i < LEN(bufs) - 1; i++)
67 if (!bufs[i].lb)
68 break;
69 bufs_free(i);
70 bufs[i].path = uc_dup(path);
71 bufs[i].lb = lbuf_make();
72 bufs[i].row = 0;
73 bufs[i].off = 0;
74 bufs[i].top = 0;
75 bufs[i].mtime = -1;
76 strcpy(bufs[i].ft, syn_filetype(path));
77 return i;
80 static void bufs_swap(int i, int j)
82 struct buf tmp;
83 if (i == j)
84 return;
85 memcpy(&tmp, &bufs[i], sizeof(tmp));
86 memcpy(&bufs[i], &bufs[j], sizeof(tmp));
87 memcpy(&bufs[j], &tmp, sizeof(tmp));
90 static void bufs_switch(int idx)
92 if (idx > 1)
93 bufs_swap(0, 1);
94 bufs_swap(0, idx);
95 xrow = bufs[0].row;
96 xoff = bufs[0].off;
97 xtop = bufs[0].top;
100 char *ex_path(void)
102 return bufs[0].path;
105 struct lbuf *ex_lbuf(void)
107 return bufs[0].lb;
110 char *ex_filetype(void)
112 return xhl ? bufs[0].ft : "";
115 /* read ex command location */
116 static char *ex_loc(char *s, char *loc)
118 while (*s == ':' || isspace((unsigned char) *s))
119 s++;
120 while (*s && !isalpha((unsigned char) *s) && *s != '=' && *s != '!') {
121 if (*s == '\'')
122 *loc++ = *s++;
123 if (*s == '/' || *s == '?') {
124 int d = *s;
125 *loc++ = *s++;
126 while (*s && *s != d) {
127 if (*s == '\\' && s[1])
128 *loc++ = *s++;
129 *loc++ = *s++;
132 if (*s)
133 *loc++ = *s++;
135 *loc = '\0';
136 return s;
139 /* read ex command name */
140 static char *ex_cmd(char *s, char *cmd)
142 char *cmd0 = cmd;
143 s = ex_loc(s, cmd);
144 while (isspace((unsigned char) *s))
145 s++;
146 while (isalpha((unsigned char) *s))
147 if ((*cmd++ = *s++) == 'k' && cmd == cmd0 + 1)
148 break;
149 if (*s == '!' || *s == '=')
150 *cmd++ = *s++;
151 *cmd = '\0';
152 return s;
155 /* read ex command argument */
156 static char *ex_arg(char *s, char *arg)
158 s = ex_cmd(s, arg);
159 while (isspace((unsigned char) *s))
160 s++;
161 while (*s && !isspace((unsigned char) *s)) {
162 if (*s == '\\' && s[1])
163 s++;
164 *arg++ = *s++;
166 *arg = '\0';
167 return s;
170 static char *ex_argeol(char *ec)
172 char arg[EXLEN];
173 char *s = ex_cmd(ec, arg);
174 while (isspace((unsigned char) *s))
175 s++;
176 return s;
179 /* the previous search keyword */
180 int ex_kwd(char **kwd, int *dir)
182 if (kwd)
183 *kwd = xkwd;
184 if (dir)
185 *dir = xkwddir;
186 return xkwddir == 0;
189 /* set the previous search keyword */
190 void ex_kwdset(char *kwd, int dir)
192 if (kwd) {
193 snprintf(xkwd, sizeof(xkwd), "%s", kwd);
194 reg_put('/', kwd, 0);
196 xkwddir = dir;
199 static int ex_search(char **pat)
201 struct sbuf *kw;
202 char *b = *pat;
203 char *e = b;
204 char *pats[1];
205 struct rset *re;
206 int dir, row;
207 kw = sbuf_make();
208 while (*++e) {
209 if (*e == **pat)
210 break;
211 sbuf_chr(kw, (unsigned char) *e);
212 if (*e == '\\' && e[1])
213 e++;
215 if (sbuf_len(kw))
216 ex_kwdset(sbuf_buf(kw), **pat == '/' ? 1 : -1);
217 sbuf_free(kw);
218 *pat = *e ? e + 1 : e;
219 if (ex_kwd(&pats[0], &dir))
220 return -1;
221 re = rset_make(1, pats, xic ? RE_ICASE : 0);
222 if (!re)
223 return -1;
224 row = xrow + dir;
225 while (row >= 0 && row < lbuf_len(xb)) {
226 if (rset_find(re, lbuf_get(xb, row), 0, NULL, 0) >= 0)
227 break;
228 row += dir;
230 rset_free(re);
231 return row >= 0 && row < lbuf_len(xb) ? row : -1;
234 static int ex_lineno(char **num)
236 int n = xrow;
237 switch ((unsigned char) **num) {
238 case '.':
239 *num += 1;
240 break;
241 case '$':
242 n = lbuf_len(xb) - 1;
243 *num += 1;
244 break;
245 case '\'':
246 if (lbuf_jump(xb, (unsigned char) *++(*num), &n, NULL))
247 return -1;
248 *num += 1;
249 break;
250 case '/':
251 case '?':
252 n = ex_search(num);
253 break;
254 default:
255 if (isdigit((unsigned char) **num)) {
256 n = atoi(*num) - 1;
257 while (isdigit((unsigned char) **num))
258 *num += 1;
261 while (**num == '-' || **num == '+') {
262 n += atoi((*num)++);
263 while (isdigit((unsigned char) **num))
264 (*num)++;
266 return n;
269 /* parse ex command location */
270 static int ex_region(char *loc, int *beg, int *end)
272 int naddr = 0;
273 if (!strcmp("%", loc)) {
274 *beg = 0;
275 *end = MAX(0, lbuf_len(xb));
276 return 0;
278 if (!*loc) {
279 *beg = xrow;
280 *end = xrow == lbuf_len(xb) ? xrow : xrow + 1;
281 return 0;
283 while (*loc) {
284 int end0 = *end;
285 *end = ex_lineno(&loc) + 1;
286 *beg = naddr++ ? end0 - 1 : *end - 1;
287 if (!naddr++)
288 *beg = *end - 1;
289 while (*loc && *loc != ';' && *loc != ',')
290 loc++;
291 if (!*loc)
292 break;
293 if (*loc == ';')
294 xrow = *end - 1;
295 loc++;
297 if (*beg < 0 || *beg >= lbuf_len(xb))
298 return 1;
299 if (*end < *beg || *end > lbuf_len(xb))
300 return 1;
301 return 0;
304 static int ec_write(char *ec);
306 static int ex_modifiedbuffer(char *msg)
308 if (!lbuf_modified(xb))
309 return 0;
310 if (xaw && ex_path()[0])
311 return ec_write("w");
312 if (msg)
313 ex_show(msg);
314 return 1;
317 static int ec_quit(char *ec)
319 char cmd[EXLEN];
320 ex_cmd(ec, cmd);
321 if (!strchr(cmd, '!'))
322 if (ex_modifiedbuffer("buffer modified\n"))
323 return 1;
324 xquit = 1;
325 return 0;
328 static int ex_expand(char *d, char *s)
330 while (*s) {
331 int c = (unsigned char) *s++;
332 if (c == '%') {
333 if (!bufs[0].path || !bufs[0].path[0]) {
334 ex_show("\"%\" is unset\n");
335 return 1;
337 strcpy(d, bufs[0].path);
338 d = strchr(d, '\0');
339 continue;
341 if (c == '#') {
342 if (!bufs[1].path || !bufs[1].path[0]) {
343 ex_show("\"#\" is unset\n");
344 return 1;
346 strcpy(d, bufs[1].path);
347 d = strchr(d, '\0');
348 continue;
350 if (c == '\\' && (*s == '%' || *s == '#'))
351 c = *s++;
352 *d++ = c;
354 *d = '\0';
355 return 0;
358 static int ec_edit(char *ec)
360 char msg[128];
361 char arg[EXLEN], cmd[EXLEN];
362 char path[EXLEN];
363 int fd;
364 ex_cmd(ec, cmd);
365 ex_arg(ec, arg);
366 if (!strchr(cmd, '!'))
367 if (xb && ex_modifiedbuffer("buffer modified\n"))
368 return 1;
369 if (ex_expand(path, arg))
370 return 1;
371 bufs[0].row = xrow;
372 bufs[0].off = xoff;
373 bufs[0].top = xtop;
374 if (arg[0] && bufs_find(path) >= 0) {
375 bufs_switch(bufs_find(path));
376 return 0;
378 if (path[0] || !bufs[0].path)
379 bufs_switch(bufs_open(path));
380 fd = open(ex_path(), O_RDONLY);
381 if (fd >= 0) {
382 int rd = lbuf_rd(xb, fd, 0, lbuf_len(xb));
383 close(fd);
384 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
385 ex_path(), lbuf_len(xb));
386 if (rd)
387 ex_show("read failed\n");
388 else
389 ex_show(msg);
391 lbuf_saved(xb, path[0] != '\0');
392 bufs[0].mtime = mtime(ex_path());
393 xrow = MAX(0, MIN(xrow, lbuf_len(xb) - 1));
394 xoff = 0;
395 xtop = MAX(0, MIN(xtop, lbuf_len(xb) - 1));
396 return 0;
399 static int ec_read(char *ec)
401 char arg[EXLEN], loc[EXLEN];
402 char msg[128];
403 int beg, end;
404 char *path;
405 char *obuf;
406 int n = lbuf_len(xb);
407 ex_arg(ec, arg);
408 ex_loc(ec, loc);
409 path = arg[0] ? arg : ex_path();
410 if (ex_region(loc, &beg, &end))
411 return 1;
412 if (arg[0] == '!') {
413 int pos = MIN(xrow + 1, lbuf_len(xb));
414 if (ex_expand(arg, ex_argeol(ec)))
415 return 1;
416 obuf = cmd_pipe(arg + 1, NULL, 0, 1);
417 if (obuf)
418 lbuf_edit(xb, obuf, pos, pos);
419 free(obuf);
420 } else {
421 int fd = open(path, O_RDONLY);
422 int pos = lbuf_len(xb) ? end : 0;
423 if (fd < 0) {
424 ex_show("read failed\n");
425 return 1;
427 if (lbuf_rd(xb, fd, pos, pos)) {
428 ex_show("read failed\n");
429 close(fd);
430 return 1;
432 close(fd);
434 xrow = end + lbuf_len(xb) - n - 1;
435 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
436 path, lbuf_len(xb) - n);
437 ex_show(msg);
438 return 0;
441 static int ec_write(char *ec)
443 char cmd[EXLEN], arg[EXLEN], loc[EXLEN];
444 char msg[128];
445 char *path;
446 char *ibuf;
447 int beg, end;
448 ex_cmd(ec, cmd);
449 ex_arg(ec, arg);
450 ex_loc(ec, loc);
451 path = arg[0] ? arg : ex_path();
452 if (cmd[0] == 'x' && !lbuf_modified(xb))
453 return ec_quit(cmd);
454 if (ex_region(loc, &beg, &end))
455 return 1;
456 if (!loc[0]) {
457 beg = 0;
458 end = lbuf_len(xb);
460 if (arg[0] == '!') {
461 if (ex_expand(arg, ex_argeol(ec)))
462 return 1;
463 ibuf = lbuf_cp(xb, beg, end);
464 ex_print(NULL);
465 cmd_pipe(arg + 1, ibuf, 1, 0);
466 free(ibuf);
467 } else {
468 int fd;
469 if (!strchr(cmd, '!') && bufs[0].path &&
470 !strcmp(bufs[0].path, path) &&
471 mtime(bufs[0].path) > bufs[0].mtime) {
472 ex_show("write failed: file changed\n");
473 return 1;
475 if (!strchr(cmd, '!') && arg[0] && mtime(arg) >= 0) {
476 ex_show("write failed: file exists\n");
477 return 1;
479 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
480 if (fd < 0) {
481 ex_show("write failed: cannot create file\n");
482 return 1;
484 if (lbuf_wr(xb, fd, beg, end)) {
485 ex_show("write failed\n");
486 close(fd);
487 return 1;
489 close(fd);
491 snprintf(msg, sizeof(msg), "\"%s\" %d lines [w]\n",
492 path, end - beg);
493 ex_show(msg);
494 if (!ex_path()[0]) {
495 free(bufs[0].path);
496 bufs[0].path = uc_dup(path);
498 if (!strcmp(ex_path(), path))
499 lbuf_saved(xb, 0);
500 if (!strcmp(ex_path(), path))
501 bufs[0].mtime = mtime(path);
502 if (cmd[0] == 'x' || (cmd[0] == 'w' && cmd[1] == 'q'))
503 ec_quit(cmd);
504 return 0;
507 static int ec_insert(char *ec)
509 char arg[EXLEN], cmd[EXLEN], loc[EXLEN];
510 struct sbuf *sb;
511 char *s;
512 int beg, end;
513 int n;
514 ex_arg(ec, arg);
515 ex_cmd(ec, cmd);
516 ex_loc(ec, loc);
517 if (ex_region(loc, &beg, &end) && (beg != 0 || end != 0))
518 return 1;
519 sb = sbuf_make();
520 while ((s = ex_read(""))) {
521 if (!strcmp(".", s)) {
522 free(s);
523 break;
525 sbuf_str(sb, s);
526 sbuf_chr(sb, '\n');
527 free(s);
529 if (cmd[0] == 'a')
530 if (beg + 1 <= lbuf_len(xb))
531 beg++;
532 if (cmd[0] != 'c')
533 end = beg;
534 n = lbuf_len(xb);
535 lbuf_edit(xb, sbuf_buf(sb), beg, end);
536 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
537 sbuf_free(sb);
538 return 0;
541 static int ec_print(char *ec)
543 char cmd[EXLEN], loc[EXLEN];
544 int beg, end;
545 int i;
546 ex_cmd(ec, cmd);
547 ex_loc(ec, loc);
548 if (!cmd[0] && !loc[0]) {
549 if (xrow >= lbuf_len(xb) - 1)
550 return 1;
551 xrow = xrow + 1;
553 if (ex_region(loc, &beg, &end))
554 return 1;
555 for (i = beg; i < end; i++)
556 ex_print(lbuf_get(xb, i));
557 xrow = end;
558 xoff = 0;
559 return 0;
562 static int ec_null(char *ec)
564 char loc[EXLEN];
565 int beg, end;
566 if (!xvis)
567 return ec_print(ec);
568 ex_loc(ec, loc);
569 if (ex_region(loc, &beg, &end))
570 return 1;
571 xrow = MAX(beg, end - 1);
572 xoff = 0;
573 return 0;
576 static void ex_yank(int reg, int beg, int end)
578 char *buf = lbuf_cp(xb, beg, end);
579 reg_put(reg, buf, 1);
580 free(buf);
583 static int ec_delete(char *ec)
585 char loc[EXLEN];
586 char arg[EXLEN];
587 int beg, end;
588 ex_loc(ec, loc);
589 ex_arg(ec, arg);
590 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
591 return 1;
592 ex_yank(arg[0], beg, end);
593 lbuf_edit(xb, NULL, beg, end);
594 xrow = beg;
595 return 0;
598 static int ec_yank(char *ec)
600 char loc[EXLEN];
601 char arg[EXLEN];
602 int beg, end;
603 ex_loc(ec, loc);
604 ex_arg(ec, arg);
605 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
606 return 1;
607 ex_yank(arg[0], beg, end);
608 return 0;
611 static int ec_put(char *ec)
613 char loc[EXLEN];
614 char arg[EXLEN];
615 int beg, end;
616 int lnmode;
617 char *buf;
618 int n = lbuf_len(xb);
619 ex_loc(ec, loc);
620 ex_arg(ec, arg);
621 buf = reg_get(arg[0], &lnmode);
622 if (!buf || ex_region(loc, &beg, &end))
623 return 1;
624 lbuf_edit(xb, buf, end, end);
625 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
626 return 0;
629 static int ec_lnum(char *ec)
631 char loc[EXLEN];
632 char msg[128];
633 int beg, end;
634 ex_loc(ec, loc);
635 if (ex_region(loc, &beg, &end))
636 return 1;
637 sprintf(msg, "%d\n", end);
638 ex_print(msg);
639 return 0;
642 static int ec_undo(char *ec)
644 return lbuf_undo(xb);
647 static int ec_redo(char *ec)
649 return lbuf_redo(xb);
652 static int ec_mark(char *ec)
654 char loc[EXLEN], arg[EXLEN];
655 int beg, end;
656 ex_arg(ec, arg);
657 ex_loc(ec, loc);
658 if (ex_region(loc, &beg, &end))
659 return 1;
660 lbuf_mark(xb, arg[0], end - 1, 0);
661 return 0;
664 static void replace(struct sbuf *dst, char *rep, char *ln, int *offs)
666 while (rep[0]) {
667 if (rep[0] == '\\' && rep[1]) {
668 if (rep[1] >= '0' && rep[1] <= '9') {
669 int grp = (rep[1] - '0') * 2;
670 int len = offs[grp + 1] - offs[grp];
671 sbuf_mem(dst, ln + offs[grp], len);
672 } else {
673 sbuf_chr(dst, (unsigned char) rep[1]);
675 rep++;
676 } else {
677 sbuf_chr(dst, (unsigned char) rep[0]);
679 rep++;
683 static int ec_substitute(char *ec)
685 char loc[EXLEN];
686 struct rset *re;
687 int offs[32];
688 int beg, end;
689 char *pats[1];
690 char *pat = NULL, *rep = NULL;
691 char *s;
692 int i;
693 ex_loc(ec, loc);
694 if (ex_region(loc, &beg, &end))
695 return 1;
696 s = ex_argeol(ec);
697 pat = re_read(&s);
698 if (pat && pat[0])
699 ex_kwdset(pat, +1);
700 if (pat && *s) {
701 s--;
702 rep = re_read(&s);
704 if (!rep)
705 rep = uc_dup(pat ? "" : xrep);
706 snprintf(xrep, sizeof(xrep), "%s", rep);
707 free(pat);
708 if (ex_kwd(&pats[0], NULL))
709 return 1;
710 re = rset_make(1, pats, xic ? RE_ICASE : 0);
711 if (!re) {
712 free(rep);
713 return 1;
715 for (i = beg; i < end; i++) {
716 char *ln = lbuf_get(xb, i);
717 struct sbuf *r = sbuf_make();
718 while (rset_find(re, ln, LEN(offs) / 2, offs, 0) >= 0) {
719 sbuf_mem(r, ln, offs[0]);
720 replace(r, rep, ln, offs);
721 ln += offs[1];
722 if (!strchr(s, 'g'))
723 break;
725 sbuf_str(r, ln);
726 lbuf_edit(xb, sbuf_buf(r), i, i + 1);
727 sbuf_free(r);
729 rset_free(re);
730 free(rep);
731 return 0;
734 static int ec_exec(char *ec)
736 char arg[EXLEN];
737 ex_modifiedbuffer(NULL);
738 if (ex_expand(arg, ex_argeol(ec)))
739 return 1;
740 ex_print(NULL);
741 if (cmd_exec(arg))
742 return 1;
743 return 0;
746 static int ec_make(char *ec)
748 char arg[EXLEN];
749 char make[EXLEN];
750 ex_modifiedbuffer(NULL);
751 if (ex_expand(arg, ex_argeol(ec)))
752 return 1;
753 sprintf(make, "make %s", arg);
754 ex_print(NULL);
755 if (cmd_exec(make))
756 return 1;
757 return 0;
760 static int ec_ft(char *ec)
762 char arg[EXLEN];
763 ex_arg(ec, arg);
764 if (arg[0])
765 snprintf(bufs[0].ft, sizeof(bufs[0].ft), arg);
766 else
767 ex_print(ex_filetype());
768 return 0;
771 static int ec_cmap(char *ec)
773 char cmd[EXLEN];
774 char arg[EXLEN];
775 ex_cmd(ec, cmd);
776 ex_arg(ec, arg);
777 if (arg[0])
778 xkmap_alt = conf_kmapfind(arg);
779 else
780 ex_print(conf_kmap(xkmap)[0]);
781 if (arg[0] && !strchr(cmd, '!'))
782 xkmap = xkmap_alt;
783 return 0;
786 static int ex_exec(char *ln);
788 static int ec_glob(char *ec)
790 char loc[EXLEN], cmd[EXLEN];
791 struct rset *re;
792 int offs[32];
793 int beg, end, not;
794 char *pats[1];
795 char *pat, *s;
796 int i;
797 ex_cmd(ec, cmd);
798 ex_loc(ec, loc);
799 if (!loc[0] && !xgdep)
800 strcpy(loc, "%");
801 if (ex_region(loc, &beg, &end))
802 return 1;
803 not = strchr(cmd, '!') || cmd[0] == 'v';
804 s = ex_argeol(ec);
805 pat = re_read(&s);
806 if (pat && pat[0])
807 ex_kwdset(pat, +1);
808 free(pat);
809 if (ex_kwd(&pats[0], NULL))
810 return 1;
811 if (!(re = rset_make(1, pats, xic ? RE_ICASE : 0)))
812 return 1;
813 xgdep++;
814 for (i = beg + 1; i < end; i++)
815 lbuf_globset(xb, i, xgdep);
816 i = beg;
817 while (i < lbuf_len(xb)) {
818 char *ln = lbuf_get(xb, i);
819 if ((rset_find(re, ln, LEN(offs) / 2, offs, 0) < 0) == not) {
820 xrow = i;
821 if (ex_exec(s))
822 break;
823 i = MIN(i, xrow);
825 while (i < lbuf_len(xb) && !lbuf_globget(xb, i, xgdep))
826 i++;
828 for (i = 0; i < lbuf_len(xb); i++)
829 lbuf_globget(xb, i, xgdep);
830 xgdep--;
831 rset_free(re);
832 return 0;
835 static struct option {
836 char *abbr;
837 char *name;
838 int *var;
839 } options[] = {
840 {"ai", "autoindent", &xai},
841 {"aw", "autowrite", &xaw},
842 {"ic", "ignorecase", &xic},
843 {"td", "textdirection", &xtd},
844 {"shape", "shape", &xshape},
845 {"order", "xorder", &xorder},
846 {"hl", "highlight", &xhl},
849 static char *cutword(char *s, char *d)
851 while (isspace(*s))
852 s++;
853 while (*s && !isspace(*s))
854 *d++ = *s++;
855 while (isspace(*s))
856 s++;
857 *d = '\0';
858 return s;
861 static int ec_set(char *ec)
863 char arg[EXLEN];
864 char tok[EXLEN];
865 char opt[EXLEN];
866 char *s = arg;
867 int val = 0;
868 int i;
869 ex_arg(ec, arg);
870 if (*s) {
871 s = cutword(s, tok);
872 if (tok[0] == 'n' && tok[1] == 'o') {
873 strcpy(opt, tok + 2);
874 val = 0;
875 } else {
876 char *r = strchr(tok, '=');
877 if (r) {
878 *r = '\0';
879 strcpy(opt, tok);
880 val = atoi(r + 1);
881 } else {
882 strcpy(opt, tok);
883 val = 1;
886 for (i = 0; i < LEN(options); i++) {
887 struct option *o = &options[i];
888 if (!strcmp(o->abbr, opt) || !strcmp(o->name, opt)) {
889 *o->var = val;
890 return 0;
893 ex_show("unknown option");
894 return 1;
896 return 0;
899 static struct excmd {
900 char *abbr;
901 char *name;
902 int (*ec)(char *s);
903 } excmds[] = {
904 {"p", "print", ec_print},
905 {"a", "append", ec_insert},
906 {"i", "insert", ec_insert},
907 {"d", "delete", ec_delete},
908 {"c", "change", ec_insert},
909 {"e", "edit", ec_edit},
910 {"e!", "edit!", ec_edit},
911 {"g", "global", ec_glob},
912 {"g!", "global!", ec_glob},
913 {"=", "=", ec_lnum},
914 {"k", "mark", ec_mark},
915 {"pu", "put", ec_put},
916 {"q", "quit", ec_quit},
917 {"q!", "quit!", ec_quit},
918 {"r", "read", ec_read},
919 {"v", "vglobal", ec_glob},
920 {"w", "write", ec_write},
921 {"w!", "write!", ec_write},
922 {"wq", "wq", ec_write},
923 {"wq!", "wq!", ec_write},
924 {"u", "undo", ec_undo},
925 {"r", "redo", ec_redo},
926 {"se", "set", ec_set},
927 {"s", "substitute", ec_substitute},
928 {"x", "xit", ec_write},
929 {"x!", "xit!", ec_write},
930 {"ya", "yank", ec_yank},
931 {"!", "!", ec_exec},
932 {"make", "make", ec_make},
933 {"ft", "filetype", ec_ft},
934 {"cm", "cmap", ec_cmap},
935 {"cm!", "cmap!", ec_cmap},
936 {"", "", ec_null},
939 /* read an ex command and its arguments from src into dst */
940 static void ex_line(int (*ec)(char *s), char *dst, char **src)
942 if (!ec || ec != ec_glob) {
943 while (**src && **src != '|' && **src != '\n')
944 *dst++ = *(*src)++;
945 *dst = '\0';
946 if (**src)
947 (*src)++;
948 } else { /* the rest of the line for :g */
949 strcpy(dst, *src);
950 *src = strchr(*src, '\0');
954 /* execute a single ex command */
955 static int ex_exec(char *ln)
957 char ec[EXLEN];
958 char cmd[EXLEN];
959 int i;
960 int ret = 0;
961 while (*ln) {
962 ex_cmd(ln, cmd);
963 for (i = 0; i < LEN(excmds); i++) {
964 if (!strcmp(excmds[i].abbr, cmd) ||
965 !strcmp(excmds[i].name, cmd)) {
966 ex_line(excmds[i].ec, ec, &ln);
967 ret = excmds[i].ec(ec);
968 break;
971 if (!xvis && !cmd[0])
972 ret = ec_print(ec);
973 if (i == LEN(excmds))
974 ex_line(NULL, ec, &ln);
976 return ret;
979 /* execute a single ex command */
980 void ex_command(char *ln)
982 ex_exec(ln);
983 lbuf_modified(xb);
984 reg_put(':', ln, 0);
987 /* ex main loop */
988 void ex(void)
990 while (!xquit) {
991 char *ln = ex_read(":");
992 if (ln)
993 ex_command(ln);
994 free(ln);
998 int ex_init(char **files)
1000 char cmd[EXLEN];
1001 char *s = cmd;
1002 char *r = files[0] ? files[0] : "";
1003 *s++ = 'e';
1004 *s++ = ' ';
1005 while (*r && s + 2 < cmd + sizeof(cmd)) {
1006 if (*r == ' ')
1007 *s++ = '\\';
1008 *s++ = *r++;
1010 *s = '\0';
1011 if (ec_edit(cmd))
1012 return 1;
1013 if (getenv("EXINIT"))
1014 ex_command(getenv("EXINIT"));
1015 return 0;
1018 void ex_done(void)
1020 int i;
1021 for (i = 0; i < LEN(bufs); i++)
1022 bufs_free(i);