BSD 4_3_Reno release
[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
1c15e888 8static char *sccsid = "@(#)ex_cmds.c 7.13 (Berkeley) 6/29/90";
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) {
5a6c967e 80 ex_putchar(':');
d9fbdd64
MH
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;
5a6c967e 94 addr = address((char *) 0);
d9fbdd64
MH
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;
5a6c967e 117 c = ex_getchar();
d9fbdd64
MH
118 }
119 if (addr1 == 0)
120 addr1 = addr2;
121 if (c == ':')
5a6c967e 122 c = ex_getchar();
d9fbdd64
MH
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) {
65bacefd 134 if (c=='\n' || c=='\r' || c==CTRL('d') || c==EOF) {
d9fbdd64
MH
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 }
d9fbdd64
MH
145 switch (c) {
146
147 case 'a':
148
d266c416
MH
149 switch(peekchar()) {
150 case 'b':
151/* abbreviate */
152 tail("abbreviate");
153 setnoaddr();
154 mapcmd(0, 1);
155 anyabbrs = 1;
156 continue;
157 case 'r':
d9fbdd64
MH
158/* args */
159 tail("args");
160 setnoaddr();
161 eol();
162 pargs();
163 continue;
164 }
165
166/* append */
167 if (inopen)
168 goto notinvis;
169 tail("append");
170 setdot();
171 aiflag = exclam();
172 newline();
d266c416 173 vmacchng(0);
d9fbdd64
MH
174 deletenone();
175 setin(addr2);
d266c416 176 inappend = 1;
d9fbdd64 177 ignore(append(gettty, addr2));
d266c416 178 inappend = 0;
d9fbdd64
MH
179 nochng();
180 continue;
181
182 case 'c':
183 switch (peekchar()) {
184
185/* copy */
186 case 'o':
187 tail("copy");
d266c416 188 vmacchng(0);
d9fbdd64
MH
189 move();
190 continue;
191
192#ifdef CHDIR
193/* cd */
194 case 'd':
195 tail("cd");
196 goto changdir;
197
198/* chdir */
199 case 'h':
200 ignchar();
201 if (peekchar() == 'd') {
202 register char *p;
203 tail2of("chdir");
204changdir:
205 if (savedfile[0] == '/' || !value(WARN))
206 ignore(exclam());
207 else
208 ignore(quickly());
209 if (skipend()) {
210 p = getenv("HOME");
211 if (p == NULL)
212 error("Home directory unknown");
213 } else
214 getone(), p = file;
215 eol();
216 if (chdir(p) < 0)
217 filioerr(p);
218 if (savedfile[0] != '/')
219 edited = 0;
220 continue;
221 }
222 if (inopen)
223 tailprim("change", 2, 1);
224 tail2of("change");
225 break;
226
227#endif
228 default:
229 if (inopen)
230 goto notinvis;
231 tail("change");
232 break;
233 }
234/* change */
235 aiflag = exclam();
236 setCNL();
d266c416 237 vmacchng(0);
d9fbdd64 238 setin(addr1);
5a6c967e 239 ex_delete(0);
d266c416 240 inappend = 1;
d9fbdd64 241 ignore(append(gettty, addr1 - 1));
d266c416 242 inappend = 0;
d9fbdd64
MH
243 nochng();
244 continue;
245
246/* delete */
247 case 'd':
248 /*
249 * Caution: dp and dl have special meaning already.
250 */
251 tail("delete");
252 c = cmdreg();
253 setCNL();
d266c416 254 vmacchng(0);
d9fbdd64
MH
255 if (c)
256 YANKreg(c);
5a6c967e 257 ex_delete(0);
d9fbdd64
MH
258 appendnone();
259 continue;
260
261/* edit */
262/* ex */
263 case 'e':
264 tail(peekchar() == 'x' ? "ex" : "edit");
d266c416 265editcmd:
d9fbdd64
MH
266 if (!exclam() && chng)
267 c = 'E';
268 filename(c);
269 if (c == 'E') {
270 ungetchar(lastchar());
271 ignore(quickly());
272 }
273 setnoaddr();
274doecmd:
275 init();
276 addr2 = zero;
277 laste++;
5a6c967e 278 ex_sync();
d9fbdd64 279 rop(c);
79086561
RC
280#ifdef VMUNIX
281 tlaste();
282#endif
283 laste = 0;
5a6c967e 284 ex_sync();
d9fbdd64
MH
285 nochng();
286 continue;
287
288/* file */
289 case 'f':
290 tail("file");
291 setnoaddr();
292 filename(c);
293 noonl();
44232d5b 294/*
d9fbdd64 295 synctmp();
44232d5b 296*/
d9fbdd64
MH
297 continue;
298
299/* global */
300 case 'g':
301 tail("global");
302 global(!exclam());
303 nochng();
304 continue;
305
306/* insert */
307 case 'i':
308 if (inopen)
309 goto notinvis;
310 tail("insert");
311 setdot();
312 nonzero();
313 aiflag = exclam();
314 newline();
d266c416 315 vmacchng(0);
d9fbdd64
MH
316 deletenone();
317 setin(addr2);
d266c416 318 inappend = 1;
d9fbdd64 319 ignore(append(gettty, addr2 - 1));
d266c416 320 inappend = 0;
d9fbdd64
MH
321 if (dot == zero && dol > zero)
322 dot = one;
323 nochng();
324 continue;
325
326/* join */
327 case 'j':
328 tail("join");
329 c = exclam();
330 setcount();
331 nonzero();
332 newline();
d266c416 333 vmacchng(0);
d9fbdd64
MH
334 if (given < 2 && addr2 != dol)
335 addr2++;
336 join(c);
337 continue;
338
339/* k */
340 case 'k':
341casek:
342 pastwh();
5a6c967e 343 c = ex_getchar();
d9fbdd64
MH
344 if (endcmd(c))
345 serror("Mark what?|%s requires following letter", Command);
346 newline();
347 if (!islower(c))
348 error("Bad mark|Mark must specify a letter");
349 setdot();
350 nonzero();
351 names[c - 'a'] = *addr2 &~ 01;
352 anymarks = 1;
353 continue;
354
355/* list */
356 case 'l':
357 tail("list");
358 setCNL();
359 ignorf(setlist(1));
360 pflag = 0;
361 goto print;
362
363 case 'm':
364 if (peekchar() == 'a') {
365 ignchar();
366 if (peekchar() == 'p') {
367/* map */
368 tail2of("map");
369 setnoaddr();
d266c416 370 mapcmd(0, 0);
d9fbdd64
MH
371 continue;
372 }
373/* mark */
374 tail2of("mark");
375 goto casek;
376 }
377/* move */
378 tail("move");
d266c416 379 vmacchng(0);
d9fbdd64
MH
380 move();
381 continue;
382
383 case 'n':
384 if (peekchar() == 'u') {
385 tail("number");
386 goto numberit;
387 }
388/* next */
389 tail("next");
390 setnoaddr();
391 ckaw();
392 ignore(quickly());
393 if (getargs())
394 makargs();
395 next();
396 c = 'e';
397 filename(c);
398 goto doecmd;
399
400/* open */
401 case 'o':
402 tail("open");
403 oop();
404 pflag = 0;
405 nochng();
406 continue;
407
408 case 'p':
409 case 'P':
410 switch (peekchar()) {
411
412/* put */
413 case 'u':
414 tail("put");
415 setdot();
416 c = cmdreg();
417 eol();
d266c416 418 vmacchng(0);
d9fbdd64
MH
419 if (c)
420 putreg(c);
421 else
422 put();
423 continue;
424
425 case 'r':
426 ignchar();
427 if (peekchar() == 'e') {
428/* preserve */
429 tail2of("preserve");
430 eol();
431 if (preserve() == 0)
432 error("Preserve failed!");
433 else
434 error("File preserved.");
435 }
436 tail2of("print");
437 break;
438
439 default:
440 tail("print");
441 break;
442 }
443/* print */
444 setCNL();
445 pflag = 0;
446print:
447 nonzero();
448 if (CL && span() > LINES) {
449 flush1();
450 vclear();
451 }
452 plines(addr1, addr2, 1);
453 continue;
454
455/* quit */
456 case 'q':
457 tail("quit");
458 setnoaddr();
459 c = quickly();
460 eol();
461 if (!c)
462quit:
463 nomore();
464 if (inopen) {
465 vgoto(WECHO, 0);
466 if (!ateopr())
467 vnfl();
468 else {
d266c416 469 tostop();
d9fbdd64
MH
470 }
471 flush();
5a6c967e 472 ignore(setty(normf));
d9fbdd64
MH
473 }
474 cleanup(1);
5a6c967e 475 ex_exit(0);
d9fbdd64
MH
476
477 case 'r':
478 if (peekchar() == 'e') {
479 ignchar();
480 switch (peekchar()) {
481
482/* rewind */
483 case 'w':
484 tail2of("rewind");
485 setnoaddr();
10499a70
MH
486 if (!exclam()) {
487 ckaw();
488 if (chng && dol > zero)
489 error("No write@since last chage (:rewind! overrides)");
490 }
d9fbdd64
MH
491 eol();
492 erewind();
493 next();
494 c = 'e';
495 ungetchar(lastchar());
496 filename(c);
497 goto doecmd;
498
499/* recover */
500 case 'c':
501 tail2of("recover");
502 setnoaddr();
503 c = 'e';
504 if (!exclam() && chng)
505 c = 'E';
506 filename(c);
507 if (c == 'E') {
508 ungetchar(lastchar());
509 ignore(quickly());
510 }
511 init();
512 addr2 = zero;
513 laste++;
5a6c967e 514 ex_sync();
d9fbdd64
MH
515 recover();
516 rop2();
517 revocer();
518 if (status == 0)
519 rop3(c);
520 if (dol != zero)
521 change();
79086561
RC
522#ifdef VMUNIX
523 tlaste();
524#endif
525 laste = 0;
d9fbdd64
MH
526 nochng();
527 continue;
528 }
529 tail2of("read");
530 } else
531 tail("read");
532/* read */
533 if (savedfile[0] == 0 && dol == zero)
534 c = 'e';
535 pastwh();
d266c416 536 vmacchng(0);
d9fbdd64
MH
537 if (peekchar() == '!') {
538 setdot();
539 ignchar();
540 unix0(0);
541 filter(0);
542 continue;
543 }
544 filename(c);
545 rop(c);
546 nochng();
547 if (inopen && endline && addr1 > zero && addr1 < dol)
548 dot = addr1 + 1;
549 continue;
550
551 case 's':
552 switch (peekchar()) {
553 /*
554 * Caution: 2nd char cannot be c, g, or r
555 * because these have meaning to substitute.
556 */
557
558/* set */
559 case 'e':
560 tail("set");
561 setnoaddr();
562 set();
563 continue;
564
565/* shell */
566 case 'h':
567 tail("shell");
568 setNAEOL();
569 vnfl();
570 putpad(TE);
571 flush();
572 unixwt(1, unixex("-i", (char *) 0, 0, 0));
573 vcontin(0);
d9fbdd64
MH
574 continue;
575
576/* source */
577 case 'o':
04379bab 578#ifdef notdef
d9fbdd64
MH
579 if (inopen)
580 goto notinvis;
04379bab 581#endif
d9fbdd64
MH
582 tail("source");
583 setnoaddr();
584 getone();
585 eol();
586 source(file, 0);
587 continue;
bdbbb330 588#ifdef SIGTSTP
04379bab 589/* stop, suspend */
d266c416
MH
590 case 't':
591 tail("stop");
04379bab
MH
592 goto suspend;
593 case 'u':
594 tail("suspend");
595suspend:
d266c416
MH
596 c = exclam();
597 eol();
598 if (!c)
599 ckaw();
d266c416
MH
600 onsusp();
601 continue;
602#endif
603
d9fbdd64
MH
604 }
605 /* fall into ... */
606
607/* & */
608/* ~ */
609/* substitute */
610 case '&':
611 case '~':
612 Command = "substitute";
613 if (c == 's')
614 tail(Command);
d266c416 615 vmacchng(0);
d9fbdd64
MH
616 if (!substitute(c))
617 pflag = 0;
618 continue;
619
620/* t */
621 case 't':
622 if (peekchar() == 'a') {
623 tail("tag");
624 tagfind(exclam());
625 if (!inopen)
626 lchng = chng - 1;
627 else
628 nochng();
629 continue;
630 }
631 tail("t");
d266c416 632 vmacchng(0);
d9fbdd64
MH
633 move();
634 continue;
635
636 case 'u':
637 if (peekchar() == 'n') {
d9fbdd64 638 ignchar();
d266c416
MH
639 switch(peekchar()) {
640/* unmap */
641 case 'm':
d9fbdd64
MH
642 tail2of("unmap");
643 setnoaddr();
d266c416
MH
644 mapcmd(1, 0);
645 continue;
646/* unabbreviate */
647 case 'a':
648 tail2of("unabbreviate");
649 setnoaddr();
650 mapcmd(1, 1);
651 anyabbrs = 1;
d9fbdd64
MH
652 continue;
653 }
654/* undo */
655 tail2of("undo");
656 } else
657 tail("undo");
658 setnoaddr();
659 markDOT();
660 c = exclam();
661 newline();
662 undo(c);
663 continue;
664
665 case 'v':
666 switch (peekchar()) {
667
668 case 'e':
669/* version */
670 tail("version");
671 setNAEOL();
5a6c967e 672 ex_printf("@(#) Version 3.7, 6/7/85."+5);
d9fbdd64
MH
673 noonl();
674 continue;
675
676/* visual */
677 case 'i':
678 tail("visual");
d266c416
MH
679 if (inopen) {
680 c = 'e';
681 goto editcmd;
682 }
d9fbdd64
MH
683 vop();
684 pflag = 0;
685 nochng();
686 continue;
687 }
688/* v */
689 tail("v");
690 global(0);
691 nochng();
692 continue;
693
694/* write */
695 case 'w':
696 c = peekchar();
697 tail(c == 'q' ? "wq" : "write");
887e3e0d 698wq:
d9fbdd64 699 if (skipwh() && peekchar() == '!') {
887e3e0d 700 pofix();
d9fbdd64
MH
701 ignchar();
702 setall();
703 unix0(0);
704 filter(1);
705 } else {
706 setall();
707 wop(1);
708 nochng();
709 }
710 if (c == 'q')
711 goto quit;
712 continue;
713
887e3e0d
MH
714/* xit */
715 case 'x':
716 tail("xit");
717 if (!chng)
718 goto quit;
719 c = 'q';
720 goto wq;
721
d9fbdd64
MH
722/* yank */
723 case 'y':
724 tail("yank");
725 c = cmdreg();
726 setcount();
727 eol();
d266c416 728 vmacchng(0);
d9fbdd64
MH
729 if (c)
730 YANKreg(c);
731 else
732 yank();
733 continue;
734
735/* z */
736 case 'z':
737 zop(0);
738 pflag = 0;
739 continue;
740
741/* * */
742/* @ */
743 case '*':
744 case '@':
5a6c967e 745 c = ex_getchar();
d9fbdd64
MH
746 if (c=='\n' || c=='\r')
747 ungetchar(c);
748 if (any(c, "@*\n\r"))
749 c = lastmac;
750 if (isupper(c))
751 c = tolower(c);
752 if (!islower(c))
753 error("Bad register");
754 newline();
755 setdot();
756 cmdmac(c);
757 continue;
758
759/* | */
760 case '|':
761 endline = 0;
762 goto caseline;
763
764/* \n */
765 case '\n':
766 endline = 1;
767caseline:
768 notempty();
769 if (addr2 == 0) {
d9fbdd64 770 if (UP != NOSTR && c == '\n' && !inglobal)
65bacefd 771 c = CTRL('k');
d9fbdd64
MH
772 if (inglobal)
773 addr1 = addr2 = dot;
887e3e0d
MH
774 else {
775 if (dot == dol)
776 error("At EOF|At end-of-file");
d9fbdd64 777 addr1 = addr2 = dot + 1;
887e3e0d 778 }
d9fbdd64
MH
779 }
780 setdot();
781 nonzero();
782 if (seensemi)
783 addr1 = addr2;
784 getline(*addr1);
65bacefd 785 if (c == CTRL('k')) {
d9fbdd64
MH
786 flush1();
787 destline--;
788 if (hadpr)
789 shudclob = 1;
790 }
791 plines(addr1, addr2, 1);
792 continue;
793
d266c416
MH
794/* " */
795 case '"':
796 comment();
797 continue;
798
d9fbdd64
MH
799/* # */
800 case '#':
801numberit:
802 setCNL();
803 ignorf(setnumb(1));
804 pflag = 0;
805 goto print;
806
807/* = */
808 case '=':
809 newline();
810 setall();
887e3e0d
MH
811 if (inglobal == 2)
812 pofix();
5a6c967e 813 ex_printf("%d", lineno(addr2));
d9fbdd64
MH
814 noonl();
815 continue;
816
817/* ! */
818 case '!':
819 if (addr2 != 0) {
d266c416 820 vmacchng(0);
d9fbdd64
MH
821 unix0(0);
822 setdot();
823 filter(2);
824 } else {
825 unix0(1);
887e3e0d 826 pofix();
d9fbdd64
MH
827 putpad(TE);
828 flush();
829 unixwt(1, unixex("-c", uxb, 0, 0));
d266c416 830 vclrech(1); /* vcontin(0); */
d9fbdd64
MH
831 nochng();
832 }
833 continue;
834
835/* < */
836/* > */
837 case '<':
838 case '>':
839 for (cnt = 1; peekchar() == c; cnt++)
840 ignchar();
841 setCNL();
d266c416 842 vmacchng(0);
d9fbdd64
MH
843 shift(c, cnt);
844 continue;
845
846/* ^D */
847/* EOF */
65bacefd 848 case CTRL('d'):
d9fbdd64
MH
849 case EOF:
850 if (exitoneof) {
851 if (addr2 != 0)
852 dot = addr2;
853 return;
854 }
855 if (!isatty(0)) {
856 if (intty)
857 /*
858 * Chtty sys call at UCB may cause a
859 * input which was a tty to suddenly be
860 * turned into /dev/null.
861 */
862 onhup();
863 return;
864 }
865 if (addr2 != 0) {
866 setlastchar('\n');
867 putnl();
868 }
869 if (dol == zero) {
870 if (addr2 == 0)
871 putnl();
872 notempty();
873 }
874 ungetchar(EOF);
875 zop(hadpr);
876 continue;
877
878 default:
879 if (!isalpha(c))
880 break;
881 ungetchar(c);
882 tailprim("", 0, 0);
883 }
884 error("What?|Unknown command character '%c'", c);
885 }
886}