add destdin and vgrindt
[unix-history] / usr / src / usr.bin / ex / ex_cmds.c
CommitLineData
7c4625ef 1/* Copyright (c) 1980 Regents of the University of California */
bdbbb330 2static char *sccsid = "@(#)ex_cmds.c 5.3 %G%";
d9fbdd64
MH
3#include "ex.h"
4#include "ex_argv.h"
5#include "ex_temp.h"
6#include "ex_tty.h"
7
8bool pflag, nflag;
9int poffset;
10
11#define nochng() lchng = chng
12
13/*
14 * Main loop for command mode command decoding.
15 * A few commands are executed here, but main function
16 * is to strip command addresses, do a little address oriented
17 * processing and call command routines to do the real work.
18 */
19commands(noprompt, exitoneof)
20 bool noprompt, exitoneof;
21{
22 register line *addr;
23 register int c;
24 register int lchng;
25 int given;
26 int seensemi;
27 int cnt;
28 bool hadpr;
29
30 resetflav();
31 nochng();
32 for (;;) {
33 /*
34 * If dot at last command
35 * ended up at zero, advance to one if there is a such.
36 */
37 if (dot <= zero) {
38 dot = zero;
39 if (dol > zero)
40 dot = one;
41 }
42 shudclob = 0;
43
44 /*
45 * If autoprint or trailing print flags,
46 * print the line at the specified offset
47 * before the next command.
48 */
49 if (pflag ||
50 lchng != chng && value(AUTOPRINT) && !inglobal && !inopen && endline) {
51 pflag = 0;
52 nochng();
53 if (dol != zero) {
54 addr1 = addr2 = dot + poffset;
55 if (addr1 < one || addr1 > dol)
56error("Offset out-of-bounds|Offset after command too large");
57 setdot1();
58 goto print;
59 }
60 }
61 nochng();
62
63 /*
64 * Print prompt if appropriate.
65 * If not in global flush output first to prevent
66 * going into pfast mode unreasonably.
67 */
68 if (inglobal == 0) {
69 flush();
70 if (!hush && value(PROMPT) && !globp && !noprompt && endline) {
71 putchar(':');
72 hadpr = 1;
73 }
74 TSYNC();
75 }
76
77 /*
78 * Gobble up the address.
79 * Degenerate addresses yield ".".
80 */
81 addr2 = 0;
82 given = seensemi = 0;
83 do {
84 addr1 = addr2;
85 addr = address(0);
86 c = getcd();
87 if (addr == 0)
88 if (c == ',')
89 addr = dot;
90 else if (addr1 != 0) {
91 addr2 = dot;
92 break;
93 } else
94 break;
95 addr2 = addr;
96 given++;
97 if (c == ';') {
98 c = ',';
99 dot = addr;
100 seensemi = 1;
101 }
102 } while (c == ',');
103 if (c == '%') {
104 /* %: same as 1,$ */
105 addr1 = one;
106 addr2 = dol;
107 given = 2;
108 c = getchar();
109 }
110 if (addr1 == 0)
111 addr1 = addr2;
112 if (c == ':')
113 c = getchar();
114
115 /*
116 * Set command name for special character commands.
117 */
118 tailspec(c);
119
120 /*
121 * If called via : escape from open or visual, limit
122 * the set of available commands here to save work below.
123 */
124 if (inopen) {
125 if (c=='\n' || c=='\r' || c==CTRL(d) || c==EOF) {
126 if (addr2)
127 dot = addr2;
128 if (c == EOF)
129 return;
130 continue;
131 }
132 if (any(c, "o"))
133notinvis:
134 tailprim(Command, 1, 1);
135 }
136choice:
137 switch (c) {
138
139 case 'a':
140
d266c416
MH
141 switch(peekchar()) {
142 case 'b':
143/* abbreviate */
144 tail("abbreviate");
145 setnoaddr();
146 mapcmd(0, 1);
147 anyabbrs = 1;
148 continue;
149 case 'r':
d9fbdd64
MH
150/* args */
151 tail("args");
152 setnoaddr();
153 eol();
154 pargs();
155 continue;
156 }
157
158/* append */
159 if (inopen)
160 goto notinvis;
161 tail("append");
162 setdot();
163 aiflag = exclam();
164 newline();
d266c416 165 vmacchng(0);
d9fbdd64
MH
166 deletenone();
167 setin(addr2);
d266c416 168 inappend = 1;
d9fbdd64 169 ignore(append(gettty, addr2));
d266c416 170 inappend = 0;
d9fbdd64
MH
171 nochng();
172 continue;
173
174 case 'c':
175 switch (peekchar()) {
176
177/* copy */
178 case 'o':
179 tail("copy");
d266c416 180 vmacchng(0);
d9fbdd64
MH
181 move();
182 continue;
183
184#ifdef CHDIR
185/* cd */
186 case 'd':
187 tail("cd");
188 goto changdir;
189
190/* chdir */
191 case 'h':
192 ignchar();
193 if (peekchar() == 'd') {
194 register char *p;
195 tail2of("chdir");
196changdir:
197 if (savedfile[0] == '/' || !value(WARN))
198 ignore(exclam());
199 else
200 ignore(quickly());
201 if (skipend()) {
202 p = getenv("HOME");
203 if (p == NULL)
204 error("Home directory unknown");
205 } else
206 getone(), p = file;
207 eol();
208 if (chdir(p) < 0)
209 filioerr(p);
210 if (savedfile[0] != '/')
211 edited = 0;
212 continue;
213 }
214 if (inopen)
215 tailprim("change", 2, 1);
216 tail2of("change");
217 break;
218
219#endif
220 default:
221 if (inopen)
222 goto notinvis;
223 tail("change");
224 break;
225 }
226/* change */
227 aiflag = exclam();
228 setCNL();
d266c416 229 vmacchng(0);
d9fbdd64
MH
230 setin(addr1);
231 delete(0);
d266c416 232 inappend = 1;
d9fbdd64 233 ignore(append(gettty, addr1 - 1));
d266c416 234 inappend = 0;
d9fbdd64
MH
235 nochng();
236 continue;
237
238/* delete */
239 case 'd':
240 /*
241 * Caution: dp and dl have special meaning already.
242 */
243 tail("delete");
244 c = cmdreg();
245 setCNL();
d266c416 246 vmacchng(0);
d9fbdd64
MH
247 if (c)
248 YANKreg(c);
249 delete(0);
250 appendnone();
251 continue;
252
253/* edit */
254/* ex */
255 case 'e':
256 tail(peekchar() == 'x' ? "ex" : "edit");
d266c416 257editcmd:
d9fbdd64
MH
258 if (!exclam() && chng)
259 c = 'E';
260 filename(c);
261 if (c == 'E') {
262 ungetchar(lastchar());
263 ignore(quickly());
264 }
265 setnoaddr();
266doecmd:
267 init();
268 addr2 = zero;
269 laste++;
270 sync();
271 rop(c);
272 nochng();
273 continue;
274
275/* file */
276 case 'f':
277 tail("file");
278 setnoaddr();
279 filename(c);
280 noonl();
44232d5b 281/*
d9fbdd64 282 synctmp();
44232d5b 283*/
d9fbdd64
MH
284 continue;
285
286/* global */
287 case 'g':
288 tail("global");
289 global(!exclam());
290 nochng();
291 continue;
292
293/* insert */
294 case 'i':
295 if (inopen)
296 goto notinvis;
297 tail("insert");
298 setdot();
299 nonzero();
300 aiflag = exclam();
301 newline();
d266c416 302 vmacchng(0);
d9fbdd64
MH
303 deletenone();
304 setin(addr2);
d266c416 305 inappend = 1;
d9fbdd64 306 ignore(append(gettty, addr2 - 1));
d266c416 307 inappend = 0;
d9fbdd64
MH
308 if (dot == zero && dol > zero)
309 dot = one;
310 nochng();
311 continue;
312
313/* join */
314 case 'j':
315 tail("join");
316 c = exclam();
317 setcount();
318 nonzero();
319 newline();
d266c416 320 vmacchng(0);
d9fbdd64
MH
321 if (given < 2 && addr2 != dol)
322 addr2++;
323 join(c);
324 continue;
325
326/* k */
327 case 'k':
328casek:
329 pastwh();
330 c = getchar();
331 if (endcmd(c))
332 serror("Mark what?|%s requires following letter", Command);
333 newline();
334 if (!islower(c))
335 error("Bad mark|Mark must specify a letter");
336 setdot();
337 nonzero();
338 names[c - 'a'] = *addr2 &~ 01;
339 anymarks = 1;
340 continue;
341
342/* list */
343 case 'l':
344 tail("list");
345 setCNL();
346 ignorf(setlist(1));
347 pflag = 0;
348 goto print;
349
350 case 'm':
351 if (peekchar() == 'a') {
352 ignchar();
353 if (peekchar() == 'p') {
354/* map */
355 tail2of("map");
356 setnoaddr();
d266c416 357 mapcmd(0, 0);
d9fbdd64
MH
358 continue;
359 }
360/* mark */
361 tail2of("mark");
362 goto casek;
363 }
364/* move */
365 tail("move");
d266c416 366 vmacchng(0);
d9fbdd64
MH
367 move();
368 continue;
369
370 case 'n':
371 if (peekchar() == 'u') {
372 tail("number");
373 goto numberit;
374 }
375/* next */
376 tail("next");
377 setnoaddr();
378 ckaw();
379 ignore(quickly());
380 if (getargs())
381 makargs();
382 next();
383 c = 'e';
384 filename(c);
385 goto doecmd;
386
387/* open */
388 case 'o':
389 tail("open");
390 oop();
391 pflag = 0;
392 nochng();
393 continue;
394
395 case 'p':
396 case 'P':
397 switch (peekchar()) {
398
399/* put */
400 case 'u':
401 tail("put");
402 setdot();
403 c = cmdreg();
404 eol();
d266c416 405 vmacchng(0);
d9fbdd64
MH
406 if (c)
407 putreg(c);
408 else
409 put();
410 continue;
411
412 case 'r':
413 ignchar();
414 if (peekchar() == 'e') {
415/* preserve */
416 tail2of("preserve");
417 eol();
418 if (preserve() == 0)
419 error("Preserve failed!");
420 else
421 error("File preserved.");
422 }
423 tail2of("print");
424 break;
425
426 default:
427 tail("print");
428 break;
429 }
430/* print */
431 setCNL();
432 pflag = 0;
433print:
434 nonzero();
435 if (CL && span() > LINES) {
436 flush1();
437 vclear();
438 }
439 plines(addr1, addr2, 1);
440 continue;
441
442/* quit */
443 case 'q':
444 tail("quit");
445 setnoaddr();
446 c = quickly();
447 eol();
448 if (!c)
449quit:
450 nomore();
451 if (inopen) {
452 vgoto(WECHO, 0);
453 if (!ateopr())
454 vnfl();
455 else {
d266c416
MH
456 tostop();
457 /* replaced by tostop
d9fbdd64
MH
458 putpad(VE);
459 putpad(KE);
d266c416 460 */
d9fbdd64
MH
461 }
462 flush();
463 setty(normf);
464 }
465 cleanup(1);
466 exit(0);
467
468 case 'r':
469 if (peekchar() == 'e') {
470 ignchar();
471 switch (peekchar()) {
472
473/* rewind */
474 case 'w':
475 tail2of("rewind");
476 setnoaddr();
10499a70
MH
477 if (!exclam()) {
478 ckaw();
479 if (chng && dol > zero)
480 error("No write@since last chage (:rewind! overrides)");
481 }
d9fbdd64
MH
482 eol();
483 erewind();
484 next();
485 c = 'e';
486 ungetchar(lastchar());
487 filename(c);
488 goto doecmd;
489
490/* recover */
491 case 'c':
492 tail2of("recover");
493 setnoaddr();
494 c = 'e';
495 if (!exclam() && chng)
496 c = 'E';
497 filename(c);
498 if (c == 'E') {
499 ungetchar(lastchar());
500 ignore(quickly());
501 }
502 init();
503 addr2 = zero;
504 laste++;
505 sync();
506 recover();
507 rop2();
508 revocer();
509 if (status == 0)
510 rop3(c);
511 if (dol != zero)
512 change();
513 nochng();
514 continue;
515 }
516 tail2of("read");
517 } else
518 tail("read");
519/* read */
520 if (savedfile[0] == 0 && dol == zero)
521 c = 'e';
522 pastwh();
d266c416 523 vmacchng(0);
d9fbdd64
MH
524 if (peekchar() == '!') {
525 setdot();
526 ignchar();
527 unix0(0);
528 filter(0);
529 continue;
530 }
531 filename(c);
532 rop(c);
533 nochng();
534 if (inopen && endline && addr1 > zero && addr1 < dol)
535 dot = addr1 + 1;
536 continue;
537
538 case 's':
539 switch (peekchar()) {
540 /*
541 * Caution: 2nd char cannot be c, g, or r
542 * because these have meaning to substitute.
543 */
544
545/* set */
546 case 'e':
547 tail("set");
548 setnoaddr();
549 set();
550 continue;
551
552/* shell */
553 case 'h':
554 tail("shell");
555 setNAEOL();
556 vnfl();
557 putpad(TE);
558 flush();
559 unixwt(1, unixex("-i", (char *) 0, 0, 0));
560 vcontin(0);
d9fbdd64
MH
561 continue;
562
563/* source */
564 case 'o':
565 if (inopen)
566 goto notinvis;
567 tail("source");
568 setnoaddr();
569 getone();
570 eol();
571 source(file, 0);
572 continue;
bdbbb330 573#ifdef SIGTSTP
d266c416
MH
574/* stop */
575 case 't':
576 tail("stop");
577 if (!ldisc)
578 error("Old tty driver|Not using new tty driver/shell");
579 c = exclam();
580 eol();
581 if (!c)
582 ckaw();
583 eol();
584 onsusp();
585 continue;
586#endif
587
d9fbdd64
MH
588 }
589 /* fall into ... */
590
591/* & */
592/* ~ */
593/* substitute */
594 case '&':
595 case '~':
596 Command = "substitute";
597 if (c == 's')
598 tail(Command);
d266c416 599 vmacchng(0);
d9fbdd64
MH
600 if (!substitute(c))
601 pflag = 0;
602 continue;
603
604/* t */
605 case 't':
606 if (peekchar() == 'a') {
607 tail("tag");
608 tagfind(exclam());
609 if (!inopen)
610 lchng = chng - 1;
611 else
612 nochng();
613 continue;
614 }
615 tail("t");
d266c416 616 vmacchng(0);
d9fbdd64
MH
617 move();
618 continue;
619
620 case 'u':
621 if (peekchar() == 'n') {
d9fbdd64 622 ignchar();
d266c416
MH
623 switch(peekchar()) {
624/* unmap */
625 case 'm':
d9fbdd64
MH
626 tail2of("unmap");
627 setnoaddr();
d266c416
MH
628 mapcmd(1, 0);
629 continue;
630/* unabbreviate */
631 case 'a':
632 tail2of("unabbreviate");
633 setnoaddr();
634 mapcmd(1, 1);
635 anyabbrs = 1;
d9fbdd64
MH
636 continue;
637 }
638/* undo */
639 tail2of("undo");
640 } else
641 tail("undo");
642 setnoaddr();
643 markDOT();
644 c = exclam();
645 newline();
646 undo(c);
647 continue;
648
649 case 'v':
650 switch (peekchar()) {
651
652 case 'e':
653/* version */
654 tail("version");
655 setNAEOL();
10499a70 656 printf("@(#) Version 3.5, %G%."+5);
d9fbdd64
MH
657 noonl();
658 continue;
659
660/* visual */
661 case 'i':
662 tail("visual");
d266c416
MH
663 if (inopen) {
664 c = 'e';
665 goto editcmd;
666 }
d9fbdd64
MH
667 vop();
668 pflag = 0;
669 nochng();
670 continue;
671 }
672/* v */
673 tail("v");
674 global(0);
675 nochng();
676 continue;
677
678/* write */
679 case 'w':
680 c = peekchar();
681 tail(c == 'q' ? "wq" : "write");
887e3e0d 682wq:
d9fbdd64 683 if (skipwh() && peekchar() == '!') {
887e3e0d 684 pofix();
d9fbdd64
MH
685 ignchar();
686 setall();
687 unix0(0);
688 filter(1);
689 } else {
690 setall();
691 wop(1);
692 nochng();
693 }
694 if (c == 'q')
695 goto quit;
696 continue;
697
887e3e0d
MH
698/* xit */
699 case 'x':
700 tail("xit");
701 if (!chng)
702 goto quit;
703 c = 'q';
704 goto wq;
705
d9fbdd64
MH
706/* yank */
707 case 'y':
708 tail("yank");
709 c = cmdreg();
710 setcount();
711 eol();
d266c416 712 vmacchng(0);
d9fbdd64
MH
713 if (c)
714 YANKreg(c);
715 else
716 yank();
717 continue;
718
719/* z */
720 case 'z':
721 zop(0);
722 pflag = 0;
723 continue;
724
725/* * */
726/* @ */
727 case '*':
728 case '@':
729 c = getchar();
730 if (c=='\n' || c=='\r')
731 ungetchar(c);
732 if (any(c, "@*\n\r"))
733 c = lastmac;
734 if (isupper(c))
735 c = tolower(c);
736 if (!islower(c))
737 error("Bad register");
738 newline();
739 setdot();
740 cmdmac(c);
741 continue;
742
743/* | */
744 case '|':
745 endline = 0;
746 goto caseline;
747
748/* \n */
749 case '\n':
750 endline = 1;
751caseline:
752 notempty();
753 if (addr2 == 0) {
d9fbdd64
MH
754 if (UP != NOSTR && c == '\n' && !inglobal)
755 c = CTRL(k);
756 if (inglobal)
757 addr1 = addr2 = dot;
887e3e0d
MH
758 else {
759 if (dot == dol)
760 error("At EOF|At end-of-file");
d9fbdd64 761 addr1 = addr2 = dot + 1;
887e3e0d 762 }
d9fbdd64
MH
763 }
764 setdot();
765 nonzero();
766 if (seensemi)
767 addr1 = addr2;
768 getline(*addr1);
769 if (c == CTRL(k)) {
770 flush1();
771 destline--;
772 if (hadpr)
773 shudclob = 1;
774 }
775 plines(addr1, addr2, 1);
776 continue;
777
d266c416
MH
778/* " */
779 case '"':
780 comment();
781 continue;
782
d9fbdd64
MH
783/* # */
784 case '#':
785numberit:
786 setCNL();
787 ignorf(setnumb(1));
788 pflag = 0;
789 goto print;
790
791/* = */
792 case '=':
793 newline();
794 setall();
887e3e0d
MH
795 if (inglobal == 2)
796 pofix();
d9fbdd64
MH
797 printf("%d", lineno(addr2));
798 noonl();
799 continue;
800
801/* ! */
802 case '!':
803 if (addr2 != 0) {
d266c416 804 vmacchng(0);
d9fbdd64
MH
805 unix0(0);
806 setdot();
807 filter(2);
808 } else {
809 unix0(1);
887e3e0d 810 pofix();
d9fbdd64
MH
811 putpad(TE);
812 flush();
813 unixwt(1, unixex("-c", uxb, 0, 0));
d266c416 814 vclrech(1); /* vcontin(0); */
d9fbdd64
MH
815 nochng();
816 }
817 continue;
818
819/* < */
820/* > */
821 case '<':
822 case '>':
823 for (cnt = 1; peekchar() == c; cnt++)
824 ignchar();
825 setCNL();
d266c416 826 vmacchng(0);
d9fbdd64
MH
827 shift(c, cnt);
828 continue;
829
830/* ^D */
831/* EOF */
832 case CTRL(d):
833 case EOF:
834 if (exitoneof) {
835 if (addr2 != 0)
836 dot = addr2;
837 return;
838 }
839 if (!isatty(0)) {
840 if (intty)
841 /*
842 * Chtty sys call at UCB may cause a
843 * input which was a tty to suddenly be
844 * turned into /dev/null.
845 */
846 onhup();
847 return;
848 }
849 if (addr2 != 0) {
850 setlastchar('\n');
851 putnl();
852 }
853 if (dol == zero) {
854 if (addr2 == 0)
855 putnl();
856 notempty();
857 }
858 ungetchar(EOF);
859 zop(hadpr);
860 continue;
861
862 default:
863 if (!isalpha(c))
864 break;
865 ungetchar(c);
866 tailprim("", 0, 0);
867 }
868 error("What?|Unknown command character '%c'", c);
869 }
870}