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
commands(noprompt,exitoneof)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 /* fall into ... */
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