manual page distributed with 4.2BSD
[unix-history] / usr / src / usr.bin / ex / ex_cmds.c
CommitLineData
299f2784 1/* Copyright (c) 1981 Regents of the University of California */
20191463 2static char *sccsid = "@(#)ex_cmds.c 7.8 %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;
d9fbdd64
MH
519 nochng();
520 continue;
521 }
522 tail2of("read");
523 } else
524 tail("read");
525/* read */
526 if (savedfile[0] == 0 && dol == zero)
527 c = 'e';
528 pastwh();
d266c416 529 vmacchng(0);
d9fbdd64
MH
530 if (peekchar() == '!') {
531 setdot();
532 ignchar();
533 unix0(0);
534 filter(0);
535 continue;
536 }
537 filename(c);
538 rop(c);
539 nochng();
540 if (inopen && endline && addr1 > zero && addr1 < dol)
541 dot = addr1 + 1;
542 continue;
543
544 case 's':
545 switch (peekchar()) {
546 /*
547 * Caution: 2nd char cannot be c, g, or r
548 * because these have meaning to substitute.
549 */
550
551/* set */
552 case 'e':
553 tail("set");
554 setnoaddr();
555 set();
556 continue;
557
558/* shell */
559 case 'h':
560 tail("shell");
561 setNAEOL();
562 vnfl();
563 putpad(TE);
564 flush();
565 unixwt(1, unixex("-i", (char *) 0, 0, 0));
566 vcontin(0);
d9fbdd64
MH
567 continue;
568
569/* source */
570 case 'o':
04379bab 571#ifdef notdef
d9fbdd64
MH
572 if (inopen)
573 goto notinvis;
04379bab 574#endif
d9fbdd64
MH
575 tail("source");
576 setnoaddr();
577 getone();
578 eol();
579 source(file, 0);
580 continue;
bdbbb330 581#ifdef SIGTSTP
04379bab 582/* stop, suspend */
d266c416
MH
583 case 't':
584 tail("stop");
04379bab
MH
585 goto suspend;
586 case 'u':
587 tail("suspend");
588suspend:
d266c416
MH
589 if (!ldisc)
590 error("Old tty driver|Not using new tty driver/shell");
591 c = exclam();
592 eol();
593 if (!c)
594 ckaw();
d266c416
MH
595 onsusp();
596 continue;
597#endif
598
d9fbdd64
MH
599 }
600 /* fall into ... */
601
602/* & */
603/* ~ */
604/* substitute */
605 case '&':
606 case '~':
607 Command = "substitute";
608 if (c == 's')
609 tail(Command);
d266c416 610 vmacchng(0);
d9fbdd64
MH
611 if (!substitute(c))
612 pflag = 0;
613 continue;
614
615/* t */
616 case 't':
617 if (peekchar() == 'a') {
618 tail("tag");
619 tagfind(exclam());
620 if (!inopen)
621 lchng = chng - 1;
622 else
623 nochng();
624 continue;
625 }
626 tail("t");
d266c416 627 vmacchng(0);
d9fbdd64
MH
628 move();
629 continue;
630
631 case 'u':
632 if (peekchar() == 'n') {
d9fbdd64 633 ignchar();
d266c416
MH
634 switch(peekchar()) {
635/* unmap */
636 case 'm':
d9fbdd64
MH
637 tail2of("unmap");
638 setnoaddr();
d266c416
MH
639 mapcmd(1, 0);
640 continue;
641/* unabbreviate */
642 case 'a':
643 tail2of("unabbreviate");
644 setnoaddr();
645 mapcmd(1, 1);
646 anyabbrs = 1;
d9fbdd64
MH
647 continue;
648 }
649/* undo */
650 tail2of("undo");
651 } else
652 tail("undo");
653 setnoaddr();
654 markDOT();
655 c = exclam();
656 newline();
657 undo(c);
658 continue;
659
660 case 'v':
661 switch (peekchar()) {
662
663 case 'e':
664/* version */
665 tail("version");
666 setNAEOL();
6365dfcb 667 printf("@(#) Version 3.7, %G%."+5);
d9fbdd64
MH
668 noonl();
669 continue;
670
671/* visual */
672 case 'i':
673 tail("visual");
d266c416
MH
674 if (inopen) {
675 c = 'e';
676 goto editcmd;
677 }
d9fbdd64
MH
678 vop();
679 pflag = 0;
680 nochng();
681 continue;
682 }
683/* v */
684 tail("v");
685 global(0);
686 nochng();
687 continue;
688
689/* write */
690 case 'w':
691 c = peekchar();
692 tail(c == 'q' ? "wq" : "write");
887e3e0d 693wq:
d9fbdd64 694 if (skipwh() && peekchar() == '!') {
887e3e0d 695 pofix();
d9fbdd64
MH
696 ignchar();
697 setall();
698 unix0(0);
699 filter(1);
700 } else {
701 setall();
702 wop(1);
703 nochng();
704 }
705 if (c == 'q')
706 goto quit;
707 continue;
708
887e3e0d
MH
709/* xit */
710 case 'x':
711 tail("xit");
712 if (!chng)
713 goto quit;
714 c = 'q';
715 goto wq;
716
d9fbdd64
MH
717/* yank */
718 case 'y':
719 tail("yank");
720 c = cmdreg();
721 setcount();
722 eol();
d266c416 723 vmacchng(0);
d9fbdd64
MH
724 if (c)
725 YANKreg(c);
726 else
727 yank();
728 continue;
729
730/* z */
731 case 'z':
732 zop(0);
733 pflag = 0;
734 continue;
735
736/* * */
737/* @ */
738 case '*':
739 case '@':
740 c = getchar();
741 if (c=='\n' || c=='\r')
742 ungetchar(c);
743 if (any(c, "@*\n\r"))
744 c = lastmac;
745 if (isupper(c))
746 c = tolower(c);
747 if (!islower(c))
748 error("Bad register");
749 newline();
750 setdot();
751 cmdmac(c);
752 continue;
753
754/* | */
755 case '|':
756 endline = 0;
757 goto caseline;
758
759/* \n */
760 case '\n':
761 endline = 1;
762caseline:
763 notempty();
764 if (addr2 == 0) {
d9fbdd64
MH
765 if (UP != NOSTR && c == '\n' && !inglobal)
766 c = CTRL(k);
767 if (inglobal)
768 addr1 = addr2 = dot;
887e3e0d
MH
769 else {
770 if (dot == dol)
771 error("At EOF|At end-of-file");
d9fbdd64 772 addr1 = addr2 = dot + 1;
887e3e0d 773 }
d9fbdd64
MH
774 }
775 setdot();
776 nonzero();
777 if (seensemi)
778 addr1 = addr2;
779 getline(*addr1);
780 if (c == CTRL(k)) {
781 flush1();
782 destline--;
783 if (hadpr)
784 shudclob = 1;
785 }
786 plines(addr1, addr2, 1);
787 continue;
788
d266c416
MH
789/* " */
790 case '"':
791 comment();
792 continue;
793
d9fbdd64
MH
794/* # */
795 case '#':
796numberit:
797 setCNL();
798 ignorf(setnumb(1));
799 pflag = 0;
800 goto print;
801
802/* = */
803 case '=':
804 newline();
805 setall();
887e3e0d
MH
806 if (inglobal == 2)
807 pofix();
d9fbdd64
MH
808 printf("%d", lineno(addr2));
809 noonl();
810 continue;
811
812/* ! */
813 case '!':
814 if (addr2 != 0) {
d266c416 815 vmacchng(0);
d9fbdd64
MH
816 unix0(0);
817 setdot();
818 filter(2);
819 } else {
820 unix0(1);
887e3e0d 821 pofix();
d9fbdd64
MH
822 putpad(TE);
823 flush();
824 unixwt(1, unixex("-c", uxb, 0, 0));
d266c416 825 vclrech(1); /* vcontin(0); */
d9fbdd64
MH
826 nochng();
827 }
828 continue;
829
830/* < */
831/* > */
832 case '<':
833 case '>':
834 for (cnt = 1; peekchar() == c; cnt++)
835 ignchar();
836 setCNL();
d266c416 837 vmacchng(0);
d9fbdd64
MH
838 shift(c, cnt);
839 continue;
840
841/* ^D */
842/* EOF */
843 case CTRL(d):
844 case EOF:
845 if (exitoneof) {
846 if (addr2 != 0)
847 dot = addr2;
848 return;
849 }
850 if (!isatty(0)) {
851 if (intty)
852 /*
853 * Chtty sys call at UCB may cause a
854 * input which was a tty to suddenly be
855 * turned into /dev/null.
856 */
857 onhup();
858 return;
859 }
860 if (addr2 != 0) {
861 setlastchar('\n');
862 putnl();
863 }
864 if (dol == zero) {
865 if (addr2 == 0)
866 putnl();
867 notempty();
868 }
869 ungetchar(EOF);
870 zop(hadpr);
871 continue;
872
873 default:
874 if (!isalpha(c))
875 break;
876 ungetchar(c);
877 tailprim("", 0, 0);
878 }
879 error("What?|Unknown command character '%c'", c);
880 }
881}