led: messages and ex prompts are always left-to-right
[neatvi.git] / ex.c
blob38af751607dc36086428438d341b2f3026e4cf9f
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 xdir = +1; /* current direction context */
20 int xshape = 1; /* perform letter shaping */
21 int xorder = 1; /* change the order of characters */
22 static char xkwd[EXLEN]; /* the last searched keyword */
23 static char xrep[EXLEN]; /* the last replacement */
24 static int xkwddir; /* the last search direction */
25 static char *xkmap = "en"; /* the current keymap */
26 static char xkmap2[8] = "fa"; /* the alternate keymap */
28 static struct buf {
29 char ft[32];
30 char *path;
31 struct lbuf *lb;
32 int row, off, top;
33 long mtime; /* modification time */
34 } bufs[8];
36 static int bufs_find(char *path)
38 int i;
39 for (i = 0; i < LEN(bufs); i++)
40 if (bufs[i].lb && !strcmp(bufs[i].path, path))
41 return i;
42 return -1;
45 static void bufs_free(int idx)
47 if (bufs[idx].lb) {
48 free(bufs[idx].path);
49 lbuf_free(bufs[idx].lb);
50 memset(&bufs[idx], 0, sizeof(bufs[idx]));
54 static long mtime(char *path)
56 struct stat st;
57 if (!stat(path, &st))
58 return st.st_mtime;
59 return -1;
62 static int bufs_open(char *path)
64 int i;
65 for (i = 0; i < LEN(bufs) - 1; i++)
66 if (!bufs[i].lb)
67 break;
68 bufs_free(i);
69 bufs[i].path = uc_dup(path);
70 bufs[i].lb = lbuf_make();
71 bufs[i].row = 0;
72 bufs[i].off = 0;
73 bufs[i].top = 0;
74 bufs[i].mtime = -1;
75 strcpy(bufs[i].ft, syn_filetype(path));
76 return i;
79 static void bufs_swap(int i, int j)
81 struct buf tmp;
82 if (i == j)
83 return;
84 memcpy(&tmp, &bufs[i], sizeof(tmp));
85 memcpy(&bufs[i], &bufs[j], sizeof(tmp));
86 memcpy(&bufs[j], &tmp, sizeof(tmp));
89 static void bufs_switch(int idx)
91 if (idx > 1)
92 bufs_swap(0, 1);
93 bufs_swap(0, idx);
94 xrow = bufs[0].row;
95 xoff = bufs[0].off;
96 xtop = bufs[0].top;
99 char *ex_path(void)
101 return bufs[0].path;
104 struct lbuf *ex_lbuf(void)
106 return bufs[0].lb;
109 char *ex_filetype(void)
111 return xhl ? bufs[0].ft : "";
114 char **ex_kmap(void)
116 return &xkmap;
119 char *ex_kmapalt(void)
121 return xkmap2;
124 /* read ex command location */
125 static char *ex_loc(char *s, char *loc)
127 while (*s == ':' || isspace((unsigned char) *s))
128 s++;
129 while (*s && !isalpha((unsigned char) *s) && *s != '=' && *s != '!') {
130 if (*s == '\'')
131 *loc++ = *s++;
132 if (*s == '/' || *s == '?') {
133 int d = *s;
134 *loc++ = *s++;
135 while (*s && *s != d) {
136 if (*s == '\\' && s[1])
137 *loc++ = *s++;
138 *loc++ = *s++;
141 if (*s)
142 *loc++ = *s++;
144 *loc = '\0';
145 return s;
148 /* read ex command name */
149 static char *ex_cmd(char *s, char *cmd)
151 char *cmd0 = cmd;
152 s = ex_loc(s, cmd);
153 while (isspace((unsigned char) *s))
154 s++;
155 while (isalpha((unsigned char) *s))
156 if ((*cmd++ = *s++) == 'k' && cmd == cmd0 + 1)
157 break;
158 if (*s == '!' || *s == '=')
159 *cmd++ = *s++;
160 *cmd = '\0';
161 return s;
164 /* read ex command argument */
165 static char *ex_arg(char *s, char *arg)
167 s = ex_cmd(s, arg);
168 while (isspace((unsigned char) *s))
169 s++;
170 while (*s && !isspace((unsigned char) *s)) {
171 if (*s == '\\' && s[1])
172 s++;
173 *arg++ = *s++;
175 *arg = '\0';
176 return s;
179 static char *ex_argeol(char *ec)
181 char arg[EXLEN];
182 char *s = ex_cmd(ec, arg);
183 while (isspace((unsigned char) *s))
184 s++;
185 return s;
188 /* the previous search keyword */
189 int ex_kwd(char **kwd, int *dir)
191 if (kwd)
192 *kwd = xkwd;
193 if (dir)
194 *dir = xkwddir;
195 return xkwddir == 0;
198 /* set the previous search keyword */
199 void ex_kwdset(char *kwd, int dir)
201 if (kwd) {
202 snprintf(xkwd, sizeof(xkwd), "%s", kwd);
203 reg_put('/', kwd, 0);
205 xkwddir = dir;
208 static int ex_search(char **pat)
210 struct sbuf *kw;
211 char *b = *pat;
212 char *e = b;
213 char *pats[1];
214 struct rset *re;
215 int dir, row;
216 kw = sbuf_make();
217 while (*++e) {
218 if (*e == **pat)
219 break;
220 sbuf_chr(kw, (unsigned char) *e);
221 if (*e == '\\' && e[1])
222 e++;
224 if (sbuf_len(kw))
225 ex_kwdset(sbuf_buf(kw), **pat == '/' ? 1 : -1);
226 sbuf_free(kw);
227 *pat = *e ? e + 1 : e;
228 if (ex_kwd(&pats[0], &dir))
229 return -1;
230 re = rset_make(1, pats, xic ? RE_ICASE : 0);
231 if (!re)
232 return -1;
233 row = xrow + dir;
234 while (row >= 0 && row < lbuf_len(xb)) {
235 if (rset_find(re, lbuf_get(xb, row), 0, NULL, 0) >= 0)
236 break;
237 row += dir;
239 rset_free(re);
240 return row >= 0 && row < lbuf_len(xb) ? row : -1;
243 static int ex_lineno(char **num)
245 int n = xrow;
246 switch ((unsigned char) **num) {
247 case '.':
248 *num += 1;
249 break;
250 case '$':
251 n = lbuf_len(xb) - 1;
252 *num += 1;
253 break;
254 case '\'':
255 if (lbuf_jump(xb, (unsigned char) *++(*num), &n, NULL))
256 return -1;
257 *num += 1;
258 break;
259 case '/':
260 case '?':
261 n = ex_search(num);
262 break;
263 default:
264 if (isdigit((unsigned char) **num)) {
265 n = atoi(*num) - 1;
266 while (isdigit((unsigned char) **num))
267 *num += 1;
270 while (**num == '-' || **num == '+') {
271 n += atoi((*num)++);
272 while (isdigit((unsigned char) **num))
273 (*num)++;
275 return n;
278 /* parse ex command location */
279 static int ex_region(char *loc, int *beg, int *end)
281 int naddr = 0;
282 if (!strcmp("%", loc)) {
283 *beg = 0;
284 *end = MAX(0, lbuf_len(xb));
285 return 0;
287 if (!*loc) {
288 *beg = xrow;
289 *end = xrow == lbuf_len(xb) ? xrow : xrow + 1;
290 return 0;
292 while (*loc) {
293 int end0 = *end;
294 *end = ex_lineno(&loc) + 1;
295 *beg = naddr++ ? end0 - 1 : *end - 1;
296 if (!naddr++)
297 *beg = *end - 1;
298 while (*loc && *loc != ';' && *loc != ',')
299 loc++;
300 if (!*loc)
301 break;
302 if (*loc == ';')
303 xrow = *end - 1;
304 loc++;
306 if (*beg < 0 || *beg >= lbuf_len(xb))
307 return 1;
308 if (*end < *beg || *end > lbuf_len(xb))
309 return 1;
310 return 0;
313 static int ec_write(char *ec);
315 static int ex_modifiedbuffer(char *msg)
317 if (!lbuf_modified(xb))
318 return 0;
319 if (xaw && ex_path()[0])
320 return ec_write("w");
321 if (msg)
322 ex_show(msg);
323 return 1;
326 static int ec_quit(char *ec)
328 char cmd[EXLEN];
329 ex_cmd(ec, cmd);
330 if (!strchr(cmd, '!'))
331 if (ex_modifiedbuffer("buffer modified\n"))
332 return 1;
333 xquit = 1;
334 return 0;
337 static int ex_expand(char *d, char *s)
339 while (*s) {
340 int c = (unsigned char) *s++;
341 if (c == '%') {
342 if (!bufs[0].path || !bufs[0].path[0]) {
343 ex_show("\"%\" is unset\n");
344 return 1;
346 strcpy(d, bufs[0].path);
347 d = strchr(d, '\0');
348 continue;
350 if (c == '#') {
351 if (!bufs[1].path || !bufs[1].path[0]) {
352 ex_show("\"#\" is unset\n");
353 return 1;
355 strcpy(d, bufs[1].path);
356 d = strchr(d, '\0');
357 continue;
359 if (c == '\\' && (*s == '%' || *s == '#'))
360 c = *s++;
361 *d++ = c;
363 *d = '\0';
364 return 0;
367 static int ec_edit(char *ec)
369 char msg[128];
370 char arg[EXLEN], cmd[EXLEN];
371 char path[EXLEN];
372 int fd;
373 ex_cmd(ec, cmd);
374 ex_arg(ec, arg);
375 if (!strchr(cmd, '!'))
376 if (xb && ex_modifiedbuffer("buffer modified\n"))
377 return 1;
378 if (ex_expand(path, arg))
379 return 1;
380 bufs[0].row = xrow;
381 bufs[0].off = xoff;
382 bufs[0].top = xtop;
383 if (arg[0] && bufs_find(path) >= 0) {
384 bufs_switch(bufs_find(path));
385 return 0;
387 if (path[0] || !bufs[0].path)
388 bufs_switch(bufs_open(path));
389 fd = open(ex_path(), O_RDONLY);
390 if (fd >= 0) {
391 int rd = lbuf_rd(xb, fd, 0, lbuf_len(xb));
392 close(fd);
393 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
394 ex_path(), lbuf_len(xb));
395 if (rd)
396 ex_show("read failed\n");
397 else
398 ex_show(msg);
400 lbuf_saved(xb, path[0] != '\0');
401 bufs[0].mtime = mtime(ex_path());
402 xrow = MAX(0, MIN(xrow, lbuf_len(xb) - 1));
403 xoff = 0;
404 xtop = MAX(0, MIN(xtop, lbuf_len(xb) - 1));
405 return 0;
408 static int ec_read(char *ec)
410 char arg[EXLEN], loc[EXLEN];
411 char msg[128];
412 int beg, end;
413 char *path;
414 char *obuf;
415 int n = lbuf_len(xb);
416 ex_arg(ec, arg);
417 ex_loc(ec, loc);
418 path = arg[0] ? arg : ex_path();
419 if (ex_region(loc, &beg, &end))
420 return 1;
421 if (arg[0] == '!') {
422 int pos = MIN(xrow + 1, lbuf_len(xb));
423 if (ex_expand(arg, ex_argeol(ec)))
424 return 1;
425 obuf = cmd_pipe(arg + 1, NULL, 0, 1);
426 if (obuf)
427 lbuf_edit(xb, obuf, pos, pos);
428 free(obuf);
429 } else {
430 int fd = open(path, O_RDONLY);
431 int pos = lbuf_len(xb) ? end : 0;
432 if (fd < 0) {
433 ex_show("read failed\n");
434 return 1;
436 if (lbuf_rd(xb, fd, pos, pos)) {
437 ex_show("read failed\n");
438 close(fd);
439 return 1;
441 close(fd);
443 xrow = end + lbuf_len(xb) - n - 1;
444 snprintf(msg, sizeof(msg), "\"%s\" %d lines [r]\n",
445 path, lbuf_len(xb) - n);
446 ex_show(msg);
447 return 0;
450 static int ec_write(char *ec)
452 char cmd[EXLEN], arg[EXLEN], loc[EXLEN];
453 char msg[128];
454 char *path;
455 char *ibuf;
456 int beg, end;
457 ex_cmd(ec, cmd);
458 ex_arg(ec, arg);
459 ex_loc(ec, loc);
460 path = arg[0] ? arg : ex_path();
461 if (cmd[0] == 'x' && !lbuf_modified(xb))
462 return ec_quit(cmd);
463 if (ex_region(loc, &beg, &end))
464 return 1;
465 if (!loc[0]) {
466 beg = 0;
467 end = lbuf_len(xb);
469 if (arg[0] == '!') {
470 if (ex_expand(arg, ex_argeol(ec)))
471 return 1;
472 ibuf = lbuf_cp(xb, beg, end);
473 ex_print(NULL);
474 cmd_pipe(arg + 1, ibuf, 1, 0);
475 free(ibuf);
476 } else {
477 int fd;
478 if (!strchr(cmd, '!') && bufs[0].path &&
479 !strcmp(bufs[0].path, path) &&
480 mtime(bufs[0].path) > bufs[0].mtime) {
481 ex_show("write failed: file changed\n");
482 return 1;
484 if (!strchr(cmd, '!') && arg[0] && mtime(arg) >= 0) {
485 ex_show("write failed: file exists\n");
486 return 1;
488 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
489 if (fd < 0) {
490 ex_show("write failed: cannot create file\n");
491 return 1;
493 if (lbuf_wr(xb, fd, beg, end)) {
494 ex_show("write failed\n");
495 close(fd);
496 return 1;
498 close(fd);
500 snprintf(msg, sizeof(msg), "\"%s\" %d lines [w]\n",
501 path, end - beg);
502 ex_show(msg);
503 if (!ex_path()[0]) {
504 free(bufs[0].path);
505 bufs[0].path = uc_dup(path);
507 if (!strcmp(ex_path(), path))
508 lbuf_saved(xb, 0);
509 if (!strcmp(ex_path(), path))
510 bufs[0].mtime = mtime(path);
511 if (cmd[0] == 'x' || (cmd[0] == 'w' && cmd[1] == 'q'))
512 ec_quit(cmd);
513 return 0;
516 static int ec_insert(char *ec)
518 char arg[EXLEN], cmd[EXLEN], loc[EXLEN];
519 struct sbuf *sb;
520 char *s;
521 int beg, end;
522 int n;
523 ex_arg(ec, arg);
524 ex_cmd(ec, cmd);
525 ex_loc(ec, loc);
526 if (ex_region(loc, &beg, &end) && (beg != 0 || end != 0))
527 return 1;
528 sb = sbuf_make();
529 while ((s = ex_read(""))) {
530 if (!strcmp(".", s)) {
531 free(s);
532 break;
534 sbuf_str(sb, s);
535 sbuf_chr(sb, '\n');
536 free(s);
538 if (cmd[0] == 'a')
539 if (beg + 1 <= lbuf_len(xb))
540 beg++;
541 if (cmd[0] != 'c')
542 end = beg;
543 n = lbuf_len(xb);
544 lbuf_edit(xb, sbuf_buf(sb), beg, end);
545 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
546 sbuf_free(sb);
547 return 0;
550 static int ec_print(char *ec)
552 char cmd[EXLEN], loc[EXLEN];
553 int beg, end;
554 int i;
555 ex_cmd(ec, cmd);
556 ex_loc(ec, loc);
557 if (!cmd[0] && !loc[0]) {
558 if (xrow >= lbuf_len(xb) - 1)
559 return 1;
560 xrow = xrow + 1;
562 if (ex_region(loc, &beg, &end))
563 return 1;
564 for (i = beg; i < end; i++)
565 ex_print(lbuf_get(xb, i));
566 xrow = end;
567 xoff = 0;
568 return 0;
571 static int ec_null(char *ec)
573 char loc[EXLEN];
574 int beg, end;
575 if (!xvis)
576 return ec_print(ec);
577 ex_loc(ec, loc);
578 if (ex_region(loc, &beg, &end))
579 return 1;
580 xrow = MAX(beg, end - 1);
581 xoff = 0;
582 return 0;
585 static void ex_yank(int reg, int beg, int end)
587 char *buf = lbuf_cp(xb, beg, end);
588 reg_put(reg, buf, 1);
589 free(buf);
592 static int ec_delete(char *ec)
594 char loc[EXLEN];
595 char arg[EXLEN];
596 int beg, end;
597 ex_loc(ec, loc);
598 ex_arg(ec, arg);
599 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
600 return 1;
601 ex_yank(arg[0], beg, end);
602 lbuf_edit(xb, NULL, beg, end);
603 xrow = beg;
604 return 0;
607 static int ec_yank(char *ec)
609 char loc[EXLEN];
610 char arg[EXLEN];
611 int beg, end;
612 ex_loc(ec, loc);
613 ex_arg(ec, arg);
614 if (ex_region(loc, &beg, &end) || !lbuf_len(xb))
615 return 1;
616 ex_yank(arg[0], beg, end);
617 return 0;
620 static int ec_put(char *ec)
622 char loc[EXLEN];
623 char arg[EXLEN];
624 int beg, end;
625 int lnmode;
626 char *buf;
627 int n = lbuf_len(xb);
628 ex_loc(ec, loc);
629 ex_arg(ec, arg);
630 buf = reg_get(arg[0], &lnmode);
631 if (!buf || ex_region(loc, &beg, &end))
632 return 1;
633 lbuf_edit(xb, buf, end, end);
634 xrow = MIN(lbuf_len(xb) - 1, end + lbuf_len(xb) - n - 1);
635 return 0;
638 static int ec_lnum(char *ec)
640 char loc[EXLEN];
641 char msg[128];
642 int beg, end;
643 ex_loc(ec, loc);
644 if (ex_region(loc, &beg, &end))
645 return 1;
646 sprintf(msg, "%d\n", end);
647 ex_print(msg);
648 return 0;
651 static int ec_undo(char *ec)
653 return lbuf_undo(xb);
656 static int ec_redo(char *ec)
658 return lbuf_redo(xb);
661 static int ec_mark(char *ec)
663 char loc[EXLEN], arg[EXLEN];
664 int beg, end;
665 ex_arg(ec, arg);
666 ex_loc(ec, loc);
667 if (ex_region(loc, &beg, &end))
668 return 1;
669 lbuf_mark(xb, arg[0], end - 1, 0);
670 return 0;
673 static void replace(struct sbuf *dst, char *rep, char *ln, int *offs)
675 while (rep[0]) {
676 if (rep[0] == '\\' && rep[1]) {
677 if (rep[1] >= '0' && rep[1] <= '9') {
678 int grp = (rep[1] - '0') * 2;
679 int len = offs[grp + 1] - offs[grp];
680 sbuf_mem(dst, ln + offs[grp], len);
681 } else {
682 sbuf_chr(dst, (unsigned char) rep[1]);
684 rep++;
685 } else {
686 sbuf_chr(dst, (unsigned char) rep[0]);
688 rep++;
692 static int ec_substitute(char *ec)
694 char loc[EXLEN];
695 struct rset *re;
696 int offs[32];
697 int beg, end;
698 char *pats[1];
699 char *pat = NULL, *rep = NULL;
700 char *s;
701 int i;
702 ex_loc(ec, loc);
703 if (ex_region(loc, &beg, &end))
704 return 1;
705 s = ex_argeol(ec);
706 pat = re_read(&s);
707 if (pat && pat[0])
708 ex_kwdset(pat, +1);
709 if (pat && *s) {
710 s--;
711 rep = re_read(&s);
713 if (!rep)
714 rep = uc_dup(pat ? "" : xrep);
715 snprintf(xrep, sizeof(xrep), "%s", rep);
716 free(pat);
717 if (ex_kwd(&pats[0], NULL))
718 return 1;
719 re = rset_make(1, pats, xic ? RE_ICASE : 0);
720 if (!re) {
721 free(rep);
722 return 1;
724 for (i = beg; i < end; i++) {
725 char *ln = lbuf_get(xb, i);
726 struct sbuf *r = sbuf_make();
727 while (rset_find(re, ln, LEN(offs) / 2, offs, 0) >= 0) {
728 sbuf_mem(r, ln, offs[0]);
729 replace(r, rep, ln, offs);
730 ln += offs[1];
731 if (!strchr(s, 'g'))
732 break;
734 sbuf_str(r, ln);
735 lbuf_edit(xb, sbuf_buf(r), i, i + 1);
736 sbuf_free(r);
738 rset_free(re);
739 free(rep);
740 return 0;
743 static int ec_exec(char *ec)
745 char arg[EXLEN];
746 ex_modifiedbuffer(NULL);
747 if (ex_expand(arg, ex_argeol(ec)))
748 return 1;
749 ex_print(NULL);
750 if (cmd_exec(arg))
751 return 1;
752 return 0;
755 static int ec_make(char *ec)
757 char arg[EXLEN];
758 char make[EXLEN];
759 ex_modifiedbuffer(NULL);
760 if (ex_expand(arg, ex_argeol(ec)))
761 return 1;
762 sprintf(make, "make %s", arg);
763 ex_print(NULL);
764 if (cmd_exec(make))
765 return 1;
766 return 0;
769 static int ec_ft(char *ec)
771 char arg[EXLEN];
772 ex_arg(ec, arg);
773 if (arg[0])
774 snprintf(bufs[0].ft, sizeof(bufs[0].ft), arg);
775 else
776 ex_print(ex_filetype());
777 return 0;
780 static int ec_cmap(char *ec)
782 char cmd[EXLEN];
783 char arg[EXLEN];
784 ex_cmd(ec, cmd);
785 ex_arg(ec, arg);
786 if (arg[0])
787 snprintf(xkmap2, sizeof(xkmap2), arg);
788 else
789 ex_print(xkmap);
790 if (arg[0] && !strchr(cmd, '!'))
791 xkmap = xkmap2;
792 return 0;
795 static int ex_exec(char *ln);
797 static int ec_glob(char *ec)
799 char loc[EXLEN], cmd[EXLEN];
800 struct rset *re;
801 int offs[32];
802 int beg, end, not;
803 char *pats[1];
804 char *pat, *s;
805 int i;
806 ex_cmd(ec, cmd);
807 ex_loc(ec, loc);
808 if (ex_region(loc, &beg, &end))
809 return 1;
810 not = strchr(cmd, '!') || cmd[0] == 'v';
811 s = ex_argeol(ec);
812 pat = re_read(&s);
813 if (pat && pat[0])
814 ex_kwdset(pat, +1);
815 free(pat);
816 if (ex_kwd(&pats[0], NULL))
817 return 1;
818 if (!(re = rset_make(1, pats, xic ? RE_ICASE : 0)))
819 return 1;
820 for (i = beg + 1; i < end; i++)
821 lbuf_glob(xb, i, 1);
822 i = beg;
823 while (i < lbuf_len(xb)) {
824 char *ln = lbuf_get(xb, i);
825 if ((rset_find(re, ln, LEN(offs) / 2, offs, 0) < 0) == not) {
826 xrow = i;
827 if (ex_exec(s))
828 break;
829 i = MIN(i, xrow);
831 while (i < lbuf_len(xb) && !lbuf_glob(xb, i, 0))
832 i++;
834 for (i = 0; i < lbuf_len(xb); i++)
835 lbuf_glob(xb, i, 0);
836 rset_free(re);
837 return 0;
840 static struct option {
841 char *abbr;
842 char *name;
843 int *var;
844 } options[] = {
845 {"ai", "autoindent", &xai},
846 {"aw", "autowrite", &xaw},
847 {"ic", "ignorecase", &xic},
848 {"td", "textdirection", &xdir},
849 {"shape", "shape", &xshape},
850 {"order", "xorder", &xorder},
851 {"hl", "highlight", &xhl},
854 static char *cutword(char *s, char *d)
856 while (isspace(*s))
857 s++;
858 while (*s && !isspace(*s))
859 *d++ = *s++;
860 while (isspace(*s))
861 s++;
862 *d = '\0';
863 return s;
866 static int ec_set(char *ec)
868 char arg[EXLEN];
869 char tok[EXLEN];
870 char opt[EXLEN];
871 char *s = arg;
872 int val = 0;
873 int i;
874 ex_arg(ec, arg);
875 if (*s) {
876 s = cutword(s, tok);
877 if (tok[0] == 'n' && tok[1] == 'o') {
878 strcpy(opt, tok + 2);
879 val = 0;
880 } else {
881 char *r = strchr(tok, '=');
882 if (r) {
883 *r = '\0';
884 strcpy(opt, tok);
885 val = atoi(r + 1);
886 } else {
887 strcpy(opt, tok);
888 val = 1;
891 for (i = 0; i < LEN(options); i++) {
892 struct option *o = &options[i];
893 if (!strcmp(o->abbr, opt) || !strcmp(o->name, opt)) {
894 *o->var = val;
895 return 0;
898 ex_show("unknown option");
899 return 1;
901 return 0;
904 static struct excmd {
905 char *abbr;
906 char *name;
907 int (*ec)(char *s);
908 } excmds[] = {
909 {"p", "print", ec_print},
910 {"a", "append", ec_insert},
911 {"i", "insert", ec_insert},
912 {"d", "delete", ec_delete},
913 {"c", "change", ec_insert},
914 {"e", "edit", ec_edit},
915 {"e!", "edit!", ec_edit},
916 {"g", "global", ec_glob},
917 {"g!", "global!", ec_glob},
918 {"=", "=", ec_lnum},
919 {"k", "mark", ec_mark},
920 {"pu", "put", ec_put},
921 {"q", "quit", ec_quit},
922 {"q!", "quit!", ec_quit},
923 {"r", "read", ec_read},
924 {"v", "vglobal", ec_glob},
925 {"w", "write", ec_write},
926 {"w!", "write!", ec_write},
927 {"wq", "wq", ec_write},
928 {"wq!", "wq!", ec_write},
929 {"u", "undo", ec_undo},
930 {"r", "redo", ec_redo},
931 {"se", "set", ec_set},
932 {"s", "substitute", ec_substitute},
933 {"x", "xit", ec_write},
934 {"x!", "xit!", ec_write},
935 {"ya", "yank", ec_yank},
936 {"!", "!", ec_exec},
937 {"make", "make", ec_make},
938 {"ft", "filetype", ec_ft},
939 {"cm", "cmap", ec_cmap},
940 {"cm!", "cmap!", ec_cmap},
941 {"", "", ec_null},
944 /* read an ex command and its arguments from src into dst */
945 static void ex_line(int (*ec)(char *s), char *dst, char **src)
947 if (!ec || ec != ec_glob) {
948 while (**src && **src != '|' && **src != '\n')
949 *dst++ = *(*src)++;
950 *dst = '\0';
951 if (**src)
952 (*src)++;
953 } else { /* the rest of the line for :g */
954 strcpy(dst, *src);
955 *src = strchr(*src, '\0');
959 /* execute a single ex command */
960 static int ex_exec(char *ln)
962 char ec[EXLEN];
963 char cmd[EXLEN];
964 int i;
965 int ret = 0;
966 while (*ln) {
967 ex_cmd(ln, cmd);
968 for (i = 0; i < LEN(excmds); i++) {
969 if (!strcmp(excmds[i].abbr, cmd) ||
970 !strcmp(excmds[i].name, cmd)) {
971 ex_line(excmds[i].ec, ec, &ln);
972 ret = excmds[i].ec(ec);
973 break;
976 if (!xvis && !cmd[0])
977 ret = ec_print(ec);
978 if (i == LEN(excmds))
979 ex_line(NULL, ec, &ln);
981 return ret;
984 /* execute a single ex command */
985 void ex_command(char *ln)
987 ex_exec(ln);
988 lbuf_modified(xb);
989 reg_put(':', ln, 0);
992 /* ex main loop */
993 void ex(void)
995 while (!xquit) {
996 char *ln = ex_read(":");
997 if (ln)
998 ex_command(ln);
999 free(ln);
1003 int ex_init(char **files)
1005 char cmd[EXLEN];
1006 char *s = cmd;
1007 char *r = files[0] ? files[0] : "";
1008 *s++ = 'e';
1009 *s++ = ' ';
1010 while (*r && s + 2 < cmd + sizeof(cmd)) {
1011 if (*r == ' ')
1012 *s++ = '\\';
1013 *s++ = *r++;
1015 *s = '\0';
1016 if (ec_edit(cmd))
1017 return 1;
1018 if (getenv("EXINIT"))
1019 ex_command(getenv("EXINIT"));
1020 return 0;
1023 void ex_done(void)
1025 int i;
1026 for (i = 0; i < LEN(bufs); i++)
1027 bufs_free(i);