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 extern int getchar(void);
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
commands(noprompt,exitoneof)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 /* FALLTHROUGH */
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 getaline(*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