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