1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 30 /* Copyright (c) 1981 Regents of the University of California */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include "ex.h" 35 #include "ex_argv.h" 36 #include "ex_temp.h" 37 #include "ex_tty.h" 38 #include "ex_vis.h" 39 40 bool pflag, nflag; 41 int poffset; 42 43 #define nochng() lchng = chng 44 45 46 /* 47 * Main loop for command mode command decoding. 48 * A few commands are executed here, but main function 49 * is to strip command addresses, do a little address oriented 50 * processing and call command routines to do the real work. 51 */ 52 extern unsigned char *Version; 53 void 54 commands(noprompt, exitoneof) 55 bool noprompt, exitoneof; 56 { 57 line *addr; 58 int c; 59 int lchng; 60 int given; 61 int seensemi; 62 int cnt; 63 bool hadpr; 64 bool gotfile; 65 #ifdef XPG4 66 int d; 67 #endif /* XPG4 */ 68 unsigned char *vgetpass(); 69 70 resetflav(); 71 nochng(); 72 for (;;) { 73 if (!firstpat) 74 laste = 0; 75 /* 76 * If dot at last command 77 * ended up at zero, advance to one if there is a such. 78 */ 79 if (dot <= zero) { 80 dot = zero; 81 if (dol > zero) 82 dot = one; 83 } 84 shudclob = 0; 85 86 /* 87 * If autoprint or trailing print flags, 88 * print the line at the specified offset 89 * before the next command. 90 */ 91 if ((pflag || lchng != chng && value(vi_AUTOPRINT) && 92 !inglobal && !inopen && endline) || poffset != 0) { 93 pflag = 0; 94 nochng(); 95 if (dol != zero) { 96 addr1 = addr2 = dot + poffset; 97 poffset = 0; 98 if (addr1 < one || addr1 > dol) 99 error(value(vi_TERSE) ? 100 gettext("Offset out-of-bounds") : 101 gettext("Offset after command " 102 "too large")); 103 dot = addr1; 104 setdot1(); 105 106 goto print; 107 } 108 } 109 nochng(); 110 111 /* 112 * Print prompt if appropriate. 113 * If not in global flush output first to prevent 114 * going into pfast mode unreasonably. 115 */ 116 if (inglobal == 0) { 117 flush(); 118 if (!hush && value(vi_PROMPT) && !globp && 119 !noprompt && endline) { 120 putchar(':'); 121 hadpr = 1; 122 } 123 TSYNC(); 124 } 125 126 /* 127 * Gobble up the address. 128 * Degenerate addresses yield ".". 129 */ 130 addr2 = 0; 131 given = seensemi = 0; 132 do { 133 addr1 = addr2; 134 addr = address(0); 135 c = getcd(); 136 if (addr == 0) { 137 if (c == ',' || c == ';') 138 addr = dot; 139 else if (addr1 != 0) { 140 addr2 = dot; 141 break; 142 } else 143 break; 144 } 145 addr2 = addr; 146 given++; 147 if (c == ';') { 148 c = ','; 149 dot = addr; 150 seensemi = 1; 151 } 152 } while (c == ','); 153 154 if (c == '%') { 155 /* %: same as 1,$ */ 156 addr1 = one; 157 addr2 = dol; 158 given = 2; 159 c = getchar(); 160 } 161 if (addr1 == 0) 162 addr1 = addr2; 163 164 /* 165 * eat multiple colons 166 */ 167 while (c == ':') 168 c = getchar(); 169 /* 170 * Set command name for special character commands. 171 */ 172 tailspec(c); 173 174 /* 175 * If called via : escape from open or visual, limit 176 * the set of available commands here to save work below. 177 */ 178 if (inopen) { 179 if (c == '\n' || c == '\r' || 180 c == CTRL('d') || c == EOF) { 181 if (addr2) 182 dot = addr2; 183 if (c == EOF) 184 return; 185 continue; 186 } 187 if (any(c, "o")) 188 notinvis: 189 tailprim(Command, 1, 1); 190 } 191 switch (c) { 192 193 case 'a': 194 195 switch (peekchar()) { 196 case 'b': 197 /* abbreviate */ 198 tail("abbreviate"); 199 setnoaddr(); 200 mapcmd(0, 1); 201 anyabbrs = 1; 202 continue; 203 case 'r': 204 /* args */ 205 tail("args"); 206 setnoaddr(); 207 eol(); 208 pargs(); 209 continue; 210 } 211 212 /* append */ 213 if (inopen) 214 goto notinvis; 215 tail("append"); 216 setdot(); 217 aiflag = exclam(); 218 donewline(); 219 vmacchng(0); 220 deletenone(); 221 setin(addr2); 222 inappend = 1; 223 (void) append(gettty, addr2); 224 inappend = 0; 225 nochng(); 226 continue; 227 228 case 'c': 229 switch (peekchar()) { 230 231 /* copy */ 232 case 'o': 233 tail("copy"); 234 vmacchng(0); 235 vi_move(); 236 continue; 237 238 /* crypt */ 239 case 'r': 240 tail("crypt"); 241 crflag = -1; 242 ent_crypt: 243 setnoaddr(); 244 xflag = 1; 245 if (permflag) 246 (void) crypt_close(perm); 247 permflag = 1; 248 if ((kflag = run_setkey(perm, 249 (key = vgetpass( 250 gettext("Enter key:"))))) == -1) { 251 xflag = 0; 252 kflag = 0; 253 crflag = 0; 254 smerror(gettext("Encryption facility " 255 "not available\n")); 256 } 257 if (kflag == 0) 258 crflag = 0; 259 continue; 260 261 /* cd */ 262 case 'd': 263 tail("cd"); 264 goto changdir; 265 266 /* chdir */ 267 case 'h': 268 ignchar(); 269 if (peekchar() == 'd') { 270 unsigned char *p; 271 tail2of("chdir"); 272 changdir: 273 if (savedfile[0] == '/' || 274 !value(vi_WARN)) 275 (void) exclam(); 276 else 277 (void) quickly(); 278 if (skipend()) { 279 p = (unsigned char *) 280 getenv("HOME"); 281 if (p == NULL) 282 error(gettext( 283 "Home directory" 284 /*CSTYLED*/ 285 " unknown")); 286 } else 287 getone(), p = file; 288 eol(); 289 if (chdir((char *)p) < 0) 290 filioerr(p); 291 if (savedfile[0] != '/') 292 edited = 0; 293 continue; 294 } 295 if (inopen) 296 tailprim((unsigned char *)"change", 297 2, 1); 298 tail2of("change"); 299 break; 300 301 default: 302 if (inopen) 303 goto notinvis; 304 tail("change"); 305 break; 306 } 307 /* change */ 308 aiflag = exclam(); 309 #ifdef XPG4ONLY 310 setcount2(); 311 donewline(); 312 #else /* XPG6 and Solaris */ 313 setCNL(); 314 #endif /* XPG4ONLY */ 315 vmacchng(0); 316 setin(addr1); 317 (void) delete(0); 318 inappend = 1; 319 if (append(gettty, addr1 - 1) == 0) { 320 #ifdef XPG4 321 /* 322 * P2003.2/D9:5.10.7.2.4, p. 646, 323 * assertion 214(A). If nothing changed, 324 * set dot to the line preceding the lines 325 * to be changed. 326 */ 327 dot = addr1 - 1; 328 #else /* XPG4 */ 329 dot = addr1; 330 #endif /* XPG4 */ 331 if (dot > dol) 332 dot = dol; 333 } 334 inappend = 0; 335 nochng(); 336 continue; 337 338 /* delete */ 339 case 'd': 340 /* 341 * Caution: dp and dl have special meaning already. 342 */ 343 tail("delete"); 344 c = cmdreg(); 345 #ifdef XPG4ONLY 346 setcount2(); 347 donewline(); 348 #else /* XPG6 and Solaris */ 349 setCNL(); 350 #endif /* XPG4ONLY */ 351 vmacchng(0); 352 if (c) 353 (void) YANKreg(c); 354 (void) delete(0); 355 appendnone(); 356 continue; 357 358 /* edit */ 359 /* ex */ 360 case 'e': 361 if (crflag == 2 || crflag == -2) 362 crflag = -1; 363 tail(peekchar() == 'x' ? "ex" : "edit"); 364 editcmd: 365 if (!exclam() && chng) 366 c = 'E'; 367 gotfile = 0; 368 if (c == 'E') { 369 if (inopen && !value(vi_AUTOWRITE)) { 370 filename(c); 371 gotfile = 1; 372 } 373 ungetchar(lastchar()); 374 if (!exclam()) { 375 ckaw(); 376 if (chng && dol > zero) { 377 xchng = 0; 378 error(value(vi_TERSE) ? 379 gettext("No write") : 380 gettext("No write since " 381 "last change (:%s! " 382 "overrides)"), 383 Command); 384 } 385 } 386 387 } 388 if (gotfile == 0) 389 filename(c); 390 setnoaddr(); 391 doecmd: 392 init(); 393 addr2 = zero; 394 laste++; 395 sync(); 396 rop(c); 397 nochng(); 398 continue; 399 400 /* file */ 401 case 'f': 402 tail("file"); 403 setnoaddr(); 404 filename(c); 405 noonl(); 406 /* 407 * synctmp(); 408 */ 409 continue; 410 411 /* global */ 412 case 'g': 413 tail("global"); 414 global(!exclam()); 415 nochng(); 416 continue; 417 418 /* insert */ 419 case 'i': 420 if (inopen) 421 goto notinvis; 422 tail("insert"); 423 setdot(); 424 nonzero(); 425 aiflag = exclam(); 426 donewline(); 427 vmacchng(0); 428 deletenone(); 429 setin(addr2); 430 inappend = 1; 431 (void) append(gettty, addr2 - 1); 432 inappend = 0; 433 if (dot == zero && dol > zero) 434 dot = one; 435 nochng(); 436 continue; 437 438 /* join */ 439 case 'j': 440 tail("join"); 441 c = exclam(); 442 setcount(); 443 nonzero(); 444 donewline(); 445 vmacchng(0); 446 #ifdef XPG4ONLY 447 /* 448 * if no count was specified, addr1 == addr2. if only 449 * 1 range arg was specified, inc addr2 to allow 450 * joining of the next line. 451 */ 452 if (given < 2 && (addr1 == addr2) && (addr2 != dol)) 453 addr2++; 454 455 #else /* XPG6 and Solaris */ 456 if (given < 2 && addr2 != dol) 457 addr2++; 458 #endif /* XPG4ONLY */ 459 (void) join(c); 460 continue; 461 462 /* k */ 463 case 'k': 464 casek: 465 pastwh(); 466 c = getchar(); 467 if (endcmd(c)) 468 serror((vi_TERSE) ? 469 (unsigned char *)gettext("Mark what?") : 470 (unsigned char *) 471 gettext("%s requires following " 472 "letter"), Command); 473 donewline(); 474 if (!islower(c)) 475 error((vi_TERSE) ? gettext("Bad mark") : 476 gettext("Mark must specify a letter")); 477 setdot(); 478 nonzero(); 479 names[c - 'a'] = *addr2 &~ 01; 480 anymarks = 1; 481 continue; 482 483 /* list */ 484 case 'l': 485 tail("list"); 486 #ifdef XPG4ONLY 487 setcount2(); 488 donewline(); 489 #else /* XPG6 and Solaris */ 490 setCNL(); 491 #endif /* XPG4ONLY */ 492 (void) setlist(1); 493 pflag = 0; 494 goto print; 495 496 case 'm': 497 if (peekchar() == 'a') { 498 ignchar(); 499 if (peekchar() == 'p') { 500 /* map */ 501 tail2of("map"); 502 setnoaddr(); 503 mapcmd(0, 0); 504 continue; 505 } 506 /* mark */ 507 tail2of("mark"); 508 goto casek; 509 } 510 /* move */ 511 tail("move"); 512 vmacchng(0); 513 vi_move(); 514 continue; 515 516 case 'n': 517 if (peekchar() == 'u') { 518 tail("number"); 519 goto numberit; 520 } 521 /* next */ 522 tail("next"); 523 setnoaddr(); 524 if (!exclam()) { 525 ckaw(); 526 if (chng && dol > zero) { 527 xchng = 0; 528 error(value(vi_TERSE) ? 529 gettext("No write") : 530 gettext("No write since last " 531 "change (:%s! overrides)"), 532 Command); 533 } 534 } 535 536 if (getargs()) 537 makargs(); 538 next(); 539 c = 'e'; 540 filename(c); 541 goto doecmd; 542 543 /* open */ 544 case 'o': 545 tail("open"); 546 oop(); 547 pflag = 0; 548 nochng(); 549 continue; 550 551 case 'p': 552 case 'P': 553 switch (peekchar()) { 554 #ifdef TAG_STACK 555 /* pop */ 556 case 'o': 557 tail("pop"); 558 poptag(exclam()); 559 if (!inopen) 560 lchng = chng - 1; 561 else 562 nochng(); 563 continue; 564 #endif 565 566 /* put */ 567 case 'u': 568 tail("put"); 569 setdot(); 570 c = cmdreg(); 571 eol(); 572 vmacchng(0); 573 if (c) 574 (void) putreg(c); 575 else 576 (void) put(); 577 continue; 578 579 case 'r': 580 ignchar(); 581 if (peekchar() == 'e') { 582 /* preserve */ 583 tail2of("preserve"); 584 eol(); 585 if (preserve() == 0) 586 error(gettext( 587 "Preserve failed!")); 588 else { 589 #ifdef XPG4 590 /* 591 * error() incs errcnt. this is 592 * misleading here; and a 593 * violation of POSIX. so call 594 * noerror() instead. 595 * this is for assertion ex:222. 596 */ 597 noerror( 598 gettext("File preserved.")); 599 600 #else /* XPG4 */ 601 error( 602 gettext("File preserved.")); 603 #endif /* XPG4 */ 604 } 605 } 606 tail2of("print"); 607 break; 608 609 default: 610 tail("print"); 611 break; 612 } 613 /* print */ 614 setCNL(); 615 pflag = 0; 616 print: 617 nonzero(); 618 if (clear_screen && span() > lines) { 619 flush1(); 620 vclear(); 621 } 622 /* 623 * poffset is nonzero if trailing + or - flags 624 * were given, and in that case we need to 625 * adjust dot before printing a line. 626 */ 627 if (poffset == 0) 628 plines(addr1, addr2, 1); 629 else 630 dot = addr2; 631 continue; 632 633 /* quit */ 634 case 'q': 635 tail("quit"); 636 setnoaddr(); 637 c = quickly(); 638 eol(); 639 if (!c) 640 quit: 641 if (nomore()) 642 continue; 643 if (inopen) { 644 vgoto(WECHO, 0); 645 if (!ateopr()) 646 vnfl(); 647 else { 648 tostop(); 649 } 650 flush(); 651 setty(normf); 652 ixlatctl(1); 653 } 654 cleanup(1); 655 exit(errcnt); 656 657 case 'r': 658 if (peekchar() == 'e') { 659 ignchar(); 660 switch (peekchar()) { 661 662 /* rewind */ 663 case 'w': 664 tail2of("rewind"); 665 setnoaddr(); 666 if (!exclam()) { 667 ckaw(); 668 if (chng && dol > zero) 669 error((vi_TERSE) ? 670 /*CSTYLED*/ 671 gettext("No write") : 672 gettext("No write " 673 "since last " 674 "change (:rewi" 675 /*CSTYLED*/ 676 "nd! overrides)")); 677 } 678 eol(); 679 erewind(); 680 next(); 681 c = 'e'; 682 ungetchar(lastchar()); 683 filename(c); 684 goto doecmd; 685 686 /* recover */ 687 case 'c': 688 tail2of("recover"); 689 setnoaddr(); 690 c = 'e'; 691 if (!exclam() && chng) 692 c = 'E'; 693 filename(c); 694 if (c == 'E') { 695 ungetchar(lastchar()); 696 (void) quickly(); 697 } 698 init(); 699 addr2 = zero; 700 laste++; 701 sync(); 702 recover(); 703 rop2(); 704 revocer(); 705 if (status == 0) 706 rop3(c); 707 if (dol != zero) 708 change(); 709 nochng(); 710 continue; 711 } 712 tail2of("read"); 713 } else 714 tail("read"); 715 /* read */ 716 if (crflag == 2 || crflag == -2) 717 /* restore crflag for new input text */ 718 crflag = -1; 719 if (savedfile[0] == 0 && dol == zero) 720 c = 'e'; 721 pastwh(); 722 vmacchng(0); 723 if (peekchar() == '!') { 724 setdot(); 725 ignchar(); 726 unix0(0, 1); 727 (void) vi_filter(0); 728 continue; 729 } 730 filename(c); 731 rop(c); 732 nochng(); 733 if (inopen && endline && addr1 > zero && addr1 < dol) 734 dot = addr1 + 1; 735 continue; 736 737 case 's': 738 switch (peekchar()) { 739 /* 740 * Caution: 2nd char cannot be c, g, or r 741 * because these have meaning to substitute. 742 */ 743 744 /* set */ 745 case 'e': 746 tail("set"); 747 setnoaddr(); 748 set(); 749 continue; 750 751 /* shell */ 752 case 'h': 753 tail("shell"); 754 setNAEOL(); 755 vnfl(); 756 putpad((unsigned char *)exit_ca_mode); 757 flush(); 758 resetterm(); 759 unixwt(1, unixex("-i", (char *)0, 0, 0)); 760 vcontin(0); 761 continue; 762 763 /* source */ 764 case 'o': 765 #ifdef notdef 766 if (inopen) 767 goto notinvis; 768 #endif 769 tail("source"); 770 setnoaddr(); 771 getone(); 772 eol(); 773 source(file, 0); 774 continue; 775 #ifdef SIGTSTP 776 /* stop, suspend */ 777 case 't': 778 tail("stop"); 779 goto suspend; 780 case 'u': 781 #ifdef XPG4 782 /* 783 * for POSIX, "su" with no other distinguishing 784 * characteristics, maps to "s". Re. P1003.D11, 785 * 5.10.7.3. 786 * 787 * so, unless the "su" is followed by a "s" or 788 * a "!", we assume that the user means "s". 789 */ 790 switch (d = peekchar()) { 791 case 's': 792 case '!': 793 #endif /* XPG4 */ 794 tail("suspend"); 795 suspend: 796 c = exclam(); 797 eol(); 798 if (!c) 799 ckaw(); 800 onsusp(0); 801 continue; 802 #ifdef XPG4 803 } 804 #endif /* XPG4 */ 805 #endif 806 807 } 808 /* fall into ... */ 809 810 /* & */ 811 /* ~ */ 812 /* substitute */ 813 case '&': 814 case '~': 815 Command = (unsigned char *)"substitute"; 816 if (c == 's') 817 tail(Command); 818 vmacchng(0); 819 if (!substitute(c)) 820 pflag = 0; 821 continue; 822 823 /* t */ 824 case 't': 825 if (peekchar() == 'a') { 826 tagflg = 1; /* :tag command */ 827 tail("tag"); 828 tagfind(exclam()); 829 tagflg = 0; 830 if (!inopen) 831 lchng = chng - 1; 832 else 833 nochng(); 834 continue; 835 } 836 tail("t"); 837 vmacchng(0); 838 vi_move(); 839 continue; 840 841 case 'u': 842 if (peekchar() == 'n') { 843 ignchar(); 844 switch (peekchar()) { 845 /* unmap */ 846 case 'm': 847 tail2of("unmap"); 848 setnoaddr(); 849 mapcmd(1, 0); 850 continue; 851 /* unabbreviate */ 852 case 'a': 853 tail2of("unabbreviate"); 854 setnoaddr(); 855 mapcmd(1, 1); 856 anyabbrs = 1; 857 continue; 858 } 859 /* undo */ 860 tail2of("undo"); 861 } else 862 tail("undo"); 863 setnoaddr(); 864 markDOT(); 865 c = exclam(); 866 donewline(); 867 undo(c); 868 continue; 869 870 case 'v': 871 switch (peekchar()) { 872 873 case 'e': 874 /* version */ 875 tail("version"); 876 setNAEOL(); 877 viprintf("%s", Version); 878 noonl(); 879 continue; 880 881 /* visual */ 882 case 'i': 883 tail("visual"); 884 if (inopen) { 885 c = 'e'; 886 goto editcmd; 887 } 888 vop(); 889 pflag = 0; 890 nochng(); 891 continue; 892 } 893 /* v */ 894 tail("v"); 895 global(0); 896 nochng(); 897 continue; 898 899 /* write */ 900 case 'w': 901 c = peekchar(); 902 tail(c == 'q' ? "wq" : "write"); 903 wq: 904 if (skipwh() && peekchar() == '!') { 905 pofix(); 906 ignchar(); 907 setall(); 908 unix0(0, 1); 909 (void) vi_filter(1); 910 } else { 911 setall(); 912 if (c == 'q') 913 write_quit = 1; 914 else 915 write_quit = 0; 916 wop(1); 917 nochng(); 918 } 919 if (c == 'q') 920 goto quit; 921 continue; 922 /* X: crypt */ 923 case 'X': 924 crflag = -1; /* determine if file is encrypted */ 925 goto ent_crypt; 926 927 case 'C': 928 crflag = 1; /* assume files read in are encrypted */ 929 goto ent_crypt; 930 931 /* xit */ 932 case 'x': 933 tail("xit"); 934 if (!chng) 935 goto quit; 936 c = 'q'; 937 goto wq; 938 939 /* yank */ 940 case 'y': 941 tail("yank"); 942 c = cmdreg(); 943 #ifdef XPG4ONLY 944 setcount2(); 945 #else /* XPG6 and Solaris */ 946 setcount(); 947 #endif /* XPG4ONLY */ 948 eol(); 949 vmacchng(0); 950 if (c) 951 (void) YANKreg(c); 952 else 953 (void) yank(); 954 continue; 955 956 /* z */ 957 case 'z': 958 zop(0); 959 pflag = 0; 960 continue; 961 962 /* * */ 963 /* @ */ 964 case '*': 965 case '@': 966 c = getchar(); 967 if (c == '\n' || c == '\r') 968 ungetchar(c); 969 if (any(c, "@*\n\r")) 970 c = lastmac; 971 if (isupper(c)) 972 c = tolower(c); 973 if (!islower(c)) 974 error(gettext("Bad register")); 975 donewline(); 976 setdot(); 977 cmdmac(c); 978 continue; 979 980 /* | */ 981 case '|': 982 endline = 0; 983 goto caseline; 984 985 /* \n */ 986 case '\n': 987 endline = 1; 988 caseline: 989 notempty(); 990 if (addr2 == 0) { 991 if (cursor_up != NOSTR && c == '\n' && 992 !inglobal) 993 c = CTRL('k'); 994 if (inglobal) 995 addr1 = addr2 = dot; 996 else { 997 if (dot == dol) 998 error((vi_TERSE) ? 999 gettext("At EOF") : 1000 gettext("At end-of-file")); 1001 addr1 = addr2 = dot + 1; 1002 } 1003 } 1004 setdot(); 1005 nonzero(); 1006 if (seensemi) 1007 addr1 = addr2; 1008 getline(*addr1); 1009 if (c == CTRL('k')) { 1010 flush1(); 1011 destline--; 1012 if (hadpr) 1013 shudclob = 1; 1014 } 1015 plines(addr1, addr2, 1); 1016 continue; 1017 1018 /* " */ 1019 case '"': 1020 comment(); 1021 continue; 1022 1023 /* # */ 1024 case '#': 1025 numberit: 1026 setCNL(); 1027 (void) setnumb(1); 1028 pflag = 0; 1029 goto print; 1030 1031 /* = */ 1032 case '=': 1033 donewline(); 1034 setall(); 1035 if (inglobal == 2) 1036 pofix(); 1037 viprintf("%d", lineno(addr2)); 1038 noonl(); 1039 continue; 1040 1041 /* ! */ 1042 case '!': 1043 if (addr2 != 0) { 1044 vmacchng(0); 1045 unix0(0, 1); 1046 setdot(); 1047 (void) vi_filter(2); 1048 } else { 1049 unix0(1, 1); 1050 pofix(); 1051 putpad((unsigned char *)exit_ca_mode); 1052 flush(); 1053 resetterm(); 1054 if (!tagflg) { 1055 unixwt(1, unixex("-c", uxb, 0, 0)); 1056 } else { 1057 error(gettext("Invalid tags file:" 1058 " contains shell escape")); 1059 } 1060 vclrech(1); /* vcontin(0); */ 1061 nochng(); 1062 } 1063 continue; 1064 1065 /* < */ 1066 /* > */ 1067 case '<': 1068 case '>': 1069 for (cnt = 1; peekchar() == c; cnt++) 1070 ignchar(); 1071 setCNL(); 1072 vmacchng(0); 1073 shift(c, cnt); 1074 continue; 1075 1076 /* ^D */ 1077 /* EOF */ 1078 case CTRL('d'): 1079 case EOF: 1080 if (exitoneof) { 1081 if (addr2 != 0) 1082 dot = addr2; 1083 return; 1084 } 1085 if (!isatty(0)) { 1086 if (intty) 1087 /* 1088 * Chtty sys call at UCB may cause a 1089 * input which was a tty to suddenly be 1090 * turned into /dev/null. 1091 */ 1092 onhup(0); 1093 return; 1094 } 1095 if (addr2 != 0) { 1096 setlastchar('\n'); 1097 putnl(); 1098 } 1099 if (dol == zero) { 1100 if (addr2 == 0) 1101 putnl(); 1102 notempty(); 1103 } 1104 ungetchar(EOF); 1105 zop(hadpr); 1106 continue; 1107 default: 1108 if (!isalpha(c) || !isascii(c)) 1109 break; 1110 ungetchar(c); 1111 tailprim((unsigned char *)"", 0, 0); 1112 } 1113 ungetchar(c); 1114 { 1115 int length; 1116 char multic[MULTI_BYTE_MAX]; 1117 wchar_t wchar; 1118 length = _mbftowc(multic, &wchar, getchar, &peekc); 1119 if (length < 0) 1120 length = -length; 1121 multic[length] = '\0'; 1122 error((vi_TERSE) ? gettext("What?") : 1123 gettext("Unknown command character '%s'"), 1124 multic); 1125 } 1126 } 1127 } 1128