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