1 /* Copyright (c) 1981 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_cmds.c 7.6 10/31/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) 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/31/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 } 873