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