vi: fix two compiler warnings on clang ver. 1000.11.45.5
[neatvi.git] / ex.c
blob70d2f7be6b7b74200bbd743aebd6d0123af5204b
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 (offs[1] <= 0)
723 sbuf_chr(r, (unsigned char) *ln++);
724 if (!strchr(s, 'g'))
725 break;
727 sbuf_str(r, ln);
728 lbuf_edit(xb, sbuf_buf(r), i, i + 1);
729 sbuf_free(r);
731 rset_free(re);
732 free(rep);
733 return 0;
736 static int ec_exec(char *ec)
738 char arg[EXLEN];
739 ex_modifiedbuffer(NULL);
740 if (ex_expand(arg, ex_argeol(ec)))
741 return 1;
742 ex_print(NULL);
743 if (cmd_exec(arg))
744 return 1;
745 return 0;
748 static int ec_make(char *ec)
750 char arg[EXLEN];
751 char make[EXLEN];
752 ex_modifiedbuffer(NULL);
753 if (ex_expand(arg, ex_argeol(ec)))
754 return 1;
755 sprintf(make, "make %s", arg);
756 ex_print(NULL);
757 if (cmd_exec(make))
758 return 1;
759 return 0;
762 static int ec_ft(char *ec)
764 char arg[EXLEN];
765 ex_arg(ec, arg);
766 if (arg[0])
767 snprintf(bufs[0].ft, sizeof(bufs[0].ft), "%s", arg);
768 else
769 ex_print(ex_filetype());
770 return 0;
773 static int ec_cmap(char *ec)
775 char cmd[EXLEN];
776 char arg[EXLEN];
777 ex_cmd(ec, cmd);
778 ex_arg(ec, arg);
779 if (arg[0])
780 xkmap_alt = conf_kmapfind(arg);
781 else
782 ex_print(conf_kmap(xkmap)[0]);
783 if (arg[0] && !strchr(cmd, '!'))
784 xkmap = xkmap_alt;
785 return 0;
788 static int ex_exec(char *ln);
790 static int ec_glob(char *ec)
792 char loc[EXLEN], cmd[EXLEN];
793 struct rset *re;
794 int offs[32];
795 int beg, end, not;
796 char *pats[1];
797 char *pat, *s;
798 int i;
799 ex_cmd(ec, cmd);
800 ex_loc(ec, loc);
801 if (!loc[0] && !xgdep)
802 strcpy(loc, "%");
803 if (ex_region(loc, &beg, &end))
804 return 1;
805 not = strchr(cmd, '!') || cmd[0] == 'v';
806 s = ex_argeol(ec);
807 pat = re_read(&s);
808 if (pat && pat[0])
809 ex_kwdset(pat, +1);
810 free(pat);
811 if (ex_kwd(&pats[0], NULL))
812 return 1;
813 if (!(re = rset_make(1, pats, xic ? RE_ICASE : 0)))
814 return 1;
815 xgdep++;
816 for (i = beg + 1; i < end; i++)
817 lbuf_globset(xb, i, xgdep);
818 i = beg;
819 while (i < lbuf_len(xb)) {
820 char *ln = lbuf_get(xb, i);
821 if ((rset_find(re, ln, LEN(offs) / 2, offs, 0) < 0) == not) {
822 xrow = i;
823 if (ex_exec(s))
824 break;
825 i = MIN(i, xrow);
827 while (i < lbuf_len(xb) && !lbuf_globget(xb, i, xgdep))
828 i++;
830 for (i = 0; i < lbuf_len(xb); i++)
831 lbuf_globget(xb, i, xgdep);
832 xgdep--;
833 rset_free(re);
834 return 0;
837 static struct option {
838 char *abbr;
839 char *name;
840 int *var;
841 } options[] = {
842 {"ai", "autoindent", &xai},
843 {"aw", "autowrite", &xaw},
844 {"ic", "ignorecase", &xic},
845 {"td", "textdirection", &xtd},
846 {"shape", "shape", &xshape},
847 {"order", "xorder", &xorder},
848 {"hl", "highlight", &xhl},
851 static char *cutword(char *s, char *d)
853 while (isspace(*s))
854 s++;
855 while (*s && !isspace(*s))
856 *d++ = *s++;
857 while (isspace(*s))
858 s++;
859 *d = '\0';
860 return s;
863 static int ec_set(char *ec)
865 char arg[EXLEN];
866 char tok[EXLEN];
867 char opt[EXLEN];
868 char *s = arg;
869 int val = 0;
870 int i;
871 ex_arg(ec, arg);
872 if (*s) {
873 s = cutword(s, tok);
874 if (tok[0] == 'n' && tok[1] == 'o') {
875 strcpy(opt, tok + 2);
876 val = 0;
877 } else {
878 char *r = strchr(tok, '=');
879 if (r) {
880 *r = '\0';
881 strcpy(opt, tok);
882 val = atoi(r + 1);
883 } else {
884 strcpy(opt, tok);
885 val = 1;
888 for (i = 0; i < LEN(options); i++) {
889 struct option *o = &options[i];
890 if (!strcmp(o->abbr, opt) || !strcmp(o->name, opt)) {
891 *o->var = val;
892 return 0;
895 ex_show("unknown option");
896 return 1;
898 return 0;
901 static struct excmd {
902 char *abbr;
903 char *name;
904 int (*ec)(char *s);
905 } excmds[] = {
906 {"p", "print", ec_print},
907 {"a", "append", ec_insert},
908 {"i", "insert", ec_insert},
909 {"d", "delete", ec_delete},
910 {"c", "change", ec_insert},
911 {"e", "edit", ec_edit},
912 {"e!", "edit!", ec_edit},
913 {"g", "global", ec_glob},
914 {"g!", "global!", ec_glob},
915 {"=", "=", ec_lnum},
916 {"k", "mark", ec_mark},
917 {"pu", "put", ec_put},
918 {"q", "quit", ec_quit},
919 {"q!", "quit!", ec_quit},
920 {"r", "read", ec_read},
921 {"v", "vglobal", ec_glob},
922 {"w", "write", ec_write},
923 {"w!", "write!", ec_write},
924 {"wq", "wq", ec_write},
925 {"wq!", "wq!", ec_write},
926 {"u", "undo", ec_undo},
927 {"r", "redo", ec_redo},
928 {"se", "set", ec_set},
929 {"s", "substitute", ec_substitute},
930 {"x", "xit", ec_write},
931 {"x!", "xit!", ec_write},
932 {"ya", "yank", ec_yank},
933 {"!", "!", ec_exec},
934 {"make", "make", ec_make},
935 {"ft", "filetype", ec_ft},
936 {"cm", "cmap", ec_cmap},
937 {"cm!", "cmap!", ec_cmap},
938 {"", "", ec_null},
941 /* read an ex command and its arguments from src into dst */
942 static void ex_line(int (*ec)(char *s), char *dst, char **src)
944 if (!ec || ec != ec_glob) {
945 while (**src && **src != '|' && **src != '\n')
946 *dst++ = *(*src)++;
947 *dst = '\0';
948 if (**src)
949 (*src)++;
950 } else { /* the rest of the line for :g */
951 strcpy(dst, *src);
952 *src = strchr(*src, '\0');
956 /* execute a single ex command */
957 static int ex_exec(char *ln)
959 char ec[EXLEN];
960 char cmd[EXLEN];
961 int i;
962 int ret = 0;
963 while (*ln) {
964 ex_cmd(ln, cmd);
965 for (i = 0; i < LEN(excmds); i++) {
966 if (!strcmp(excmds[i].abbr, cmd) ||
967 !strcmp(excmds[i].name, cmd)) {
968 ex_line(excmds[i].ec, ec, &ln);
969 ret = excmds[i].ec(ec);
970 break;
973 if (!xvis && !cmd[0])
974 ret = ec_print(ec);
975 if (i == LEN(excmds))
976 ex_line(NULL, ec, &ln);
978 return ret;
981 /* execute a single ex command */
982 void ex_command(char *ln)
984 ex_exec(ln);
985 lbuf_modified(xb);
986 reg_put(':', ln, 0);
989 /* ex main loop */
990 void ex(void)
992 while (!xquit) {
993 char *ln = ex_read(":");
994 if (ln)
995 ex_command(ln);
996 free(ln);
1000 int ex_init(char **files)
1002 char cmd[EXLEN];
1003 char *s = cmd;
1004 char *r = files[0] ? files[0] : "";
1005 *s++ = 'e';
1006 *s++ = ' ';
1007 while (*r && s + 2 < cmd + sizeof(cmd)) {
1008 if (*r == ' ')
1009 *s++ = '\\';
1010 *s++ = *r++;
1012 *s = '\0';
1013 if (ec_edit(cmd))
1014 return 1;
1015 if (getenv("EXINIT"))
1016 ex_command(getenv("EXINIT"));
1017 return 0;
1020 void ex_done(void)
1022 int i;
1023 for (i = 0; i < LEN(bufs); i++)
1024 bufs_free(i);