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