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