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.13 (Berkeley) 06/29/90"; 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 c = exclam(); 597 eol(); 598 if (!c) 599 ckaw(); 600 onsusp(); 601 continue; 602 #endif 603 604 } 605 /* fall into ... */ 606 607 /* & */ 608 /* ~ */ 609 /* substitute */ 610 case '&': 611 case '~': 612 Command = "substitute"; 613 if (c == 's') 614 tail(Command); 615 vmacchng(0); 616 if (!substitute(c)) 617 pflag = 0; 618 continue; 619 620 /* t */ 621 case 't': 622 if (peekchar() == 'a') { 623 tail("tag"); 624 tagfind(exclam()); 625 if (!inopen) 626 lchng = chng - 1; 627 else 628 nochng(); 629 continue; 630 } 631 tail("t"); 632 vmacchng(0); 633 move(); 634 continue; 635 636 case 'u': 637 if (peekchar() == 'n') { 638 ignchar(); 639 switch(peekchar()) { 640 /* unmap */ 641 case 'm': 642 tail2of("unmap"); 643 setnoaddr(); 644 mapcmd(1, 0); 645 continue; 646 /* unabbreviate */ 647 case 'a': 648 tail2of("unabbreviate"); 649 setnoaddr(); 650 mapcmd(1, 1); 651 anyabbrs = 1; 652 continue; 653 } 654 /* undo */ 655 tail2of("undo"); 656 } else 657 tail("undo"); 658 setnoaddr(); 659 markDOT(); 660 c = exclam(); 661 newline(); 662 undo(c); 663 continue; 664 665 case 'v': 666 switch (peekchar()) { 667 668 case 'e': 669 /* version */ 670 tail("version"); 671 setNAEOL(); 672 ex_printf("@(#) Version 3.7, 6/7/85."+5); 673 noonl(); 674 continue; 675 676 /* visual */ 677 case 'i': 678 tail("visual"); 679 if (inopen) { 680 c = 'e'; 681 goto editcmd; 682 } 683 vop(); 684 pflag = 0; 685 nochng(); 686 continue; 687 } 688 /* v */ 689 tail("v"); 690 global(0); 691 nochng(); 692 continue; 693 694 /* write */ 695 case 'w': 696 c = peekchar(); 697 tail(c == 'q' ? "wq" : "write"); 698 wq: 699 if (skipwh() && peekchar() == '!') { 700 pofix(); 701 ignchar(); 702 setall(); 703 unix0(0); 704 filter(1); 705 } else { 706 setall(); 707 wop(1); 708 nochng(); 709 } 710 if (c == 'q') 711 goto quit; 712 continue; 713 714 /* xit */ 715 case 'x': 716 tail("xit"); 717 if (!chng) 718 goto quit; 719 c = 'q'; 720 goto wq; 721 722 /* yank */ 723 case 'y': 724 tail("yank"); 725 c = cmdreg(); 726 setcount(); 727 eol(); 728 vmacchng(0); 729 if (c) 730 YANKreg(c); 731 else 732 yank(); 733 continue; 734 735 /* z */ 736 case 'z': 737 zop(0); 738 pflag = 0; 739 continue; 740 741 /* * */ 742 /* @ */ 743 case '*': 744 case '@': 745 c = ex_getchar(); 746 if (c=='\n' || c=='\r') 747 ungetchar(c); 748 if (any(c, "@*\n\r")) 749 c = lastmac; 750 if (isupper(c)) 751 c = tolower(c); 752 if (!islower(c)) 753 error("Bad register"); 754 newline(); 755 setdot(); 756 cmdmac(c); 757 continue; 758 759 /* | */ 760 case '|': 761 endline = 0; 762 goto caseline; 763 764 /* \n */ 765 case '\n': 766 endline = 1; 767 caseline: 768 notempty(); 769 if (addr2 == 0) { 770 if (UP != NOSTR && c == '\n' && !inglobal) 771 c = CTRL('k'); 772 if (inglobal) 773 addr1 = addr2 = dot; 774 else { 775 if (dot == dol) 776 error("At EOF|At end-of-file"); 777 addr1 = addr2 = dot + 1; 778 } 779 } 780 setdot(); 781 nonzero(); 782 if (seensemi) 783 addr1 = addr2; 784 getline(*addr1); 785 if (c == CTRL('k')) { 786 flush1(); 787 destline--; 788 if (hadpr) 789 shudclob = 1; 790 } 791 plines(addr1, addr2, 1); 792 continue; 793 794 /* " */ 795 case '"': 796 comment(); 797 continue; 798 799 /* # */ 800 case '#': 801 numberit: 802 setCNL(); 803 ignorf(setnumb(1)); 804 pflag = 0; 805 goto print; 806 807 /* = */ 808 case '=': 809 newline(); 810 setall(); 811 if (inglobal == 2) 812 pofix(); 813 ex_printf("%d", lineno(addr2)); 814 noonl(); 815 continue; 816 817 /* ! */ 818 case '!': 819 if (addr2 != 0) { 820 vmacchng(0); 821 unix0(0); 822 setdot(); 823 filter(2); 824 } else { 825 unix0(1); 826 pofix(); 827 putpad(TE); 828 flush(); 829 unixwt(1, unixex("-c", uxb, 0, 0)); 830 vclrech(1); /* vcontin(0); */ 831 nochng(); 832 } 833 continue; 834 835 /* < */ 836 /* > */ 837 case '<': 838 case '>': 839 for (cnt = 1; peekchar() == c; cnt++) 840 ignchar(); 841 setCNL(); 842 vmacchng(0); 843 shift(c, cnt); 844 continue; 845 846 /* ^D */ 847 /* EOF */ 848 case CTRL('d'): 849 case EOF: 850 if (exitoneof) { 851 if (addr2 != 0) 852 dot = addr2; 853 return; 854 } 855 if (!isatty(0)) { 856 if (intty) 857 /* 858 * Chtty sys call at UCB may cause a 859 * input which was a tty to suddenly be 860 * turned into /dev/null. 861 */ 862 onhup(); 863 return; 864 } 865 if (addr2 != 0) { 866 setlastchar('\n'); 867 putnl(); 868 } 869 if (dol == zero) { 870 if (addr2 == 0) 871 putnl(); 872 notempty(); 873 } 874 ungetchar(EOF); 875 zop(hadpr); 876 continue; 877 878 default: 879 if (!isalpha(c)) 880 break; 881 ungetchar(c); 882 tailprim("", 0, 0); 883 } 884 error("What?|Unknown command character '%c'", c); 885 } 886 } 887