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