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