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