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