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