bug fix, 4.3BSD/usr.bin/41
[unix-history] / usr / src / usr.bin / ex / ex_cmds.c
CommitLineData
19d73a0e
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
70190965 8static char *sccsid = "@(#)ex_cmds.c 7.10 (Berkeley) %G%";
19d73a0e
DF
9#endif not lint
10
d9fbdd64
MH
11#include "ex.h"
12#include "ex_argv.h"
13#include "ex_temp.h"
14#include "ex_tty.h"
714bf4c2 15#include "ex_vis.h"
d9fbdd64
MH
16
17bool pflag, nflag;
18int poffset;
19
20#define nochng() lchng = chng
21
22/*
23 * Main loop for command mode command decoding.
24 * A few commands are executed here, but main function
25 * is to strip command addresses, do a little address oriented
26 * processing and call command routines to do the real work.
27 */
28commands(noprompt, exitoneof)
29 bool noprompt, exitoneof;
30{
31 register line *addr;
32 register int c;
33 register int lchng;
34 int given;
35 int seensemi;
36 int cnt;
37 bool hadpr;
38
39 resetflav();
40 nochng();
41 for (;;) {
42 /*
43 * If dot at last command
44 * ended up at zero, advance to one if there is a such.
45 */
46 if (dot <= zero) {
47 dot = zero;
48 if (dol > zero)
49 dot = one;
50 }
51 shudclob = 0;
52
53 /*
54 * If autoprint or trailing print flags,
55 * print the line at the specified offset
56 * before the next command.
57 */
58 if (pflag ||
59 lchng != chng && value(AUTOPRINT) && !inglobal && !inopen && endline) {
60 pflag = 0;
61 nochng();
62 if (dol != zero) {
63 addr1 = addr2 = dot + poffset;
64 if (addr1 < one || addr1 > dol)
65error("Offset out-of-bounds|Offset after command too large");
66 setdot1();
67 goto print;
68 }
69 }
70 nochng();
71
72 /*
73 * Print prompt if appropriate.
74 * If not in global flush output first to prevent
75 * going into pfast mode unreasonably.
76 */
77 if (inglobal == 0) {
78 flush();
79 if (!hush && value(PROMPT) && !globp && !noprompt && endline) {
80 putchar(':');
81 hadpr = 1;
82 }
83 TSYNC();
84 }
85
86 /*
87 * Gobble up the address.
88 * Degenerate addresses yield ".".
89 */
90 addr2 = 0;
91 given = seensemi = 0;
92 do {
93 addr1 = addr2;
94 addr = address(0);
95 c = getcd();
96 if (addr == 0)
97 if (c == ',')
98 addr = dot;
99 else if (addr1 != 0) {
100 addr2 = dot;
101 break;
102 } else
103 break;
104 addr2 = addr;
105 given++;
106 if (c == ';') {
107 c = ',';
108 dot = addr;
109 seensemi = 1;
110 }
111 } while (c == ',');
112 if (c == '%') {
113 /* %: same as 1,$ */
114 addr1 = one;
115 addr2 = dol;
116 given = 2;
117 c = getchar();
118 }
119 if (addr1 == 0)
120 addr1 = addr2;
121 if (c == ':')
122 c = getchar();
123
124 /*
125 * Set command name for special character commands.
126 */
127 tailspec(c);
128
129 /*
130 * If called via : escape from open or visual, limit
131 * the set of available commands here to save work below.
132 */
133 if (inopen) {
134 if (c=='\n' || c=='\r' || c==CTRL(d) || c==EOF) {
135 if (addr2)
136 dot = addr2;
137 if (c == EOF)
138 return;
139 continue;
140 }
141 if (any(c, "o"))
142notinvis:
143 tailprim(Command, 1, 1);
144 }
145choice:
146 switch (c) {
147
148 case 'a':
149
d266c416
MH
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':
d9fbdd64
MH
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();
d266c416 174 vmacchng(0);
d9fbdd64
MH
175 deletenone();
176 setin(addr2);
d266c416 177 inappend = 1;
d9fbdd64 178 ignore(append(gettty, addr2));
d266c416 179 inappend = 0;
d9fbdd64
MH
180 nochng();
181 continue;
182
183 case 'c':
184 switch (peekchar()) {
185
186/* copy */
187 case 'o':
188 tail("copy");
d266c416 189 vmacchng(0);
d9fbdd64
MH
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");
205changdir:
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();
d266c416 238 vmacchng(0);
d9fbdd64
MH
239 setin(addr1);
240 delete(0);
d266c416 241 inappend = 1;
d9fbdd64 242 ignore(append(gettty, addr1 - 1));
d266c416 243 inappend = 0;
d9fbdd64
MH
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();
d266c416 255 vmacchng(0);
d9fbdd64
MH
256 if (c)
257 YANKreg(c);
258 delete(0);
259 appendnone();
260 continue;
261
262/* edit */
263/* ex */
264 case 'e':
265 tail(peekchar() == 'x' ? "ex" : "edit");
d266c416 266editcmd:
d9fbdd64
MH
267 if (!exclam() && chng)
268 c = 'E';
269 filename(c);
270 if (c == 'E') {
271 ungetchar(lastchar());
272 ignore(quickly());
273 }
274 setnoaddr();
275doecmd:
276 init();
277 addr2 = zero;
278 laste++;
279 sync();
280 rop(c);
79086561
RC
281#ifdef VMUNIX
282 tlaste();
283#endif
284 laste = 0;
285 sync();
d9fbdd64
MH
286 nochng();
287 continue;
288
289/* file */
290 case 'f':
291 tail("file");
292 setnoaddr();
293 filename(c);
294 noonl();
44232d5b 295/*
d9fbdd64 296 synctmp();
44232d5b 297*/
d9fbdd64
MH
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();
d266c416 316 vmacchng(0);
d9fbdd64
MH
317 deletenone();
318 setin(addr2);
d266c416 319 inappend = 1;
d9fbdd64 320 ignore(append(gettty, addr2 - 1));
d266c416 321 inappend = 0;
d9fbdd64
MH
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();
d266c416 334 vmacchng(0);
d9fbdd64
MH
335 if (given < 2 && addr2 != dol)
336 addr2++;
337 join(c);
338 continue;
339
340/* k */
341 case 'k':
342casek:
343 pastwh();
344 c = 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();
d266c416 371 mapcmd(0, 0);
d9fbdd64
MH
372 continue;
373 }
374/* mark */
375 tail2of("mark");
376 goto casek;
377 }
378/* move */
379 tail("move");
d266c416 380 vmacchng(0);
d9fbdd64
MH
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();
d266c416 419 vmacchng(0);
d9fbdd64
MH
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;
447print:
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)
463quit:
464 nomore();
465 if (inopen) {
466 vgoto(WECHO, 0);
467 if (!ateopr())
468 vnfl();
469 else {
d266c416 470 tostop();
d9fbdd64
MH
471 }
472 flush();
473 setty(normf);
474 }
475 cleanup(1);
476 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();
10499a70
MH
487 if (!exclam()) {
488 ckaw();
489 if (chng && dol > zero)
490 error("No write@since last chage (:rewind! overrides)");
491 }
d9fbdd64
MH
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 sync();
516 recover();
517 rop2();
518 revocer();
519 if (status == 0)
520 rop3(c);
521 if (dol != zero)
522 change();
79086561
RC
523#ifdef VMUNIX
524 tlaste();
525#endif
526 laste = 0;
d9fbdd64
MH
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();
d266c416 537 vmacchng(0);
d9fbdd64
MH
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);
d9fbdd64
MH
575 continue;
576
577/* source */
578 case 'o':
04379bab 579#ifdef notdef
d9fbdd64
MH
580 if (inopen)
581 goto notinvis;
04379bab 582#endif
d9fbdd64
MH
583 tail("source");
584 setnoaddr();
585 getone();
586 eol();
587 source(file, 0);
588 continue;
bdbbb330 589#ifdef SIGTSTP
04379bab 590/* stop, suspend */
d266c416
MH
591 case 't':
592 tail("stop");
04379bab
MH
593 goto suspend;
594 case 'u':
595 tail("suspend");
596suspend:
d266c416
MH
597 if (!ldisc)
598 error("Old tty driver|Not using new tty driver/shell");
599 c = exclam();
600 eol();
601 if (!c)
602 ckaw();
d266c416
MH
603 onsusp();
604 continue;
605#endif
606
d9fbdd64
MH
607 }
608 /* fall into ... */
609
610/* & */
611/* ~ */
612/* substitute */
613 case '&':
614 case '~':
615 Command = "substitute";
616 if (c == 's')
617 tail(Command);
d266c416 618 vmacchng(0);
d9fbdd64
MH
619 if (!substitute(c))
620 pflag = 0;
621 continue;
622
623/* t */
624 case 't':
625 if (peekchar() == 'a') {
626 tail("tag");
627 tagfind(exclam());
628 if (!inopen)
629 lchng = chng - 1;
630 else
631 nochng();
632 continue;
633 }
634 tail("t");
d266c416 635 vmacchng(0);
d9fbdd64
MH
636 move();
637 continue;
638
639 case 'u':
640 if (peekchar() == 'n') {
d9fbdd64 641 ignchar();
d266c416
MH
642 switch(peekchar()) {
643/* unmap */
644 case 'm':
d9fbdd64
MH
645 tail2of("unmap");
646 setnoaddr();
d266c416
MH
647 mapcmd(1, 0);
648 continue;
649/* unabbreviate */
650 case 'a':
651 tail2of("unabbreviate");
652 setnoaddr();
653 mapcmd(1, 1);
654 anyabbrs = 1;
d9fbdd64
MH
655 continue;
656 }
657/* undo */
658 tail2of("undo");
659 } else
660 tail("undo");
661 setnoaddr();
662 markDOT();
663 c = exclam();
664 newline();
665 undo(c);
666 continue;
667
668 case 'v':
669 switch (peekchar()) {
670
671 case 'e':
672/* version */
673 tail("version");
674 setNAEOL();
19d73a0e 675 printf("@(#) Version 3.7, %G%."+5);
d9fbdd64
MH
676 noonl();
677 continue;
678
679/* visual */
680 case 'i':
681 tail("visual");
d266c416
MH
682 if (inopen) {
683 c = 'e';
684 goto editcmd;
685 }
d9fbdd64
MH
686 vop();
687 pflag = 0;
688 nochng();
689 continue;
690 }
691/* v */
692 tail("v");
693 global(0);
694 nochng();
695 continue;
696
697/* write */
698 case 'w':
699 c = peekchar();
700 tail(c == 'q' ? "wq" : "write");
887e3e0d 701wq:
d9fbdd64 702 if (skipwh() && peekchar() == '!') {
887e3e0d 703 pofix();
d9fbdd64
MH
704 ignchar();
705 setall();
706 unix0(0);
707 filter(1);
708 } else {
709 setall();
710 wop(1);
711 nochng();
712 }
713 if (c == 'q')
714 goto quit;
715 continue;
716
887e3e0d
MH
717/* xit */
718 case 'x':
719 tail("xit");
720 if (!chng)
721 goto quit;
722 c = 'q';
723 goto wq;
724
d9fbdd64
MH
725/* yank */
726 case 'y':
727 tail("yank");
728 c = cmdreg();
729 setcount();
730 eol();
d266c416 731 vmacchng(0);
d9fbdd64
MH
732 if (c)
733 YANKreg(c);
734 else
735 yank();
736 continue;
737
738/* z */
739 case 'z':
740 zop(0);
741 pflag = 0;
742 continue;
743
744/* * */
745/* @ */
746 case '*':
747 case '@':
748 c = getchar();
749 if (c=='\n' || c=='\r')
750 ungetchar(c);
751 if (any(c, "@*\n\r"))
752 c = lastmac;
753 if (isupper(c))
754 c = tolower(c);
755 if (!islower(c))
756 error("Bad register");
757 newline();
758 setdot();
759 cmdmac(c);
760 continue;
761
762/* | */
763 case '|':
764 endline = 0;
765 goto caseline;
766
767/* \n */
768 case '\n':
769 endline = 1;
770caseline:
771 notempty();
772 if (addr2 == 0) {
d9fbdd64
MH
773 if (UP != NOSTR && c == '\n' && !inglobal)
774 c = CTRL(k);
775 if (inglobal)
776 addr1 = addr2 = dot;
887e3e0d
MH
777 else {
778 if (dot == dol)
779 error("At EOF|At end-of-file");
d9fbdd64 780 addr1 = addr2 = dot + 1;
887e3e0d 781 }
d9fbdd64
MH
782 }
783 setdot();
784 nonzero();
785 if (seensemi)
786 addr1 = addr2;
787 getline(*addr1);
788 if (c == CTRL(k)) {
789 flush1();
790 destline--;
791 if (hadpr)
792 shudclob = 1;
793 }
794 plines(addr1, addr2, 1);
795 continue;
796
d266c416
MH
797/* " */
798 case '"':
799 comment();
800 continue;
801
d9fbdd64
MH
802/* # */
803 case '#':
804numberit:
805 setCNL();
806 ignorf(setnumb(1));
807 pflag = 0;
808 goto print;
809
810/* = */
811 case '=':
812 newline();
813 setall();
887e3e0d
MH
814 if (inglobal == 2)
815 pofix();
d9fbdd64
MH
816 printf("%d", lineno(addr2));
817 noonl();
818 continue;
819
820/* ! */
821 case '!':
822 if (addr2 != 0) {
d266c416 823 vmacchng(0);
d9fbdd64
MH
824 unix0(0);
825 setdot();
826 filter(2);
827 } else {
828 unix0(1);
887e3e0d 829 pofix();
d9fbdd64
MH
830 putpad(TE);
831 flush();
832 unixwt(1, unixex("-c", uxb, 0, 0));
d266c416 833 vclrech(1); /* vcontin(0); */
d9fbdd64
MH
834 nochng();
835 }
836 continue;
837
838/* < */
839/* > */
840 case '<':
841 case '>':
842 for (cnt = 1; peekchar() == c; cnt++)
843 ignchar();
844 setCNL();
d266c416 845 vmacchng(0);
d9fbdd64
MH
846 shift(c, cnt);
847 continue;
848
849/* ^D */
850/* EOF */
851 case CTRL(d):
852 case EOF:
853 if (exitoneof) {
854 if (addr2 != 0)
855 dot = addr2;
856 return;
857 }
858 if (!isatty(0)) {
859 if (intty)
860 /*
861 * Chtty sys call at UCB may cause a
862 * input which was a tty to suddenly be
863 * turned into /dev/null.
864 */
865 onhup();
866 return;
867 }
868 if (addr2 != 0) {
869 setlastchar('\n');
870 putnl();
871 }
872 if (dol == zero) {
873 if (addr2 == 0)
874 putnl();
875 notempty();
876 }
877 ungetchar(EOF);
878 zop(hadpr);
879 continue;
880
881 default:
882 if (!isalpha(c))
883 break;
884 ungetchar(c);
885 tailprim("", 0, 0);
886 }
887 error("What?|Unknown command character '%c'", c);
888 }
889}