1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_cmds.c 6.3 11/03/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 } 458 flush(); 459 setty(normf); 460 } 461 cleanup(1); 462 exit(0); 463 464 case 'r': 465 if (peekchar() == 'e') { 466 ignchar(); 467 switch (peekchar()) { 468 469 /* rewind */ 470 case 'w': 471 tail2of("rewind"); 472 setnoaddr(); 473 if (!exclam()) { 474 ckaw(); 475 if (chng && dol > zero) 476 error("No write@since last chage (:rewind! overrides)"); 477 } 478 eol(); 479 erewind(); 480 next(); 481 c = 'e'; 482 ungetchar(lastchar()); 483 filename(c); 484 goto doecmd; 485 486 /* recover */ 487 case 'c': 488 tail2of("recover"); 489 setnoaddr(); 490 c = 'e'; 491 if (!exclam() && chng) 492 c = 'E'; 493 filename(c); 494 if (c == 'E') { 495 ungetchar(lastchar()); 496 ignore(quickly()); 497 } 498 init(); 499 addr2 = zero; 500 laste++; 501 sync(); 502 recover(); 503 rop2(); 504 revocer(); 505 if (status == 0) 506 rop3(c); 507 if (dol != zero) 508 change(); 509 nochng(); 510 continue; 511 } 512 tail2of("read"); 513 } else 514 tail("read"); 515 /* read */ 516 if (savedfile[0] == 0 && dol == zero) 517 c = 'e'; 518 pastwh(); 519 vmacchng(0); 520 if (peekchar() == '!') { 521 setdot(); 522 ignchar(); 523 unix0(0); 524 filter(0); 525 continue; 526 } 527 filename(c); 528 rop(c); 529 nochng(); 530 if (inopen && endline && addr1 > zero && addr1 < dol) 531 dot = addr1 + 1; 532 continue; 533 534 case 's': 535 switch (peekchar()) { 536 /* 537 * Caution: 2nd char cannot be c, g, or r 538 * because these have meaning to substitute. 539 */ 540 541 /* set */ 542 case 'e': 543 tail("set"); 544 setnoaddr(); 545 set(); 546 continue; 547 548 /* shell */ 549 case 'h': 550 tail("shell"); 551 setNAEOL(); 552 vnfl(); 553 putpad(TE); 554 flush(); 555 unixwt(1, unixex("-i", (char *) 0, 0, 0)); 556 vcontin(0); 557 continue; 558 559 /* source */ 560 case 'o': 561 #ifdef notdef 562 if (inopen) 563 goto notinvis; 564 #endif 565 tail("source"); 566 setnoaddr(); 567 getone(); 568 eol(); 569 source(file, 0); 570 continue; 571 #ifdef SIGTSTP 572 /* stop, suspend */ 573 case 't': 574 tail("stop"); 575 goto suspend; 576 case 'u': 577 tail("suspend"); 578 suspend: 579 if (!ldisc) 580 error("Old tty driver|Not using new tty driver/shell"); 581 c = exclam(); 582 eol(); 583 if (!c) 584 ckaw(); 585 onsusp(); 586 continue; 587 #endif 588 589 } 590 /* fall into ... */ 591 592 /* & */ 593 /* ~ */ 594 /* substitute */ 595 case '&': 596 case '~': 597 Command = "substitute"; 598 if (c == 's') 599 tail(Command); 600 vmacchng(0); 601 if (!substitute(c)) 602 pflag = 0; 603 continue; 604 605 /* t */ 606 case 't': 607 if (peekchar() == 'a') { 608 tail("tag"); 609 tagfind(exclam()); 610 if (!inopen) 611 lchng = chng - 1; 612 else 613 nochng(); 614 continue; 615 } 616 tail("t"); 617 vmacchng(0); 618 move(); 619 continue; 620 621 case 'u': 622 if (peekchar() == 'n') { 623 ignchar(); 624 switch(peekchar()) { 625 /* unmap */ 626 case 'm': 627 tail2of("unmap"); 628 setnoaddr(); 629 mapcmd(1, 0); 630 continue; 631 /* unabbreviate */ 632 case 'a': 633 tail2of("unabbreviate"); 634 setnoaddr(); 635 mapcmd(1, 1); 636 anyabbrs = 1; 637 continue; 638 } 639 /* undo */ 640 tail2of("undo"); 641 } else 642 tail("undo"); 643 setnoaddr(); 644 markDOT(); 645 c = exclam(); 646 newline(); 647 undo(c); 648 continue; 649 650 case 'v': 651 switch (peekchar()) { 652 653 case 'e': 654 /* version */ 655 tail("version"); 656 setNAEOL(); 657 printf("@(#) Version 3.6, 11/03/80."+5); 658 noonl(); 659 continue; 660 661 /* visual */ 662 case 'i': 663 tail("visual"); 664 if (inopen) { 665 c = 'e'; 666 goto editcmd; 667 } 668 vop(); 669 pflag = 0; 670 nochng(); 671 continue; 672 } 673 /* v */ 674 tail("v"); 675 global(0); 676 nochng(); 677 continue; 678 679 /* write */ 680 case 'w': 681 c = peekchar(); 682 tail(c == 'q' ? "wq" : "write"); 683 wq: 684 if (skipwh() && peekchar() == '!') { 685 pofix(); 686 ignchar(); 687 setall(); 688 unix0(0); 689 filter(1); 690 } else { 691 setall(); 692 wop(1); 693 nochng(); 694 } 695 if (c == 'q') 696 goto quit; 697 continue; 698 699 /* xit */ 700 case 'x': 701 tail("xit"); 702 if (!chng) 703 goto quit; 704 c = 'q'; 705 goto wq; 706 707 /* yank */ 708 case 'y': 709 tail("yank"); 710 c = cmdreg(); 711 setcount(); 712 eol(); 713 vmacchng(0); 714 if (c) 715 YANKreg(c); 716 else 717 yank(); 718 continue; 719 720 /* z */ 721 case 'z': 722 zop(0); 723 pflag = 0; 724 continue; 725 726 /* * */ 727 /* @ */ 728 case '*': 729 case '@': 730 c = getchar(); 731 if (c=='\n' || c=='\r') 732 ungetchar(c); 733 if (any(c, "@*\n\r")) 734 c = lastmac; 735 if (isupper(c)) 736 c = tolower(c); 737 if (!islower(c)) 738 error("Bad register"); 739 newline(); 740 setdot(); 741 cmdmac(c); 742 continue; 743 744 /* | */ 745 case '|': 746 endline = 0; 747 goto caseline; 748 749 /* \n */ 750 case '\n': 751 endline = 1; 752 caseline: 753 notempty(); 754 if (addr2 == 0) { 755 if (UP != NOSTR && c == '\n' && !inglobal) 756 c = CTRL(k); 757 if (inglobal) 758 addr1 = addr2 = dot; 759 else { 760 if (dot == dol) 761 error("At EOF|At end-of-file"); 762 addr1 = addr2 = dot + 1; 763 } 764 } 765 setdot(); 766 nonzero(); 767 if (seensemi) 768 addr1 = addr2; 769 getline(*addr1); 770 if (c == CTRL(k)) { 771 flush1(); 772 destline--; 773 if (hadpr) 774 shudclob = 1; 775 } 776 plines(addr1, addr2, 1); 777 continue; 778 779 /* " */ 780 case '"': 781 comment(); 782 continue; 783 784 /* # */ 785 case '#': 786 numberit: 787 setCNL(); 788 ignorf(setnumb(1)); 789 pflag = 0; 790 goto print; 791 792 /* = */ 793 case '=': 794 newline(); 795 setall(); 796 if (inglobal == 2) 797 pofix(); 798 printf("%d", lineno(addr2)); 799 noonl(); 800 continue; 801 802 /* ! */ 803 case '!': 804 if (addr2 != 0) { 805 vmacchng(0); 806 unix0(0); 807 setdot(); 808 filter(2); 809 } else { 810 unix0(1); 811 pofix(); 812 putpad(TE); 813 flush(); 814 unixwt(1, unixex("-c", uxb, 0, 0)); 815 vclrech(1); /* vcontin(0); */ 816 nochng(); 817 } 818 continue; 819 820 /* < */ 821 /* > */ 822 case '<': 823 case '>': 824 for (cnt = 1; peekchar() == c; cnt++) 825 ignchar(); 826 setCNL(); 827 vmacchng(0); 828 shift(c, cnt); 829 continue; 830 831 /* ^D */ 832 /* EOF */ 833 case CTRL(d): 834 case EOF: 835 if (exitoneof) { 836 if (addr2 != 0) 837 dot = addr2; 838 return; 839 } 840 if (!isatty(0)) { 841 if (intty) 842 /* 843 * Chtty sys call at UCB may cause a 844 * input which was a tty to suddenly be 845 * turned into /dev/null. 846 */ 847 onhup(); 848 return; 849 } 850 if (addr2 != 0) { 851 setlastchar('\n'); 852 putnl(); 853 } 854 if (dol == zero) { 855 if (addr2 == 0) 856 putnl(); 857 notempty(); 858 } 859 ungetchar(EOF); 860 zop(hadpr); 861 continue; 862 863 default: 864 if (!isalpha(c)) 865 break; 866 ungetchar(c); 867 tailprim("", 0, 0); 868 } 869 error("What?|Unknown command character '%c'", c); 870 } 871 } 872