(no message)
[unix-history] / usr / src / usr.bin / ex / ex_cmds.c
CommitLineData
299f2784 1/* Copyright (c) 1981 Regents of the University of California */
b8c3ed58 2static char *sccsid = "@(#)ex_cmds.c 7.6 %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);
273 nochng();
274 continue;
275
276/* file */
277 case 'f':
278 tail("file");
279 setnoaddr();
280 filename(c);
281 noonl();
44232d5b 282/*
d9fbdd64 283 synctmp();
44232d5b 284*/
d9fbdd64
MH
285 continue;
286
287/* global */
288 case 'g':
289 tail("global");
290 global(!exclam());
291 nochng();
292 continue;
293
294/* insert */
295 case 'i':
296 if (inopen)
297 goto notinvis;
298 tail("insert");
299 setdot();
300 nonzero();
301 aiflag = exclam();
302 newline();
d266c416 303 vmacchng(0);
d9fbdd64
MH
304 deletenone();
305 setin(addr2);
d266c416 306 inappend = 1;
d9fbdd64 307 ignore(append(gettty, addr2 - 1));
d266c416 308 inappend = 0;
d9fbdd64
MH
309 if (dot == zero && dol > zero)
310 dot = one;
311 nochng();
312 continue;
313
314/* join */
315 case 'j':
316 tail("join");
317 c = exclam();
318 setcount();
319 nonzero();
320 newline();
d266c416 321 vmacchng(0);
d9fbdd64
MH
322 if (given < 2 && addr2 != dol)
323 addr2++;
324 join(c);
325 continue;
326
327/* k */
328 case 'k':
329casek:
330 pastwh();
331 c = getchar();
332 if (endcmd(c))
333 serror("Mark what?|%s requires following letter", Command);
334 newline();
335 if (!islower(c))
336 error("Bad mark|Mark must specify a letter");
337 setdot();
338 nonzero();
339 names[c - 'a'] = *addr2 &~ 01;
340 anymarks = 1;
341 continue;
342
343/* list */
344 case 'l':
345 tail("list");
346 setCNL();
347 ignorf(setlist(1));
348 pflag = 0;
349 goto print;
350
351 case 'm':
352 if (peekchar() == 'a') {
353 ignchar();
354 if (peekchar() == 'p') {
355/* map */
356 tail2of("map");
357 setnoaddr();
d266c416 358 mapcmd(0, 0);
d9fbdd64
MH
359 continue;
360 }
361/* mark */
362 tail2of("mark");
363 goto casek;
364 }
365/* move */
366 tail("move");
d266c416 367 vmacchng(0);
d9fbdd64
MH
368 move();
369 continue;
370
371 case 'n':
372 if (peekchar() == 'u') {
373 tail("number");
374 goto numberit;
375 }
376/* next */
377 tail("next");
378 setnoaddr();
379 ckaw();
380 ignore(quickly());
381 if (getargs())
382 makargs();
383 next();
384 c = 'e';
385 filename(c);
386 goto doecmd;
387
388/* open */
389 case 'o':
390 tail("open");
391 oop();
392 pflag = 0;
393 nochng();
394 continue;
395
396 case 'p':
397 case 'P':
398 switch (peekchar()) {
399
400/* put */
401 case 'u':
402 tail("put");
403 setdot();
404 c = cmdreg();
405 eol();
d266c416 406 vmacchng(0);
d9fbdd64
MH
407 if (c)
408 putreg(c);
409 else
410 put();
411 continue;
412
413 case 'r':
414 ignchar();
415 if (peekchar() == 'e') {
416/* preserve */
417 tail2of("preserve");
418 eol();
419 if (preserve() == 0)
420 error("Preserve failed!");
421 else
422 error("File preserved.");
423 }
424 tail2of("print");
425 break;
426
427 default:
428 tail("print");
429 break;
430 }
431/* print */
432 setCNL();
433 pflag = 0;
434print:
435 nonzero();
436 if (CL && span() > LINES) {
437 flush1();
438 vclear();
439 }
440 plines(addr1, addr2, 1);
441 continue;
442
443/* quit */
444 case 'q':
445 tail("quit");
446 setnoaddr();
447 c = quickly();
448 eol();
449 if (!c)
450quit:
451 nomore();
452 if (inopen) {
453 vgoto(WECHO, 0);
454 if (!ateopr())
455 vnfl();
456 else {
d266c416 457 tostop();
d9fbdd64
MH
458 }
459 flush();
460 setty(normf);
461 }
462 cleanup(1);
463 exit(0);
464
465 case 'r':
466 if (peekchar() == 'e') {
467 ignchar();
468 switch (peekchar()) {
469
470/* rewind */
471 case 'w':
472 tail2of("rewind");
473 setnoaddr();
10499a70
MH
474 if (!exclam()) {
475 ckaw();
476 if (chng && dol > zero)
477 error("No write@since last chage (:rewind! overrides)");
478 }
d9fbdd64
MH
479 eol();
480 erewind();
481 next();
482 c = 'e';
483 ungetchar(lastchar());
484 filename(c);
485 goto doecmd;
486
487/* recover */
488 case 'c':
489 tail2of("recover");
490 setnoaddr();
491 c = 'e';
492 if (!exclam() && chng)
493 c = 'E';
494 filename(c);
495 if (c == 'E') {
496 ungetchar(lastchar());
497 ignore(quickly());
498 }
499 init();
500 addr2 = zero;
501 laste++;
502 sync();
503 recover();
504 rop2();
505 revocer();
506 if (status == 0)
507 rop3(c);
508 if (dol != zero)
509 change();
510 nochng();
511 continue;
512 }
513 tail2of("read");
514 } else
515 tail("read");
516/* read */
517 if (savedfile[0] == 0 && dol == zero)
518 c = 'e';
519 pastwh();
d266c416 520 vmacchng(0);
d9fbdd64
MH
521 if (peekchar() == '!') {
522 setdot();
523 ignchar();
524 unix0(0);
525 filter(0);
526 continue;
527 }
528 filename(c);
529 rop(c);
530 nochng();
531 if (inopen && endline && addr1 > zero && addr1 < dol)
532 dot = addr1 + 1;
533 continue;
534
535 case 's':
536 switch (peekchar()) {
537 /*
538 * Caution: 2nd char cannot be c, g, or r
539 * because these have meaning to substitute.
540 */
541
542/* set */
543 case 'e':
544 tail("set");
545 setnoaddr();
546 set();
547 continue;
548
549/* shell */
550 case 'h':
551 tail("shell");
552 setNAEOL();
553 vnfl();
554 putpad(TE);
555 flush();
556 unixwt(1, unixex("-i", (char *) 0, 0, 0));
557 vcontin(0);
d9fbdd64
MH
558 continue;
559
560/* source */
561 case 'o':
04379bab 562#ifdef notdef
d9fbdd64
MH
563 if (inopen)
564 goto notinvis;
04379bab 565#endif
d9fbdd64
MH
566 tail("source");
567 setnoaddr();
568 getone();
569 eol();
570 source(file, 0);
571 continue;
bdbbb330 572#ifdef SIGTSTP
04379bab 573/* stop, suspend */
d266c416
MH
574 case 't':
575 tail("stop");
04379bab
MH
576 goto suspend;
577 case 'u':
578 tail("suspend");
579suspend:
d266c416
MH
580 if (!ldisc)
581 error("Old tty driver|Not using new tty driver/shell");
582 c = exclam();
583 eol();
584 if (!c)
585 ckaw();
d266c416
MH
586 onsusp();
587 continue;
588#endif
589
d9fbdd64
MH
590 }
591 /* fall into ... */
592
593/* & */
594/* ~ */
595/* substitute */
596 case '&':
597 case '~':
598 Command = "substitute";
599 if (c == 's')
600 tail(Command);
d266c416 601 vmacchng(0);
d9fbdd64
MH
602 if (!substitute(c))
603 pflag = 0;
604 continue;
605
606/* t */
607 case 't':
608 if (peekchar() == 'a') {
609 tail("tag");
610 tagfind(exclam());
611 if (!inopen)
612 lchng = chng - 1;
613 else
614 nochng();
615 continue;
616 }
617 tail("t");
d266c416 618 vmacchng(0);
d9fbdd64
MH
619 move();
620 continue;
621
622 case 'u':
623 if (peekchar() == 'n') {
d9fbdd64 624 ignchar();
d266c416
MH
625 switch(peekchar()) {
626/* unmap */
627 case 'm':
d9fbdd64
MH
628 tail2of("unmap");
629 setnoaddr();
d266c416
MH
630 mapcmd(1, 0);
631 continue;
632/* unabbreviate */
633 case 'a':
634 tail2of("unabbreviate");
635 setnoaddr();
636 mapcmd(1, 1);
637 anyabbrs = 1;
d9fbdd64
MH
638 continue;
639 }
640/* undo */
641 tail2of("undo");
642 } else
643 tail("undo");
644 setnoaddr();
645 markDOT();
646 c = exclam();
647 newline();
648 undo(c);
649 continue;
650
651 case 'v':
652 switch (peekchar()) {
653
654 case 'e':
655/* version */
656 tail("version");
657 setNAEOL();
6365dfcb 658 printf("@(#) Version 3.7, %G%."+5);
d9fbdd64
MH
659 noonl();
660 continue;
661
662/* visual */
663 case 'i':
664 tail("visual");
d266c416
MH
665 if (inopen) {
666 c = 'e';
667 goto editcmd;
668 }
d9fbdd64
MH
669 vop();
670 pflag = 0;
671 nochng();
672 continue;
673 }
674/* v */
675 tail("v");
676 global(0);
677 nochng();
678 continue;
679
680/* write */
681 case 'w':
682 c = peekchar();
683 tail(c == 'q' ? "wq" : "write");
887e3e0d 684wq:
d9fbdd64 685 if (skipwh() && peekchar() == '!') {
887e3e0d 686 pofix();
d9fbdd64
MH
687 ignchar();
688 setall();
689 unix0(0);
690 filter(1);
691 } else {
692 setall();
693 wop(1);
694 nochng();
695 }
696 if (c == 'q')
697 goto quit;
698 continue;
699
887e3e0d
MH
700/* xit */
701 case 'x':
702 tail("xit");
703 if (!chng)
704 goto quit;
705 c = 'q';
706 goto wq;
707
d9fbdd64
MH
708/* yank */
709 case 'y':
710 tail("yank");
711 c = cmdreg();
712 setcount();
713 eol();
d266c416 714 vmacchng(0);
d9fbdd64
MH
715 if (c)
716 YANKreg(c);
717 else
718 yank();
719 continue;
720
721/* z */
722 case 'z':
723 zop(0);
724 pflag = 0;
725 continue;
726
727/* * */
728/* @ */
729 case '*':
730 case '@':
731 c = getchar();
732 if (c=='\n' || c=='\r')
733 ungetchar(c);
734 if (any(c, "@*\n\r"))
735 c = lastmac;
736 if (isupper(c))
737 c = tolower(c);
738 if (!islower(c))
739 error("Bad register");
740 newline();
741 setdot();
742 cmdmac(c);
743 continue;
744
745/* | */
746 case '|':
747 endline = 0;
748 goto caseline;
749
750/* \n */
751 case '\n':
752 endline = 1;
753caseline:
754 notempty();
755 if (addr2 == 0) {
d9fbdd64
MH
756 if (UP != NOSTR && c == '\n' && !inglobal)
757 c = CTRL(k);
758 if (inglobal)
759 addr1 = addr2 = dot;
887e3e0d
MH
760 else {
761 if (dot == dol)
762 error("At EOF|At end-of-file");
d9fbdd64 763 addr1 = addr2 = dot + 1;
887e3e0d 764 }
d9fbdd64
MH
765 }
766 setdot();
767 nonzero();
768 if (seensemi)
769 addr1 = addr2;
770 getline(*addr1);
771 if (c == CTRL(k)) {
772 flush1();
773 destline--;
774 if (hadpr)
775 shudclob = 1;
776 }
777 plines(addr1, addr2, 1);
778 continue;
779
d266c416
MH
780/* " */
781 case '"':
782 comment();
783 continue;
784
d9fbdd64
MH
785/* # */
786 case '#':
787numberit:
788 setCNL();
789 ignorf(setnumb(1));
790 pflag = 0;
791 goto print;
792
793/* = */
794 case '=':
795 newline();
796 setall();
887e3e0d
MH
797 if (inglobal == 2)
798 pofix();
d9fbdd64
MH
799 printf("%d", lineno(addr2));
800 noonl();
801 continue;
802
803/* ! */
804 case '!':
805 if (addr2 != 0) {
d266c416 806 vmacchng(0);
d9fbdd64
MH
807 unix0(0);
808 setdot();
809 filter(2);
810 } else {
811 unix0(1);
887e3e0d 812 pofix();
d9fbdd64
MH
813 putpad(TE);
814 flush();
815 unixwt(1, unixex("-c", uxb, 0, 0));
d266c416 816 vclrech(1); /* vcontin(0); */
d9fbdd64
MH
817 nochng();
818 }
819 continue;
820
821/* < */
822/* > */
823 case '<':
824 case '>':
825 for (cnt = 1; peekchar() == c; cnt++)
826 ignchar();
827 setCNL();
d266c416 828 vmacchng(0);
d9fbdd64
MH
829 shift(c, cnt);
830 continue;
831
832/* ^D */
833/* EOF */
834 case CTRL(d):
835 case EOF:
836 if (exitoneof) {
837 if (addr2 != 0)
838 dot = addr2;
839 return;
840 }
841 if (!isatty(0)) {
842 if (intty)
843 /*
844 * Chtty sys call at UCB may cause a
845 * input which was a tty to suddenly be
846 * turned into /dev/null.
847 */
848 onhup();
849 return;
850 }
851 if (addr2 != 0) {
852 setlastchar('\n');
853 putnl();
854 }
855 if (dol == zero) {
856 if (addr2 == 0)
857 putnl();
858 notempty();
859 }
860 ungetchar(EOF);
861 zop(hadpr);
862 continue;
863
864 default:
865 if (!isalpha(c))
866 break;
867 ungetchar(c);
868 tailprim("", 0, 0);
869 }
870 error("What?|Unknown command character '%c'", c);
871 }
872}