conf.h: update syntax highlighting rules for neatmail summaries
[neatvi.git] / ex.c
blobf5588274cbf8915b9513b6c5e58a8aaaba80f379
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 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 static char xkwd[EXLEN]; /* the last searched keyword */
26 static char xrep[EXLEN]; /* the last replacement */
27 static int xkwddir; /* the last search direction */
28 static int xgdep; /* global command recursion depth */
30 static struct buf {
31 char ft[32];
32 char *path;
33 struct lbuf *lb;
34 int row, off, top;
35 long mtime; /* modification time */
36 } bufs[8];
38 static int bufs_find(char *path)
40 int i;
41 for (i = 0; i < LEN(bufs); i++)
42 if (bufs[i].lb && !strcmp(bufs[i].path, path))
43 return i;
44 return -1;
47 static void bufs_free(int idx)
49 if (bufs[idx].lb) {
50 free(bufs[idx].path);
51 lbuf_free(bufs[idx].lb);
52 memset(&bufs[idx], 0, sizeof(bufs[idx]));
56 static long mtime(char *path)
58 struct stat st;
59 if (!stat(path, &st))
60 return st.st_mtime;
61 return -1;
64 static int bufs_open(char *path)
66 int i;
67 for (i = 0; i < LEN(bufs) - 1; i++)
68 if (!bufs[i].lb)
69 break;
70 bufs_free(i);
71 bufs[i].path = uc_dup(path);
72 bufs[i].lb = lbuf_make();
73 bufs[i].row = 0;
74 bufs[i].off = 0;
75 bufs[i].top = 0;
76 bufs[i].mtime = -1;
77 strcpy(bufs[i].ft, syn_filetype(path));
78 return i;
81 static void bufs_swap(int i, int j)
83 struct buf tmp;
84 if (i == j)
85 return;
86 memcpy(&tmp, &bufs[i], sizeof(tmp));
87 memcpy(&bufs[i], &bufs[j], sizeof(tmp));
88 memcpy(&bufs[j], &tmp, sizeof(tmp));
91 static void bufs_switch(int idx)
93 if (idx > 1)
94 bufs_swap(0, 1);
95 bufs_swap(0, idx);
96 xrow = bufs[0].row;
97 xoff = bufs[0].off;
98 xtop = bufs[0].top;
101 char *ex_path(void)
103 return bufs[0].path;
106 struct lbuf *ex_lbuf(void)
108 return bufs[0].lb;
111 char *ex_filetype(void)
113 return bufs[0].ft;
116 /* read ex command location */
117 static char *ex_loc(char *s, char *loc)
119 while (*s == ':' || isspace((unsigned char) *s))
120 s++;
121 while (*s && !isalpha((unsigned char) *s) && *s != '=' && *s != '!') {
122 if (*s == '\'')
123 *loc++ = *s++;
124 if (*s == '/' || *s == '?') {
125 int d = *s;
126 *loc++ = *s++;
127 while (*s && *s != d) {
128 if (*s == '\\' && s[1])
129 *loc++ = *s++;
130 *loc++ = *s++;
133 if (*s)
134 *loc++ = *s++;
136 *loc = '\0';
137 return s;
140 /* read ex command name */
141 static char *ex_cmd(char *s, char *cmd)
143 char *cmd0 = cmd;
144 s = ex_loc(s, cmd);
145 while (isspace((unsigned char) *s))
146 s++;
147 while (isalpha((unsigned char) *s))
148 if ((*cmd++ = *s++) == 'k' && cmd == cmd0 + 1)
149 break;
150 if (*s == '!' || *s == '=')
151 *cmd++ = *s++;
152 *cmd = '\0';
153 return s;
156 /* read ex command argument */
157 static char *ex_arg(char *s, char *arg)
159 s = ex_cmd(s, arg);
160 while (isspace((unsigned char) *s))
161 s++;
162 while (*s && !isspace((unsigned char) *s)) {
163 if (*s == '\\' && s[1])
164 s++;
165 *arg++ = *s++;
167 *arg = '\0';
168 return s;
171 static char *ex_argeol(char *ec)
173 char arg[EXLEN];
174 char *s = ex_cmd(ec, arg);
175 while (isspace((unsigned char) *s))
176 s++;
177 return s;
180 /* the previous search keyword */
181 int ex_kwd(char **kwd, int *dir)
183 if (kwd)
184 *kwd = xkwd;
185 if (dir)
186 *dir = xkwddir;
187 return xkwddir == 0;
190 /* set the previous search keyword */
191 void ex_kwdset(char *kwd, int dir)
193 if (kwd) {
194 snprintf(xkwd, sizeof(xkwd), "%s", kwd);
195 reg_put('/', kwd, 0);
197 xkwddir = dir;
200 static int ex_search(char **pat)
202 struct sbuf *kw;
203 char *b = *pat;
204 char *e = b;
205 char *pats[1];
206 struct rset *re;
207 int dir, row;
208 kw = sbuf_make();
209 while (*++e) {
210 if (*e == **pat)
211 break;
212 sbuf_chr(kw, (unsigned char) *e);
213 if (*e == '\\' && e[1])
214 e++;
216 if (sbuf_len(kw))
217 ex_kwdset(sbuf_buf(kw), **pat == '/' ? 1 : -1);
218 sbuf_free(kw);
219 *pat = *e ? e + 1 : e;
220 if (ex_kwd(&pats[0], &dir))
221 return -1;
222 re = rset_make(1, pats, xic ? RE_ICASE : 0);
223 if (!re)
224 return -1;
225 row = xrow + dir;
226 while (row >= 0 && row < lbuf_len(xb)) {
227 if (rset_find(re, lbuf_get(xb, row), 0, NULL, 0) >= 0)
228 break;
229 row += dir;
231 rset_free(re);
232 return row >= 0 && row < lbuf_len(xb) ? row : -1;
235 static int ex_lineno(char **num)
237 int n = xrow;
238 switch ((unsigned char) **num) {
239 case '.':
240 *num += 1;
241 break;
242 case '$':
243 n = lbuf_len(xb) - 1;
244 *num += 1;
245 break;
246 case '\'':
247 if (lbuf_jump(xb, (unsigned char) *++(*num), &n, NULL))
248 return -1;
249 *num += 1;
250 break;
251 case '/':
252 case '?':
253 n = ex_search(num);
254 break;
255 default:
256 if (isdigit((unsigned char) **num)) {
257 n = atoi(*num) - 1;
258 while (isdigit((unsigned char) **num))
259 *num += 1;
262 while (**num == '-' || **num == '+') {
263 n += atoi((*num)++);
264 while (isdigit((unsigned char) **num))
265 (*num)++;
267 return n;
270 /* parse ex command location */
271 static int ex_region(char *loc, int *beg, int *end)
273 int naddr = 0;
274 if (!strcmp("%", loc)) {
275 *beg = 0;
276 *end = MAX(0, lbuf_len(xb));
277 return 0;
279 if (!*loc) {
280 *beg = xrow;
281 *end = xrow == lbuf_len(xb) ? xrow : xrow + 1;
282 return 0;
284 while (*loc) {
285 int end0 = *end;
286 *end = ex_lineno(&loc) + 1;
287 *beg = naddr++ ? end0 - 1 : *end - 1;
288 if (!naddr++)
289 *beg = *end - 1;
290 while (*loc && *loc != ';' && *loc != ',')
291 loc++;
292 if (!*loc)
293 break;
294 if (*loc == ';')
295 xrow = *end - 1;
296 loc++;
298 if (*beg < 0 || *beg >= lbuf_len(xb))
299 return 1;
300 if (*end < *beg || *end > lbuf_len(xb))
301 return 1;
302 return 0;
305 static int ec_write(char *ec);
307 static int ex_modifiedbuffer(char *msg)
309 if (!lbuf_modified(xb))
310 return 0;
311 if (xaw && ex_path()[0])
312 return ec_write("w");
313 if (msg)
314 ex_show(msg);
315 return 1;
318 static int ec_quit(char *ec)
320 char cmd[EXLEN];
321 ex_cmd(ec, cmd);
322 if (!strchr(cmd, '!'))
323 if (ex_modifiedbuffer("buffer modified\n"))
324 return 1;
325 xquit = 1;
326 return 0;
329 static int ex_expand(char *d, char *s)
331 while (*s) {
332 int c = (unsigned char) *s++;
333 if (c == '%') {
334 if (!bufs[0].path || !bufs[0].path[0]) {
335 ex_show("\"%\" is unset\n");
336 return 1;
338 strcpy(d, bufs[0].path);
339 d = strchr(d, '\0');
340 continue;
342 if (c == '#') {
343 if (!bufs[1].path || !bufs[1].path[0]) {
344 ex_show("\"#\" is unset\n");
345 return 1;
347 strcpy(d, bufs[1].path);
348 d = strchr(d, '\0');
349 continue;
351 if (c == '\\' && (*s == '%' || *s == '#'))
352 c = *s++;
353 *d++ = c;
355 *d = '\0';
356 return 0;
359 static int ec_edit(char *ec)
361 char msg[128];
362 char arg[EXLEN], cmd[EXLEN];
363 char path[EXLEN];
364 int fd;
365 ex_cmd(ec, cmd);
366 ex_arg(ec, arg);
367 if (!strchr(cmd, '!'))
368 if (xb && ex_modifiedbuffer("buffer modified\n"))
369 return 1;
370 if (ex_expand(path, arg))
371 return 1;
372 bufs[0].row = xrow;
373 bufs[0].off = xoff;
374 bufs[0].top = xtop;
375 if (arg[0] && bufs_find(path) >= 0) {
376 bufs_switch(bufs_find(path));
377 return 0;
379 if (path[0] || !bufs[0].path)
380 bufs_switch(bufs_open(path));
381 fd = open(ex_path(), O_RDONLY);
382 if (fd >= 0) {
383 int rd = lbuf_rd(xb, fd, 0, lbuf_len(xb));
384 close(fd);
385 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
386 ex_path(), lbuf_len(xb));
387 if (rd)
388 ex_show("read failed\n");
389 else
390 ex_show(msg);
392 lbuf_saved(xb, path[0] != '\0');
393 bufs[0].mtime = mtime(ex_path());
394 xrow = MAX(0, MIN(xrow, lbuf_len(xb) - 1));
395 xoff = 0;
396 xtop = MAX(0, MIN(xtop, lbuf_len(xb) - 1));
397 return 0;
400 static int ec_read(char *ec)
402 char arg[EXLEN], loc[EXLEN];
403 char msg[128];
404 int beg, end;
405 char *path;
406 char *obuf;
407 int n = lbuf_len(xb);
408 ex_arg(ec, arg);
409 ex_loc(ec, loc);
410 path = arg[0] ? arg : ex_path();
411 if (ex_region(loc, &beg, &end))
412 return 1;
413 if (arg[0] == '!') {
414 int pos = MIN(xrow + 1, lbuf_len(xb));
415 if (ex_expand(arg, ex_argeol(ec)))
416 return 1;
417 obuf = cmd_pipe(arg + 1, NULL, 0, 1);
418 if (obuf)
419 lbuf_edit(xb, obuf, pos, pos);
420 free(obuf);
421 } else {
422 int fd = open(path, O_RDONLY);
423 int pos = lbuf_len(xb) ? end : 0;
424 if (fd < 0) {
425 ex_show("read failed\n");
426 return 1;
428 if (lbuf_rd(xb, fd, pos, pos)) {
429 ex_show("read failed\n");
430 close(fd);
431 return 1;
433 close(fd);
435 xrow = end + lbuf_len(xb) - n - 1;
436 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
437 path, lbuf_len(xb) - n);
438 ex_show(msg);
439 return 0;
442 static int ec_write(char *ec)
444 char cmd[EXLEN], arg[EXLEN], loc[EXLEN];
445 char msg[128];
446 char *path;
447 char *ibuf;
448 int beg, end;
449 ex_cmd(ec, cmd);
450 ex_arg(ec, arg);
451 ex_loc(ec, loc);
452 path = arg[0] ? arg : ex_path();
453 if (cmd[0] == 'x' && !lbuf_modified(xb))
454 return ec_quit(cmd);
455 if (ex_region(loc, &beg, &end))
456 return 1;
457 if (!loc[0]) {
458 beg = 0;
459 end = lbuf_len(xb);
461 if (arg[0] == '!') {
462 if (ex_expand(arg, ex_argeol(ec)))
463 return 1;
464 ibuf = lbuf_cp(xb, beg, end);
465 ex_print(NULL);
466 cmd_pipe(arg + 1, ibuf, 1, 0);
467 free(ibuf);
468 } else {
469 int fd;
470 if (!strchr(cmd, '!') && bufs[0].path &&
471 !strcmp(bufs[0].path, path) &&
472 mtime(bufs[0].path) > bufs[0].mtime) {
473 ex_show("write failed: file changed\n");
474 return 1;
476 if (!strchr(cmd, '!') && arg[0] && mtime(arg) >= 0) {
477 ex_show("write failed: file exists\n");
478 return 1;
480 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
481 if (fd < 0) {
482 ex_show("write failed: cannot create file\n");
483 return 1;
485 if (lbuf_wr(xb, fd, beg, end)) {
486 ex_show("write failed\n");
487 close(fd);
488 return 1;
490 close(fd);
492 snprintf(msg, sizeof(msg), "\"%s\" %d lines [w]\n",
493 path, end - beg);
494 ex_show(msg);
495 if (!ex_path()[0]) {
496 free(bufs[0].path);
497 bufs[0].path = uc_dup(path);
499 if (!strcmp(ex_path(), path))
500 lbuf_saved(xb, 0);
501 if (!strcmp(ex_path(), path))
502 bufs[0].mtime = mtime(path);
503 if (cmd[0] == 'x' || (cmd[0] == 'w' && cmd[1] == 'q'))
504 ec_quit(cmd);
505 return 0;
508 static int ec_insert(char *ec)
510 char arg[EXLEN], cmd[EXLEN], loc[EXLEN];
511 struct sbuf *sb;
512 char *s;
513 int beg, end;
514 int n;
515 ex_arg(ec, arg);
516 ex_cmd(ec, cmd);
517 ex_loc(ec, loc);
518 if (ex_region(loc, &beg, &end) && (beg != 0 || end != 0))
519 return 1;
520 sb = sbuf_make();
521 while ((s = ex_read(""))) {
522 if (!strcmp(".", s)) {
523 free(s);
524 break;
526 sbuf_str(sb, s);
527 sbuf_chr(sb, '\n');
528 free(s);
530 if (cmd[0] == 'a')
531 if (beg + 1 <= lbuf_len(xb))
532 beg++;
533 if (cmd[0] != 'c')
534 end = beg;
535 n = lbuf_len(xb);
536 lbuf_edit(xb, sbuf_buf(sb), beg, end);
537 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
538 sbuf_free(sb);
539 return 0;
542 static int ec_print(char *ec)
544 char cmd[EXLEN], loc[EXLEN];
545 int beg, end;
546 int i;
547 ex_cmd(ec, cmd);
548 ex_loc(ec, loc);
549 if (!cmd[0] && !loc[0]) {
550 if (xrow >= lbuf_len(xb) - 1)
551 return 1;
552 xrow = xrow + 1;
554 if (ex_region(loc, &beg, &end))
555 return 1;
556 for (i = beg; i < end; i++)
557 ex_print(lbuf_get(xb, i));
558 xrow = end;
559 xoff = 0;
560 return 0;
563 static int ec_null(char *ec)
565 char loc[EXLEN];
566 int beg, end;
567 if (!xvis)
568 return ec_print(ec);
569 ex_loc(ec, loc);
570 if (ex_region(loc, &beg, &end))
571 return 1;
572 xrow = MAX(beg, end - 1);
573 xoff = 0;
574 return 0;
577 static void ex_yank(int reg, int beg, int end)
579 char *buf = lbuf_cp(xb, beg, end);
580 reg_put(reg, buf, 1);
581 free(buf);
584 static int ec_delete(char *ec)
586 char loc[EXLEN];
587 char arg[EXLEN];
588 int beg, end;
589 ex_loc(ec, loc);
590 ex_arg(ec, arg);
591 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
592 return 1;
593 ex_yank(arg[0], beg, end);
594 lbuf_edit(xb, NULL, beg, end);
595 xrow = beg;
596 return 0;
599 static int ec_yank(char *ec)
601 char loc[EXLEN];
602 char arg[EXLEN];
603 int beg, end;
604 ex_loc(ec, loc);
605 ex_arg(ec, arg);
606 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
607 return 1;
608 ex_yank(arg[0], beg, end);
609 return 0;
612 static int ec_put(char *ec)
614 char loc[EXLEN];
615 char arg[EXLEN];
616 int beg, end;
617 int lnmode;
618 char *buf;
619 int n = lbuf_len(xb);
620 ex_loc(ec, loc);
621 ex_arg(ec, arg);
622 buf = reg_get(arg[0], &lnmode);
623 if (!buf || ex_region(loc, &beg, &end))
624 return 1;
625 lbuf_edit(xb, buf, end, end);
626 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
627 return 0;
630 static int ec_lnum(char *ec)
632 char loc[EXLEN];
633 char msg[128];
634 int beg, end;
635 ex_loc(ec, loc);
636 if (ex_region(loc, &beg, &end))
637 return 1;
638 sprintf(msg, "%d\n", end);
639 ex_print(msg);
640 return 0;
643 static int ec_undo(char *ec)
645 return lbuf_undo(xb);
648 static int ec_redo(char *ec)
650 return lbuf_redo(xb);
653 static int ec_mark(char *ec)
655 char loc[EXLEN], arg[EXLEN];
656 int beg, end;
657 ex_arg(ec, arg);
658 ex_loc(ec, loc);
659 if (ex_region(loc, &beg, &end))
660 return 1;
661 lbuf_mark(xb, arg[0], end - 1, 0);
662 return 0;
665 static void replace(struct sbuf *dst, char *rep, char *ln, int *offs)
667 while (rep[0]) {
668 if (rep[0] == '\\' && rep[1]) {
669 if (rep[1] >= '0' && rep[1] <= '9') {
670 int grp = (rep[1] - '0') * 2;
671 int len = offs[grp + 1] - offs[grp];
672 sbuf_mem(dst, ln + offs[grp], len);
673 } else {
674 sbuf_chr(dst, (unsigned char) rep[1]);
676 rep++;
677 } else {
678 sbuf_chr(dst, (unsigned char) rep[0]);
680 rep++;
684 static int ec_substitute(char *ec)
686 char loc[EXLEN];
687 struct rset *re;
688 int offs[32];
689 int beg, end;
690 char *pats[1];
691 char *pat = NULL, *rep = NULL;
692 char *s;
693 int i;
694 ex_loc(ec, loc);
695 if (ex_region(loc, &beg, &end))
696 return 1;
697 s = ex_argeol(ec);
698 pat = re_read(&s);
699 if (pat && pat[0])
700 ex_kwdset(pat, +1);
701 if (pat && *s) {
702 s--;
703 rep = re_read(&s);
705 if (!rep)
706 rep = uc_dup(pat ? "" : xrep);
707 snprintf(xrep, sizeof(xrep), "%s", rep);
708 free(pat);
709 if (ex_kwd(&pats[0], NULL))
710 return 1;
711 re = rset_make(1, pats, xic ? RE_ICASE : 0);
712 if (!re) {
713 free(rep);
714 return 1;
716 for (i = beg; i < end; i++) {
717 char *ln = lbuf_get(xb, i);
718 struct sbuf *r = sbuf_make();
719 while (rset_find(re, ln, LEN(offs) / 2, offs, 0) >= 0) {
720 sbuf_mem(r, ln, offs[0]);
721 replace(r, rep, ln, offs);
722 ln += offs[1];
723 if (!*ln || !strchr(s, 'g'))
724 break;
725 if (offs[1] <= 0) /* zero-length match */
726 sbuf_chr(r, (unsigned char) *ln++);
728 sbuf_str(r, ln);
729 lbuf_edit(xb, sbuf_buf(r), i, i + 1);
730 sbuf_free(r);
732 rset_free(re);
733 free(rep);
734 return 0;
737 static int ec_exec(char *ec)
739 char loc[EXLEN];
740 char arg[EXLEN];
741 int beg, end;
742 char *text;
743 char *rep;
744 ex_modifiedbuffer(NULL);
745 ex_loc(ec, loc);
746 if (ex_expand(arg, ex_argeol(ec)))
747 return 1;
748 if (!loc[0]) {
749 ex_print(NULL);
750 return cmd_exec(arg);
752 if (ex_region(loc, &beg, &end))
753 return 1;
754 text = lbuf_cp(xb, beg, end);
755 rep = cmd_pipe(arg, text, 1, 1);
756 if (rep)
757 lbuf_edit(xb, rep, beg, end);
758 free(text);
759 free(rep);
760 return 0;
763 static int ec_make(char *ec)
765 char arg[EXLEN];
766 char make[EXLEN];
767 ex_modifiedbuffer(NULL);
768 if (ex_expand(arg, ex_argeol(ec)))
769 return 1;
770 sprintf(make, "make %s", arg);
771 ex_print(NULL);
772 if (cmd_exec(make))
773 return 1;
774 return 0;
777 static int ec_ft(char *ec)
779 char arg[EXLEN];
780 ex_arg(ec, arg);
781 if (arg[0])
782 snprintf(bufs[0].ft, sizeof(bufs[0].ft), "%s", arg);
783 else
784 ex_print(ex_filetype());
785 return 0;
788 static int ec_cmap(char *ec)
790 char cmd[EXLEN];
791 char arg[EXLEN];
792 ex_cmd(ec, cmd);
793 ex_arg(ec, arg);
794 if (arg[0])
795 xkmap_alt = conf_kmapfind(arg);
796 else
797 ex_print(conf_kmap(xkmap)[0]);
798 if (arg[0] && !strchr(cmd, '!'))
799 xkmap = xkmap_alt;
800 return 0;
803 static int ex_exec(char *ln);
805 static int ec_glob(char *ec)
807 char loc[EXLEN], cmd[EXLEN];
808 struct rset *re;
809 int offs[32];
810 int beg, end, not;
811 char *pats[1];
812 char *pat, *s;
813 int i;
814 ex_cmd(ec, cmd);
815 ex_loc(ec, loc);
816 if (!loc[0] && !xgdep)
817 strcpy(loc, "%");
818 if (ex_region(loc, &beg, &end))
819 return 1;
820 not = strchr(cmd, '!') || cmd[0] == 'v';
821 s = ex_argeol(ec);
822 pat = re_read(&s);
823 if (pat && pat[0])
824 ex_kwdset(pat, +1);
825 free(pat);
826 if (ex_kwd(&pats[0], NULL))
827 return 1;
828 if (!(re = rset_make(1, pats, xic ? RE_ICASE : 0)))
829 return 1;
830 xgdep++;
831 for (i = beg + 1; i < end; i++)
832 lbuf_globset(xb, i, xgdep);
833 i = beg;
834 while (i < lbuf_len(xb)) {
835 char *ln = lbuf_get(xb, i);
836 if ((rset_find(re, ln, LEN(offs) / 2, offs, 0) < 0) == not) {
837 xrow = i;
838 if (ex_exec(s))
839 break;
840 i = MIN(i, xrow);
842 while (i < lbuf_len(xb) && !lbuf_globget(xb, i, xgdep))
843 i++;
845 for (i = 0; i < lbuf_len(xb); i++)
846 lbuf_globget(xb, i, xgdep);
847 xgdep--;
848 rset_free(re);
849 return 0;
852 static struct option {
853 char *abbr;
854 char *name;
855 int *var;
856 } options[] = {
857 {"ai", "autoindent", &xai},
858 {"aw", "autowrite", &xaw},
859 {"ic", "ignorecase", &xic},
860 {"td", "textdirection", &xtd},
861 {"shape", "shape", &xshape},
862 {"order", "xorder", &xorder},
863 {"hl", "highlight", &xhl},
864 {"hll", "highlightline", &xhll},
867 static char *cutword(char *s, char *d)
869 while (isspace(*s))
870 s++;
871 while (*s && !isspace(*s))
872 *d++ = *s++;
873 while (isspace(*s))
874 s++;
875 *d = '\0';
876 return s;
879 static int ec_set(char *ec)
881 char arg[EXLEN];
882 char tok[EXLEN];
883 char opt[EXLEN];
884 char *s = arg;
885 int val = 0;
886 int i;
887 ex_arg(ec, arg);
888 if (*s) {
889 s = cutword(s, tok);
890 if (tok[0] == 'n' && tok[1] == 'o') {
891 strcpy(opt, tok + 2);
892 val = 0;
893 } else {
894 char *r = strchr(tok, '=');
895 if (r) {
896 *r = '\0';
897 strcpy(opt, tok);
898 val = atoi(r + 1);
899 } else {
900 strcpy(opt, tok);
901 val = 1;
904 for (i = 0; i < LEN(options); i++) {
905 struct option *o = &options[i];
906 if (!strcmp(o->abbr, opt) || !strcmp(o->name, opt)) {
907 *o->var = val;
908 return 0;
911 ex_show("unknown option");
912 return 1;
914 return 0;
917 static struct excmd {
918 char *abbr;
919 char *name;
920 int (*ec)(char *s);
921 } excmds[] = {
922 {"p", "print", ec_print},
923 {"a", "append", ec_insert},
924 {"i", "insert", ec_insert},
925 {"d", "delete", ec_delete},
926 {"c", "change", ec_insert},
927 {"e", "edit", ec_edit},
928 {"e!", "edit!", ec_edit},
929 {"g", "global", ec_glob},
930 {"g!", "global!", ec_glob},
931 {"=", "=", ec_lnum},
932 {"k", "mark", ec_mark},
933 {"pu", "put", ec_put},
934 {"q", "quit", ec_quit},
935 {"q!", "quit!", ec_quit},
936 {"r", "read", ec_read},
937 {"v", "vglobal", ec_glob},
938 {"w", "write", ec_write},
939 {"w!", "write!", ec_write},
940 {"wq", "wq", ec_write},
941 {"wq!", "wq!", ec_write},
942 {"u", "undo", ec_undo},
943 {"r", "redo", ec_redo},
944 {"se", "set", ec_set},
945 {"s", "substitute", ec_substitute},
946 {"x", "xit", ec_write},
947 {"x!", "xit!", ec_write},
948 {"ya", "yank", ec_yank},
949 {"!", "!", ec_exec},
950 {"make", "make", ec_make},
951 {"ft", "filetype", ec_ft},
952 {"cm", "cmap", ec_cmap},
953 {"cm!", "cmap!", ec_cmap},
954 {"", "", ec_null},
957 /* read an ex command and its arguments from src into dst */
958 static void ex_line(int (*ec)(char *s), char *dst, char **src)
960 if (!ec || (ec != ec_glob && ec != ec_exec)) {
961 while (**src && **src != '|' && **src != '\n')
962 *dst++ = *(*src)++;
963 *dst = '\0';
964 if (**src)
965 (*src)++;
966 } else { /* the rest of the line for :g and :! */
967 strcpy(dst, *src);
968 *src = strchr(*src, '\0');
972 /* execute a single ex command */
973 static int ex_exec(char *ln)
975 char ec[EXLEN];
976 char cmd[EXLEN];
977 int i;
978 int ret = 0;
979 while (*ln) {
980 ex_cmd(ln, cmd);
981 for (i = 0; i < LEN(excmds); i++) {
982 if (!strcmp(excmds[i].abbr, cmd) ||
983 !strcmp(excmds[i].name, cmd)) {
984 ex_line(excmds[i].ec, ec, &ln);
985 ret = excmds[i].ec(ec);
986 break;
989 if (i == LEN(excmds))
990 ex_line(NULL, ec, &ln);
992 return ret;
995 /* execute a single ex command */
996 void ex_command(char *ln)
998 ex_exec(ln);
999 lbuf_modified(xb);
1000 reg_put(':', ln, 0);
1003 /* ex main loop */
1004 void ex(void)
1006 while (!xquit) {
1007 char *ln = ex_read(":");
1008 if (ln)
1009 ex_command(ln);
1010 free(ln);
1014 int ex_init(char **files)
1016 char cmd[EXLEN];
1017 char *s = cmd;
1018 char *r = files[0] ? files[0] : "";
1019 *s++ = 'e';
1020 *s++ = ' ';
1021 while (*r && s + 2 < cmd + sizeof(cmd)) {
1022 if (*r == ' ')
1023 *s++ = '\\';
1024 *s++ = *r++;
1026 *s = '\0';
1027 if (ec_edit(cmd))
1028 return 1;
1029 if (getenv("EXINIT"))
1030 ex_command(getenv("EXINIT"));
1031 return 0;
1034 void ex_done(void)
1036 int i;
1037 for (i = 0; i < LEN(bufs); i++)
1038 bufs_free(i);