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