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