|
|
1.1 root 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:
7: bool pflag, nflag;
8: int 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: */
18: commands(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)
55: error("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"))
132: notinvis:
133: tailprim(Command, 1, 1);
134: }
135: choice:
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");
183: changdir:
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();
248: doecmd:
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: /*
264: synctmp();
265: */
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':
306: casek:
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;
409: print:
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)
425: quit:
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 */
601: printf("Version 3.2, January 4, 1980");
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;
681: caseline:
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 '#':
709: numberit:
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.