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