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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* Copyright (c) 1981 Regents of the University of California */ 27 28 /* 29 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 30 * Use is subject to license terms. 31 */ 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 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 register 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(p) < 0) 290 filioerr(p); 291 if (savedfile[0] != '/') 292 edited = 0; 293 continue; 294 } 295 if (inopen) 296 tailprim("change", 2, 1); 297 tail2of("change"); 298 break; 299 300 default: 301 if (inopen) 302 goto notinvis; 303 tail("change"); 304 break; 305 } 306 /* change */ 307 aiflag = exclam(); 308 #ifdef XPG4ONLY 309 setcount2(); 310 donewline(); 311 #else /* XPG6 and Solaris */ 312 setCNL(); 313 #endif /* XPG4ONLY */ 314 vmacchng(0); 315 setin(addr1); 316 delete(0); 317 inappend = 1; 318 if (append(gettty, addr1 - 1) == 0) { 319 #ifdef XPG4 320 /* 321 * P2003.2/D9:5.10.7.2.4, p. 646, 322 * assertion 214(A). If nothing changed, 323 * set dot to the line preceding the lines 324 * to be changed. 325 */ 326 dot = addr1 - 1; 327 #else /* XPG4 */ 328 dot = addr1; 329 #endif /* XPG4 */ 330 if (dot > dol) 331 dot = dol; 332 } 333 inappend = 0; 334 nochng(); 335 continue; 336 337 /* delete */ 338 case 'd': 339 /* 340 * Caution: dp and dl have special meaning already. 341 */ 342 tail("delete"); 343 c = cmdreg(); 344 #ifdef XPG4ONLY 345 setcount2(); 346 donewline(); 347 #else /* XPG6 and Solaris */ 348 setCNL(); 349 #endif /* XPG4ONLY */ 350 vmacchng(0); 351 if (c) 352 YANKreg(c); 353 delete(0); 354 appendnone(); 355 continue; 356 357 /* edit */ 358 /* ex */ 359 case 'e': 360 if (crflag == 2 || crflag == -2) 361 crflag = -1; 362 tail(peekchar() == 'x' ? "ex" : "edit"); 363 editcmd: 364 if (!exclam() && chng) 365 c = 'E'; 366 gotfile = 0; 367 if (c == 'E') { 368 if (inopen && !value(vi_AUTOWRITE)) { 369 filename(c); 370 gotfile = 1; 371 } 372 ungetchar(lastchar()); 373 if (!exclam()) { 374 ckaw(); 375 if (chng && dol > zero) { 376 xchng = 0; 377 error(value(vi_TERSE) ? 378 gettext("No write") : 379 gettext("No write since " 380 "last change (:%s! " 381 "overrides)"), 382 Command); 383 } 384 } 385 386 } 387 if (gotfile == 0) 388 filename(c); 389 setnoaddr(); 390 doecmd: 391 init(); 392 addr2 = zero; 393 laste++; 394 sync(); 395 rop(c); 396 nochng(); 397 continue; 398 399 /* file */ 400 case 'f': 401 tail("file"); 402 setnoaddr(); 403 filename(c); 404 noonl(); 405 /* 406 * synctmp(); 407 */ 408 continue; 409 410 /* global */ 411 case 'g': 412 tail("global"); 413 global(!exclam()); 414 nochng(); 415 continue; 416 417 /* insert */ 418 case 'i': 419 if (inopen) 420 goto notinvis; 421 tail("insert"); 422 setdot(); 423 nonzero(); 424 aiflag = exclam(); 425 donewline(); 426 vmacchng(0); 427 deletenone(); 428 setin(addr2); 429 inappend = 1; 430 (void) append(gettty, addr2 - 1); 431 inappend = 0; 432 if (dot == zero && dol > zero) 433 dot = one; 434 nochng(); 435 continue; 436 437 /* join */ 438 case 'j': 439 tail("join"); 440 c = exclam(); 441 setcount(); 442 nonzero(); 443 donewline(); 444 vmacchng(0); 445 #ifdef XPG4ONLY 446 /* 447 * if no count was specified, addr1 == addr2. if only 448 * 1 range arg was specified, inc addr2 to allow 449 * joining of the next line. 450 */ 451 if (given < 2 && (addr1 == addr2) && (addr2 != dol)) 452 addr2++; 453 454 #else /* XPG6 and Solaris */ 455 if (given < 2 && addr2 != dol) 456 addr2++; 457 #endif /* XPG4ONLY */ 458 join(c); 459 continue; 460 461 /* k */ 462 case 'k': 463 casek: 464 pastwh(); 465 c = getchar(); 466 if (endcmd(c)) 467 serror((vi_TERSE) ? gettext("Mark what?") : 468 gettext("%s requires following " 469 "letter"), Command); 470 donewline(); 471 if (!islower(c)) 472 error((vi_TERSE) ? gettext("Bad mark") : 473 gettext("Mark must specify a letter")); 474 setdot(); 475 nonzero(); 476 names[c - 'a'] = *addr2 &~ 01; 477 anymarks = 1; 478 continue; 479 480 /* list */ 481 case 'l': 482 tail("list"); 483 #ifdef XPG4ONLY 484 setcount2(); 485 donewline(); 486 #else /* XPG6 and Solaris */ 487 setCNL(); 488 #endif /* XPG4ONLY */ 489 (void) setlist(1); 490 pflag = 0; 491 goto print; 492 493 case 'm': 494 if (peekchar() == 'a') { 495 ignchar(); 496 if (peekchar() == 'p') { 497 /* map */ 498 tail2of("map"); 499 setnoaddr(); 500 mapcmd(0, 0); 501 continue; 502 } 503 /* mark */ 504 tail2of("mark"); 505 goto casek; 506 } 507 /* move */ 508 tail("move"); 509 vmacchng(0); 510 vi_move(); 511 continue; 512 513 case 'n': 514 if (peekchar() == 'u') { 515 tail("number"); 516 goto numberit; 517 } 518 /* next */ 519 tail("next"); 520 setnoaddr(); 521 if (!exclam()) { 522 ckaw(); 523 if (chng && dol > zero) { 524 xchng = 0; 525 error(value(vi_TERSE) ? 526 gettext("No write") : 527 gettext("No write since last " 528 "change (:%s! overrides)"), 529 Command); 530 } 531 } 532 533 if (getargs()) 534 makargs(); 535 next(); 536 c = 'e'; 537 filename(c); 538 goto doecmd; 539 540 /* open */ 541 case 'o': 542 tail("open"); 543 oop(); 544 pflag = 0; 545 nochng(); 546 continue; 547 548 case 'p': 549 case 'P': 550 switch (peekchar()) { 551 #ifdef TAG_STACK 552 /* pop */ 553 case 'o': 554 tail("pop"); 555 poptag(exclam()); 556 if (!inopen) 557 lchng = chng - 1; 558 else 559 nochng(); 560 continue; 561 #endif 562 563 /* put */ 564 case 'u': 565 tail("put"); 566 setdot(); 567 c = cmdreg(); 568 eol(); 569 vmacchng(0); 570 if (c) 571 putreg(c); 572 else 573 put(); 574 continue; 575 576 case 'r': 577 ignchar(); 578 if (peekchar() == 'e') { 579 /* preserve */ 580 tail2of("preserve"); 581 eol(); 582 if (preserve() == 0) 583 error(gettext( 584 "Preserve failed!")); 585 else { 586 #ifdef XPG4 587 /* 588 * error() incs errcnt. this is 589 * misleading here; and a 590 * violation of POSIX. so call 591 * noerror() instead. 592 * this is for assertion ex:222. 593 */ 594 noerror( 595 gettext("File preserved.")); 596 597 #else /* XPG4 */ 598 error( 599 gettext("File preserved.")); 600 #endif /* XPG4 */ 601 } 602 } 603 tail2of("print"); 604 break; 605 606 default: 607 tail("print"); 608 break; 609 } 610 /* print */ 611 setCNL(); 612 pflag = 0; 613 print: 614 nonzero(); 615 if (clear_screen && span() > lines) { 616 flush1(); 617 vclear(); 618 } 619 /* 620 * poffset is nonzero if trailing + or - flags 621 * were given, and in that case we need to 622 * adjust dot before printing a line. 623 */ 624 if (poffset == 0) 625 plines(addr1, addr2, 1); 626 else 627 dot = addr2; 628 continue; 629 630 /* quit */ 631 case 'q': 632 tail("quit"); 633 setnoaddr(); 634 c = quickly(); 635 eol(); 636 if (!c) 637 quit: 638 if (nomore()) 639 continue; 640 if (inopen) { 641 vgoto(WECHO, 0); 642 if (!ateopr()) 643 vnfl(); 644 else { 645 tostop(); 646 } 647 flush(); 648 setty(normf); 649 ixlatctl(1); 650 } 651 cleanup(1); 652 exit(errcnt); 653 654 case 'r': 655 if (peekchar() == 'e') { 656 ignchar(); 657 switch (peekchar()) { 658 659 /* rewind */ 660 case 'w': 661 tail2of("rewind"); 662 setnoaddr(); 663 if (!exclam()) { 664 ckaw(); 665 if (chng && dol > zero) 666 error((vi_TERSE) ? 667 /*CSTYLED*/ 668 gettext("No write") : 669 gettext("No write " 670 "since last " 671 "change (:rewi" 672 /*CSTYLED*/ 673 "nd! overrides)")); 674 } 675 eol(); 676 erewind(); 677 next(); 678 c = 'e'; 679 ungetchar(lastchar()); 680 filename(c); 681 goto doecmd; 682 683 /* recover */ 684 case 'c': 685 tail2of("recover"); 686 setnoaddr(); 687 c = 'e'; 688 if (!exclam() && chng) 689 c = 'E'; 690 filename(c); 691 if (c == 'E') { 692 ungetchar(lastchar()); 693 (void) quickly(); 694 } 695 init(); 696 addr2 = zero; 697 laste++; 698 sync(); 699 recover(); 700 rop2(); 701 revocer(); 702 if (status == 0) 703 rop3(c); 704 if (dol != zero) 705 change(); 706 nochng(); 707 continue; 708 } 709 tail2of("read"); 710 } else 711 tail("read"); 712 /* read */ 713 if (crflag == 2 || crflag == -2) 714 /* restore crflag for new input text */ 715 crflag = -1; 716 if (savedfile[0] == 0 && dol == zero) 717 c = 'e'; 718 pastwh(); 719 vmacchng(0); 720 if (peekchar() == '!') { 721 setdot(); 722 ignchar(); 723 unix0(0); 724 vi_filter(0); 725 continue; 726 } 727 filename(c); 728 rop(c); 729 nochng(); 730 if (inopen && endline && addr1 > zero && addr1 < dol) 731 dot = addr1 + 1; 732 continue; 733 734 case 's': 735 switch (peekchar()) { 736 /* 737 * Caution: 2nd char cannot be c, g, or r 738 * because these have meaning to substitute. 739 */ 740 741 /* set */ 742 case 'e': 743 tail("set"); 744 setnoaddr(); 745 set(); 746 continue; 747 748 /* shell */ 749 case 'h': 750 tail("shell"); 751 setNAEOL(); 752 vnfl(); 753 putpad(exit_ca_mode); 754 flush(); 755 resetterm(); 756 unixwt(1, unixex("-i", (char *)0, 0, 0)); 757 vcontin(0); 758 continue; 759 760 /* source */ 761 case 'o': 762 #ifdef notdef 763 if (inopen) 764 goto notinvis; 765 #endif 766 tail("source"); 767 setnoaddr(); 768 getone(); 769 eol(); 770 source(file, 0); 771 continue; 772 #ifdef SIGTSTP 773 /* stop, suspend */ 774 case 't': 775 tail("stop"); 776 goto suspend; 777 case 'u': 778 #ifdef XPG4 779 /* 780 * for POSIX, "su" with no other distinguishing 781 * characteristics, maps to "s". Re. P1003.D11, 782 * 5.10.7.3. 783 * 784 * so, unless the "su" is followed by a "s" or 785 * a "!", we assume that the user means "s". 786 */ 787 switch (d = peekchar()) { 788 case 's': 789 case '!': 790 #endif /* XPG4 */ 791 tail("suspend"); 792 suspend: 793 c = exclam(); 794 eol(); 795 if (!c) 796 ckaw(); 797 onsusp(0); 798 continue; 799 #ifdef XPG4 800 } 801 #endif /* XPG4 */ 802 #endif 803 804 } 805 /* fall into ... */ 806 807 /* & */ 808 /* ~ */ 809 /* substitute */ 810 case '&': 811 case '~': 812 Command = (unsigned char *)"substitute"; 813 if (c == 's') 814 tail(Command); 815 vmacchng(0); 816 if (!substitute(c)) 817 pflag = 0; 818 continue; 819 820 /* t */ 821 case 't': 822 if (peekchar() == 'a') { 823 tail("tag"); 824 tagfind(exclam()); 825 if (!inopen) 826 lchng = chng - 1; 827 else 828 nochng(); 829 continue; 830 } 831 tail("t"); 832 vmacchng(0); 833 vi_move(); 834 continue; 835 836 case 'u': 837 if (peekchar() == 'n') { 838 ignchar(); 839 switch (peekchar()) { 840 /* unmap */ 841 case 'm': 842 tail2of("unmap"); 843 setnoaddr(); 844 mapcmd(1, 0); 845 continue; 846 /* unabbreviate */ 847 case 'a': 848 tail2of("unabbreviate"); 849 setnoaddr(); 850 mapcmd(1, 1); 851 anyabbrs = 1; 852 continue; 853 } 854 /* undo */ 855 tail2of("undo"); 856 } else 857 tail("undo"); 858 setnoaddr(); 859 markDOT(); 860 c = exclam(); 861 donewline(); 862 undo(c); 863 continue; 864 865 case 'v': 866 switch (peekchar()) { 867 868 case 'e': 869 /* version */ 870 tail("version"); 871 setNAEOL(); 872 printf("%s", Version); 873 noonl(); 874 continue; 875 876 /* visual */ 877 case 'i': 878 tail("visual"); 879 if (inopen) { 880 c = 'e'; 881 goto editcmd; 882 } 883 vop(); 884 pflag = 0; 885 nochng(); 886 continue; 887 } 888 /* v */ 889 tail("v"); 890 global(0); 891 nochng(); 892 continue; 893 894 /* write */ 895 case 'w': 896 c = peekchar(); 897 tail(c == 'q' ? "wq" : "write"); 898 wq: 899 if (skipwh() && peekchar() == '!') { 900 pofix(); 901 ignchar(); 902 setall(); 903 unix0(0); 904 vi_filter(1); 905 } else { 906 setall(); 907 if (c == 'q') 908 write_quit = 1; 909 else 910 write_quit = 0; 911 wop(1); 912 nochng(); 913 } 914 if (c == 'q') 915 goto quit; 916 continue; 917 /* X: crypt */ 918 case 'X': 919 crflag = -1; /* determine if file is encrypted */ 920 goto ent_crypt; 921 922 case 'C': 923 crflag = 1; /* assume files read in are encrypted */ 924 goto ent_crypt; 925 926 /* xit */ 927 case 'x': 928 tail("xit"); 929 if (!chng) 930 goto quit; 931 c = 'q'; 932 goto wq; 933 934 /* yank */ 935 case 'y': 936 tail("yank"); 937 c = cmdreg(); 938 #ifdef XPG4ONLY 939 setcount2(); 940 #else /* XPG6 and Solaris */ 941 setcount(); 942 #endif /* XPG4ONLY */ 943 eol(); 944 vmacchng(0); 945 if (c) 946 YANKreg(c); 947 else 948 yank(); 949 continue; 950 951 /* z */ 952 case 'z': 953 zop(0); 954 pflag = 0; 955 continue; 956 957 /* * */ 958 /* @ */ 959 case '*': 960 case '@': 961 c = getchar(); 962 if (c == '\n' || c == '\r') 963 ungetchar(c); 964 if (any(c, "@*\n\r")) 965 c = lastmac; 966 if (isupper(c)) 967 c = tolower(c); 968 if (!islower(c)) 969 error(gettext("Bad register")); 970 donewline(); 971 setdot(); 972 cmdmac(c); 973 continue; 974 975 /* | */ 976 case '|': 977 endline = 0; 978 goto caseline; 979 980 /* \n */ 981 case '\n': 982 endline = 1; 983 caseline: 984 notempty(); 985 if (addr2 == 0) { 986 if (cursor_up != NOSTR && c == '\n' && 987 !inglobal) 988 c = CTRL('k'); 989 if (inglobal) 990 addr1 = addr2 = dot; 991 else { 992 if (dot == dol) 993 error((vi_TERSE) ? 994 gettext("At EOF") : 995 gettext("At end-of-file")); 996 addr1 = addr2 = dot + 1; 997 } 998 } 999 setdot(); 1000 nonzero(); 1001 if (seensemi) 1002 addr1 = addr2; 1003 getline(*addr1); 1004 if (c == CTRL('k')) { 1005 flush1(); 1006 destline--; 1007 if (hadpr) 1008 shudclob = 1; 1009 } 1010 plines(addr1, addr2, 1); 1011 continue; 1012 1013 /* " */ 1014 case '"': 1015 comment(); 1016 continue; 1017 1018 /* # */ 1019 case '#': 1020 numberit: 1021 setCNL(); 1022 (void) setnumb(1); 1023 pflag = 0; 1024 goto print; 1025 1026 /* = */ 1027 case '=': 1028 donewline(); 1029 setall(); 1030 if (inglobal == 2) 1031 pofix(); 1032 printf("%d", lineno(addr2)); 1033 noonl(); 1034 continue; 1035 1036 /* ! */ 1037 case '!': 1038 if (addr2 != 0) { 1039 vmacchng(0); 1040 unix0(0); 1041 setdot(); 1042 vi_filter(2); 1043 } else { 1044 unix0(1); 1045 pofix(); 1046 putpad(exit_ca_mode); 1047 flush(); 1048 resetterm(); 1049 unixwt(1, unixex("-c", uxb, 0, 0)); 1050 vclrech(1); /* vcontin(0); */ 1051 nochng(); 1052 } 1053 continue; 1054 1055 /* < */ 1056 /* > */ 1057 case '<': 1058 case '>': 1059 for (cnt = 1; peekchar() == c; cnt++) 1060 ignchar(); 1061 setCNL(); 1062 vmacchng(0); 1063 shift(c, cnt); 1064 continue; 1065 1066 /* ^D */ 1067 /* EOF */ 1068 case CTRL('d'): 1069 case EOF: 1070 if (exitoneof) { 1071 if (addr2 != 0) 1072 dot = addr2; 1073 return; 1074 } 1075 if (!isatty(0)) { 1076 if (intty) 1077 /* 1078 * Chtty sys call at UCB may cause a 1079 * input which was a tty to suddenly be 1080 * turned into /dev/null. 1081 */ 1082 onhup(0); 1083 return; 1084 } 1085 if (addr2 != 0) { 1086 setlastchar('\n'); 1087 putnl(); 1088 } 1089 if (dol == zero) { 1090 if (addr2 == 0) 1091 putnl(); 1092 notempty(); 1093 } 1094 ungetchar(EOF); 1095 zop(hadpr); 1096 continue; 1097 default: 1098 if (!isalpha(c) || !isascii(c)) 1099 break; 1100 ungetchar(c); 1101 tailprim("", 0, 0); 1102 } 1103 ungetchar(c); 1104 { 1105 int length; 1106 char multic[MULTI_BYTE_MAX]; 1107 wchar_t wchar; 1108 length = _mbftowc(multic, &wchar, getchar, &peekc); 1109 if (length < 0) 1110 length = -length; 1111 multic[length] = '\0'; 1112 error((vi_TERSE) ? gettext("What?") : 1113 gettext("Unknown command character '%s'"), 1114 multic); 1115 } 1116 } 1117 } 1118