xref: /illumos-gate/usr/src/cmd/vi/port/ex_subr.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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 <sys/stropts.h>
33 #include <sys/eucioctl.h>
34 #ifndef PRESUNEUC
35 #include <locale.h>
36 /* Undef putchar/getchar if they're defined. */
37 #ifdef putchar
38 #	undef putchar
39 #endif
40 #ifdef getchar
41 #	undef getchar
42 #endif
43 #endif /* PRESUNEUC */
44 
45 #include "ex.h"
46 #include "ex_re.h"
47 #include "ex_tty.h"
48 #include "ex_vis.h"
49 
50 /*
51  * Random routines, in alphabetical order.
52  */
53 
54 int
55 any(int c, unsigned char *s)
56 {
57 	int x;
58 
59 	while (x = *s++)
60 		if (x == c)
61 			return (1);
62 	return (0);
63 }
64 
65 int
66 backtab(int i)
67 {
68 	int j;
69 
70 	j = i % value(vi_SHIFTWIDTH);
71 	if (j == 0)
72 		j = value(vi_SHIFTWIDTH);
73 	i -= j;
74 	if (i < 0)
75 		i = 0;
76 	return (i);
77 }
78 
79 void
80 change(void)
81 {
82 
83 	tchng++;
84 	chng = tchng;
85 }
86 
87 /*
88  * Column returns the number of
89  * columns occupied by printing the
90  * characters through position cp of the
91  * current line.
92  */
93 int
94 column(unsigned char *cp)
95 {
96 
97 	if (cp == 0)
98 		cp = &linebuf[LBSIZE - 2];
99 	return (qcolumn(cp, (unsigned char *)0));
100 }
101 
102 /* lcolumn is same as column except it returns number of columns
103  * occupied by characters before position
104  * cp of the current line
105  */
106 int
107 lcolumn(unsigned char *cp)
108 {
109 
110 	if (cp == 0)
111 		cp = &linebuf[LBSIZE - 2];
112 	return (nqcolumn(lastchr(linebuf, cp), (unsigned char *)0));
113 }
114 
115 /*
116  * Ignore a comment to the end of the line.
117  * This routine eats the trailing newline so don't call donewline().
118  */
119 void
120 comment(void)
121 {
122 	int c;
123 
124 	do {
125 		c = getchar();
126 	} while (c != '\n' && c != EOF);
127 	if (c == EOF)
128 		ungetchar(c);
129 }
130 
131 void
132 Copy(unsigned char *to, unsigned char *from, int size)
133 {
134 
135 	if (size > 0)
136 		do
137 			*to++ = *from++;
138 		while (--size > 0);
139 }
140 
141 void
142 copyw(line *to, line *from, int size)
143 {
144 
145 	if (size > 0)
146 		do
147 			*to++ = *from++;
148 		while (--size > 0);
149 }
150 
151 void
152 copywR(line *to, line *from, int size)
153 {
154 
155 	while (--size >= 0)
156 		to[size] = from[size];
157 }
158 
159 int
160 ctlof(int c)
161 {
162 
163 	return (c == DELETE ? '?' : c | ('A' - 1));
164 }
165 
166 void
167 dingdong(void)
168 {
169 
170 	if (flash_screen && value(vi_FLASH))
171 		putpad((unsigned char *)flash_screen);
172 	else if (value(vi_ERRORBELLS))
173 		putpad((unsigned char *)bell);
174 }
175 
176 int
177 fixindent(int indent)
178 {
179 	int i;
180 	unsigned char *cp;
181 
182 	i = whitecnt(genbuf);
183 	cp = vpastwh(genbuf);
184 	if (*cp == 0 && i == indent && linebuf[0] == 0) {
185 		genbuf[0] = 0;
186 		return (i);
187 	}
188 	CP(genindent(i), cp);
189 	return (i);
190 }
191 
192 void
193 filioerr(unsigned char *cp)
194 {
195 	int oerrno = errno;
196 
197 	lprintf("\"%s\"", cp);
198 	errno = oerrno;
199 	syserror(1);
200 }
201 
202 unsigned char *
203 genindent(indent)
204 	int indent;
205 {
206 	unsigned char *cp;
207 
208 	for (cp = genbuf; indent >= value(vi_TABSTOP); indent -= value(vi_TABSTOP))
209 		*cp++ = '\t';
210 	for (; indent > 0; indent--)
211 		*cp++ = ' ';
212 	return (cp);
213 }
214 
215 void
216 getDOT(void)
217 {
218 
219 	getaline(*dot);
220 }
221 
222 line *
223 getmark(c)
224 	int c;
225 {
226 	line *addr;
227 
228 	for (addr = one; addr <= dol; addr++)
229 		if (names[c - 'a'] == (*addr &~ 01)) {
230 			return (addr);
231 		}
232 	return (0);
233 }
234 
235 void
236 ignnEOF(void)
237 {
238 	int c = getchar();
239 
240 	if (c == EOF)
241 		ungetchar(c);
242 	else if (c=='"')
243 		comment();
244 }
245 
246 int
247 iswhite(int c)
248 {
249 
250 	return (c == ' ' || c == '\t');
251 }
252 
253 int
254 junk(wchar_t c)
255 {
256 
257 	if (c && !value(vi_BEAUTIFY))
258 		return (0);
259 	if (c >= ' ' && c != DELETE)
260 		return (0);
261 	switch (c) {
262 
263 	case '\t':
264 	case '\n':
265 	case '\f':
266 		return (0);
267 
268 	default:
269 		return (1);
270 	}
271 }
272 
273 void
274 killed(void)
275 {
276 
277 	killcnt(addr2 - addr1 + 1);
278 }
279 
280 void
281 killcnt(int cnt)
282 {
283 	extern char *verbalize();
284 
285 	if (inopen) {
286 		notecnt = cnt;
287 		notenam = notesgn = (unsigned char *)"";
288 		return;
289 	}
290 	if (!notable(cnt))
291 		return;
292 	if (value(vi_TERSE) == 0) {
293 		verbalize(cnt, Command, "");
294 	} else {
295 		if (cnt == 1) {
296 			viprintf(gettext("1 line"), cnt);
297 		} else {
298 			viprintf(gettext("%d lines"), cnt);
299 		}
300 	}
301 	putNFL();
302 }
303 
304 int
305 lineno(line *a)
306 {
307 
308 	return (a - zero);
309 }
310 
311 int
312 lineDOL(void)
313 {
314 
315 	return (lineno(dol));
316 }
317 
318 int
319 lineDOT(void)
320 {
321 
322 	return (lineno(dot));
323 }
324 
325 void
326 markDOT(void)
327 {
328 
329 	markpr(dot);
330 }
331 
332 void
333 markpr(line *which)
334 {
335 
336 	if ((inglobal == 0 || inopen) && which <= endcore) {
337 		names['z'-'a'+1] = *which & ~01;
338 		if (inopen)
339 			ncols['z'-'a'+1] = cursor;
340 	}
341 }
342 
343 int
344 markreg(int c)
345 {
346 
347 	if (c == '\'' || c == '`')
348 		return ('z' + 1);
349 	if (c >= 'a' && c <= 'z')
350 		return (c);
351 	return (0);
352 }
353 
354 /*
355  * Mesg decodes the terse/verbose strings. Thus
356  *	'xxx@yyy' -> 'xxx' if terse, else 'xxx yyy'
357  *	'xxx|yyy' -> 'xxx' if terse, else 'yyy'
358  * All others map to themselves.
359  */
360 /*
361  * The feature described above was disabled for localizable messaging.
362  */
363 unsigned char *
364 mesg(str)
365 	unsigned char *str;
366 {
367 	unsigned char *cp;
368 
369 	str = (unsigned char *)strcpy(genbuf, str);
370 	/* commented out for localizable messaging */
371 /*	for (cp = str; *cp; cp++)
372 		switch (*cp) {
373 
374 		case '@':
375 			if (value(vi_TERSE))
376 				*cp = 0;
377 			else
378 				*cp = ' ';
379 			break;
380 
381 		case '|':
382 			if (value(vi_TERSE) == 0)
383 				return (cp + 1);
384 			*cp = 0;
385 			break;
386 		}	*/
387 	return (str);
388 }
389 
390 /*VARARGS2*/
391 void
392 merror(unsigned char *seekpt, int i)
393 {
394 	unsigned char *cp = linebuf;
395 
396 	if (seekpt == 0)
397 		return;
398 	merror1(seekpt);
399 	if (*cp == '\n')
400 		putnl(), cp++;
401 	if (inopen > 0 && clr_eol)
402 		vclreol();
403 	if (enter_standout_mode && exit_bold)
404 		putpad((unsigned char *)enter_standout_mode);
405 #ifdef PRESUNEUC
406 	viprintf(mesg(cp), i);
407 #else
408 	viprintf((char *)mesg(cp), i);
409 #endif /* PRESUNEUC */
410 	if (enter_standout_mode && exit_bold)
411 		putpad((unsigned char *)exit_bold);
412 }
413 
414 void
415 merror1(unsigned char *seekpt)
416 {
417 
418 	strcpy(linebuf, seekpt);
419 }
420 
421 #define MAXDATA (56*1024)
422 int
423 morelines(void)
424 {
425 	unsigned char *end;
426 
427 	if ((int) sbrk(1024 * sizeof (line)) == -1) {
428 		if (endcore >= (line *) MAXDATA)
429 			return -1;
430 		end = (unsigned char *) MAXDATA;
431 		/*
432 		 * Ask for end+2 sice we want end to be the last used location.
433 		 */
434 		while (brk(end+2) == -1)
435 			end -= 64;
436 		if (end <= (unsigned char *) endcore)
437 			return -1;
438 		endcore = (line *) end;
439 	} else {
440 		endcore += 1024;
441 	}
442 	return (0);
443 }
444 
445 void
446 nonzero(void)
447 {
448 
449 	if (addr1 == zero) {
450 		notempty();
451 		error(value(vi_TERSE) ? gettext("Nonzero address required") :
452 gettext("Nonzero address required on this command"));
453 	}
454 }
455 
456 int
457 notable(int i)
458 {
459 
460 	return (hush == 0 && !inglobal && i > value(vi_REPORT));
461 }
462 
463 
464 void
465 notempty(void)
466 {
467 
468 	if (dol == zero)
469 		error(value(vi_TERSE) ? gettext("No lines") :
470 gettext("No lines in the buffer"));
471 }
472 
473 
474 void
475 netchHAD(int cnt)
476 {
477 
478 	netchange(lineDOL() - cnt);
479 }
480 
481 void
482 netchange(int i)
483 {
484 	unsigned char *cp;
485 
486 	if (i > 0)
487 		notesgn = cp = (unsigned char *)"more ";
488 	else
489 		notesgn = cp = (unsigned char *)"fewer ", i = -i;
490 	if (inopen) {
491 		notecnt = i;
492 		notenam = (unsigned char *)"";
493 		return;
494 	}
495 	if (!notable(i))
496 		return;
497 	if (*cp == 'm')	/* for ease of messge localization */
498 #ifdef PRESUNEUC
499 		viprintf(mesg(value(vi_TERSE) ?
500 #else
501 		viprintf((char *)mesg(value(vi_TERSE) ?
502 #endif /* PRESUNEUC */
503 gettext("%d more lines") :
504 		/*
505 		 * TRANSLATION_NOTE
506 		 *	Reference order of arguments must not
507 		 *	be changed using '%digit$', since vi's
508 		 *	viprintf() does not support it.
509 		 */
510 gettext("%d more lines in file after %s")), i, Command);
511 	else
512 #ifdef PRESUNEUC
513 		viprintf(mesg(value(vi_TERSE) ?
514 #else
515 		viprintf((char *)mesg(value(vi_TERSE) ?
516 #endif /* PRESUNEUC */
517 gettext("%d fewer lines") :
518 		/*
519 		 * TRANSLATION_NOTE
520 		 *	Reference order of arguments must not
521 		 *	be changed using '%digit$', since vi's
522 		 *	viprintf() does not support it.
523 		 */
524 gettext("%d fewer lines in file after %s")), i, Command);
525 	putNFL();
526 }
527 
528 void
529 putmark(line *addr)
530 {
531 
532 	putmk1(addr, putline());
533 }
534 
535 void
536 putmk1(line *addr, int n)
537 {
538 	line *markp;
539 	int oldglobmk;
540 
541 	oldglobmk = *addr & 1;
542 	*addr &= ~1;
543 	for (markp = (anymarks ? names : &names['z'-'a'+1]);
544 	  markp <= &names['z'-'a'+1]; markp++)
545 		if (*markp == *addr)
546 			*markp = n;
547 	*addr = n | oldglobmk;
548 }
549 
550 unsigned char *
551 plural(i)
552 	long i;
553 {
554 
555 	return (i == 1 ? (unsigned char *)"" : (unsigned char *)"s");
556 }
557 
558 int	qcount();
559 short	vcntcol;
560 
561 int
562 qcolumn(unsigned char *lim, unsigned char *gp)
563 {
564 	int x, length;
565 	int	col;
566 	wchar_t wchar;
567 	int (*OO)();
568 
569 	OO = Outchar;
570 	Outchar = qcount;
571 	vcntcol = 0;
572 	if (lim != NULL) {
573 		if(lim == linebuf - 1 || lim == &linebuf[LBSIZE-2])
574 			length = 1;
575 		else
576 			length = mbtowc(&wchar, (char *)lim, MULTI_BYTE_MAX);
577 		if(length < 0)
578 			length = 1;
579 		x = lim[length];
580 		lim[length] = 0;
581 	}
582 	pline(0);
583 	if (lim != NULL)
584 		lim[length] = x;
585 	if(length > 1 && !gp) {
586 		/* put cursor at beginning of multibyte character */
587 		if ((col = wcwidth(wchar)) < 0)
588 			col = 0;
589 		vcntcol = vcntcol - col + 1;
590 	}
591  	if (gp)
592 		while (*gp) {
593 			length = mbtowc(&wchar, (char *)gp, MULTI_BYTE_MAX);
594 			if(length < 0) {
595 				putoctal = 1;
596 				putchar(*gp++);
597 				putoctal = 0;
598 			} else {
599 				putchar(wchar);
600 				gp += length;
601 			}
602 		}
603 	Outchar = OO;
604 	return (vcntcol);
605 }
606 
607 /* This routine puts cursor after multibyte character */
608 int
609 nqcolumn(unsigned char *lim, unsigned char *gp)
610 {
611 	int x, length;
612 	wchar_t wchar;
613 	int (*OO)();
614 
615 	OO = Outchar;
616 	Outchar = qcount;
617 	vcntcol = 0;
618 	if (lim != NULL) {
619 		if(lim == linebuf - 1 || lim == &linebuf[LBSIZE-2])
620 			length = 1;
621 		else
622 			length = mbtowc(&wchar, (char *)lim, MULTI_BYTE_MAX);
623 		if(length < 0)
624 			length = 1;
625 		x = lim[length];
626 		lim[length] = 0;
627 	}
628 	pline(0);
629 	if (lim != NULL)
630 		lim[length] = x;
631  	if (gp)
632 		while (*gp) {
633 			length = mbtowc(&wchar, (char *)gp, MULTI_BYTE_MAX);
634 			if(length < 0) {
635 				putoctal = 1;
636 				putchar(*gp++);
637 				putoctal = 0;
638 			} else {
639 				putchar(wchar);
640 				gp += length;
641 			}
642 		}
643 	Outchar = OO;
644 	return (vcntcol);
645 }
646 
647 int
648 qcount(c)
649 wchar_t c;
650 {
651 	int cols;
652 #ifndef PRESUNEUC
653 	int remcols;
654 	short OWCOLS;
655 #endif /* PRESUNEUC */
656 
657 	if (c == '\t') {
658 		vcntcol += value(vi_TABSTOP) - vcntcol % value(vi_TABSTOP);
659 		return (0);
660 	}
661 #ifdef PRESUNEUC
662 	if ((cols = wcwidth(c)) > 0)
663 		vcntcol += cols;
664 #else
665 	if ((cols = wcwidth(c)) < 0)
666 		cols = 0;
667 	OWCOLS = WCOLS;
668 	if (WCOLS == 0)
669 		WCOLS = columns;
670 	if ((mc_wrap) == 1 && (remcols = (WCOLS - (vcntcol % WCOLS))) < cols)
671 		vcntcol += remcols;
672 	WCOLS = OWCOLS;
673 	vcntcol += cols;
674 #endif /* PRESUNEUC */
675 	return (0);
676 }
677 
678 void
679 reverse(line *a1, line *a2)
680 {
681 	line t;
682 
683 	for (;;) {
684 		t = *--a2;
685 		if (a2 <= a1)
686 			return;
687 		*a2 = *a1;
688 		*a1++ = t;
689 	}
690 }
691 
692 void
693 save(line *a1, line *a2)
694 {
695 	int more;
696 
697 	if (!FIXUNDO)
698 		return;
699 #ifdef UNDOTRACE
700 	if (trace)
701 		vudump("before save");
702 #endif
703 	undkind = UNDNONE;
704 	undadot = dot;
705 	more = (a2 - a1 + 1) - (unddol - dol);
706 	while (more > (endcore - truedol))
707 		if (morelines() < 0)
708 			error(value(vi_TERSE) ? gettext("Out of memory") :
709 gettext("Out of memory saving lines for undo - try using ed"));
710 	if (more)
711 		(*(more > 0 ? copywR : copyw))(unddol + more + 1, unddol + 1,
712 		    (truedol - unddol));
713 	unddol += more;
714 	truedol += more;
715 	copyw(dol + 1, a1, a2 - a1 + 1);
716 	undkind = UNDALL;
717 	unddel = a1 - 1;
718 	undap1 = a1;
719 	undap2 = a2 + 1;
720 #ifdef UNDOTRACE
721 	if (trace)
722 		vudump("after save");
723 #endif
724 }
725 
726 void
727 save12(void)
728 {
729 
730 	save(addr1, addr2);
731 }
732 
733 void
734 saveall(void)
735 {
736 
737 	save(one, dol);
738 }
739 
740 int
741 span(void)
742 {
743 
744 	return (addr2 - addr1 + 1);
745 }
746 
747 void
748 sync(void)
749 {
750 
751 	chng = 0;
752 	tchng = 0;
753 	xchng = 0;
754 }
755 
756 
757 int
758 skipwh(void)
759 {
760 	int wh;
761 
762 	wh = 0;
763 	while (iswhite(peekchar())) {
764 		wh++;
765 		ignchar();
766 	}
767 	return (wh);
768 }
769 
770 /*VARARGS2*/
771 void
772 smerror(unsigned char *seekpt, unsigned char *cp)
773 {
774 
775 	errcnt++;
776 	merror1(seekpt);
777 	if (inopen && clr_eol)
778 		vclreol();
779 	if (enter_standout_mode && exit_bold)
780 		putpad((unsigned char *)enter_standout_mode);
781 	lprintf(mesg(linebuf), cp);
782 	if (enter_standout_mode && exit_bold)
783 		putpad((unsigned char *)exit_bold);
784 }
785 
786 unsigned char *
787 strend(cp)
788 	unsigned char *cp;
789 {
790 
791 	while (*cp)
792 		cp++;
793 	return (cp);
794 }
795 
796 void
797 strcLIN(unsigned char *dp)
798 {
799 
800 	CP(linebuf, dp);
801 }
802 
803 /*
804  * A system error has occurred that we need to perror.
805  * danger is true if we are unsure of the contents of
806  * the file or our buffer, e.g. a write error in the
807  * middle of a write operation, or a temp file error.
808  */
809 void
810 syserror(int danger)
811 {
812 	int e = errno;
813 	char *errstr;
814 	extern char *strerror();
815 
816 	dirtcnt = 0;
817 	putchar(' ');
818 	if (danger)
819 		edited = 0;	/* for temp file errors, for example */
820 	if ((errstr = strerror(e)) != NULL)
821 		error(errstr);
822 	else
823 		error(gettext("System error %d"), e);
824 }
825 
826 /*
827  * Return the column number that results from being in column col and
828  * hitting a tab, where tabs are set every ts columns.  Work right for
829  * the case where col > columns, even if ts does not divide columns.
830  */
831 int
832 tabcol(int col, int ts)
833 {
834 	int offset, result;
835 
836 	if (col >= columns) {
837 		offset = columns * (col/columns);
838 		col -= offset;
839 	} else
840 		offset = 0;
841 	result = col + ts - (col % ts) + offset;
842 	return (result);
843 }
844 
845 unsigned char *
846 vfindcol(i)
847 	int i;
848 {
849 	unsigned char *cp, *oldcp;
850 	int (*OO)() = Outchar;
851 	int length;
852 	unsigned char x;
853 	wchar_t wchar;
854 
855 	Outchar = qcount;
856 	(void) qcolumn(linebuf - 1, (unsigned char *)NOSTR);
857 	for (cp = linebuf; *cp && vcntcol < i; ) {
858 		oldcp = cp;
859 		length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX);
860 		if(length < 0) {
861 			putoctal = 1;
862 			putchar(*cp++);
863 			putoctal = 0;
864 		} else {
865 			putchar(wchar);
866 			cp += length;
867 		}
868 	}
869 	if (cp != linebuf)
870 		cp = oldcp;
871 	Outchar = OO;
872 	return (cp);
873 }
874 
875 unsigned char *
876 vskipwh(cp)
877 	unsigned char *cp;
878 {
879 
880 	while (iswhite(*cp) && cp[1])
881 		cp++;
882 	return (cp);
883 }
884 
885 
886 unsigned char *
887 vpastwh(cp)
888 	unsigned char *cp;
889 {
890 
891 	while (iswhite(*cp))
892 		cp++;
893 	return (cp);
894 }
895 
896 int
897 whitecnt(unsigned char *cp)
898 {
899 	int i;
900 
901 	i = 0;
902 	for (;;)
903 		switch (*cp++) {
904 
905 		case '\t':
906 			i += value(vi_TABSTOP) - i % value(vi_TABSTOP);
907 			break;
908 
909 		case ' ':
910 			i++;
911 			break;
912 
913 		default:
914 			return (i);
915 		}
916 }
917 
918 void
919 markit(line *addr)
920 {
921 
922 	if (addr != dot && addr >= one && addr <= dol)
923 		markDOT();
924 }
925 
926 /*
927  * The following code is defensive programming against a bug in the
928  * pdp-11 overlay implementation.  Sometimes it goes nuts and asks
929  * for an overlay with some garbage number, which generates an emt
930  * trap.  This is a less than elegant solution, but it is somewhat
931  * better than core dumping and losing your work, leaving your tty
932  * in a weird state, etc.
933  */
934 int _ovno;
935 
936 /*ARGSUSED*/
937 void
938 onemt(sig)
939 int sig;
940 {
941 	int oovno;
942 
943 	signal(SIGEMT, onemt);
944 	oovno = _ovno;
945 	/* 2 and 3 are valid on 11/40 type vi, so */
946 	if (_ovno < 0 || _ovno > 3)
947 		_ovno = 0;
948 	error(value(vi_TERSE) ? gettext("emt trap, _ovno is %d ") :
949 gettext("emt trap, _ovno is %d   - try again"));
950 }
951 
952 /*
953  * When a hangup occurs our actions are similar to a preserve
954  * command.  If the buffer has not been [Modified], then we do
955  * nothing but remove the temporary files and exit.
956  * Otherwise, we sync the temp file and then attempt a preserve.
957  * If the preserve succeeds, we unlink our temp files.
958  * If the preserve fails, we leave the temp files as they are
959  * as they are a backup even without preservation if they
960  * are not removed.
961  */
962 
963 /*ARGSUSED*/
964 void
965 onhup(sig)
966 int sig;
967 {
968 
969 	/*
970 	 * USG tty driver can send multiple HUP's!!
971 	 */
972 	signal(SIGINT, SIG_IGN);
973 	signal(SIGHUP, SIG_IGN);
974 	if (chng == 0) {
975 		cleanup(1);
976 		exit(++errcnt);
977 	}
978 	if (setexit() == 0) {
979 		if (preserve()) {
980 			cleanup(1);
981 			exit(++errcnt);
982 		}
983 	}
984 	if (kflag)
985 		crypt_close(perm);
986 	if (xtflag)
987 		crypt_close(tperm);
988 	exit(++errcnt);
989 }
990 
991 /*
992  * Similar to onhup.  This happens when any random core dump occurs,
993  * e.g. a bug in vi.  We preserve the file and then generate a core.
994  */
995 void oncore(sig)
996 int sig;
997 {
998 	static int timescalled = 0;
999 	char *messagep;	/* for message localization */
1000 
1001 	/*
1002 	 * USG tty driver can send multiple HUP's!!
1003 	 */
1004 	signal(SIGINT, SIG_IGN);
1005 	signal(SIGHUP, SIG_IGN);
1006 	signal(sig, SIG_DFL);	/* Insure that we don't catch it again */
1007 	messagep = (char *)gettext("\r\nYour file has been preserved\r\n");
1008 	if (timescalled++ == 0 && chng && setexit() == 0) {
1009 		if (inopen)
1010 			vsave();
1011 		(void) preserve();
1012 		write(1, messagep, strlen(messagep));
1013 	}
1014 	if (timescalled < 2) {
1015 		normal(normf);
1016 		cleanup(2);
1017 		kill(getpid(), sig);	/* Resend ourselves the same signal */
1018 		/* We won't get past here */
1019 	}
1020 	if (kflag)
1021 		crypt_close(perm);
1022 	if (xtflag)
1023 		crypt_close(tperm);
1024 	exit(++errcnt);
1025 }
1026 
1027 /*
1028  * An interrupt occurred.  Drain any output which
1029  * is still in the output buffering pipeline.
1030  * Catch interrupts again.  Unless we are in visual
1031  * reset the output state (out of -nl mode, e.g).
1032  * Then like a normal error (with the \n before Interrupt
1033  * suppressed in visual mode).
1034  */
1035 
1036 /*ARGSUSED*/
1037 void
1038 onintr(sig)
1039 int sig;
1040 {
1041 #ifndef CBREAK
1042 	signal(SIGINT, onintr);
1043 #else
1044 	signal(SIGINT, inopen ? vintr : onintr);
1045 #endif
1046 	cancelalarm();
1047 	draino();
1048 	if (!inopen) {
1049 		pstop();
1050 		setlastchar('\n');
1051 #ifdef CBREAK
1052 	}
1053 #else
1054 	} else
1055 		vraw();
1056 #endif
1057 	error(gettext("\nInterrupt") + (inopen!=0));
1058 }
1059 
1060 /*
1061  * If we are interruptible, enable interrupts again.
1062  * In some critical sections we turn interrupts off,
1063  * but not very often.
1064  */
1065 void
1066 setrupt(void)
1067 {
1068 
1069 	if (ruptible) {
1070 #ifndef CBREAK
1071 		signal(SIGINT, onintr);
1072 #else
1073 		signal(SIGINT, inopen ? vintr : onintr);
1074 #endif
1075 #ifdef SIGTSTP
1076 		if (dosusp)
1077 			signal(SIGTSTP, onsusp);
1078 #endif
1079 	}
1080 }
1081 
1082 int
1083 preserve(void)
1084 {
1085 
1086 #ifdef VMUNIX
1087 	tflush();
1088 #endif
1089 	synctmp();
1090 	pid = fork();
1091 	if (pid < 0)
1092 		return (0);
1093 	if (pid == 0) {
1094 		close(0);
1095 		dup(tfile);
1096 		execlp(EXPRESERVE, "expreserve", (char *) 0);
1097 		exit(++errcnt);
1098 	}
1099 	waitfor();
1100 	if (rpid == pid && status == 0)
1101 		return (1);
1102 	return (0);
1103 }
1104 
1105 #ifndef V6
1106 void exit(i)
1107 	int i;
1108 {
1109 
1110 	extern void _exit(int) __NORETURN;
1111 #ifdef TRACE
1112 	if (trace)
1113 		fclose(trace);
1114 #endif
1115 	_exit(i);
1116 }
1117 #endif
1118 
1119 #ifdef SIGTSTP
1120 /*
1121  * We have just gotten a susp.  Suspend and prepare to resume.
1122  */
1123 extern void redraw();
1124 
1125 /*ARGSUSED*/
1126 void
1127 onsusp(sig)
1128 int sig;
1129 {
1130 	ttymode f;
1131 	int savenormtty;
1132 
1133 	f = setty(normf);
1134 	vnfl();
1135 	putpad((unsigned char *)exit_ca_mode);
1136 	flush();
1137 	resetterm();
1138 	savenormtty = normtty;
1139 	normtty = 0;
1140 
1141 	signal(SIGTSTP, SIG_DFL);
1142 	kill(0, SIGTSTP);
1143 
1144 	/* the pc stops here */
1145 
1146 	signal(SIGTSTP, onsusp);
1147 	normtty = savenormtty;
1148 	vcontin(0);
1149 	flush();
1150 	setty(f);
1151 	if (!inopen)
1152 		error(0);
1153 	else {
1154 		if(vcnt < 0) {
1155 			vcnt = -vcnt;
1156 			if(state == VISUAL)
1157 				vclear();
1158 			else if(state == CRTOPEN)
1159 				vcnt = 0;
1160 		}
1161 		vdirty(0, lines);
1162 		if (sig)
1163 			vrepaint(cursor);
1164 	}
1165 }
1166 #endif
1167 
1168 unsigned char *nextchr(cursor)
1169 unsigned char *cursor;
1170 {
1171 
1172 	wchar_t wchar;
1173 	int length;
1174 	length = mbtowc(&wchar, (char *)cursor, MULTI_BYTE_MAX);
1175 	if(length <= 0)
1176 		return(++cursor);
1177 	return(cursor + length);
1178 }
1179 
1180 unsigned char *lastchr(linebuf, cursor)
1181 unsigned char *linebuf, *cursor;
1182 {
1183 	wchar_t wchar;
1184 	int length;
1185 	unsigned char *ccursor, *ocursor;
1186 	if(cursor == linebuf)
1187 		return(linebuf - 1);
1188 	ccursor = ocursor = linebuf;
1189 	while(ccursor < cursor) {
1190 		length = mbtowc(&wchar, (char *)ccursor, MULTI_BYTE_MAX);
1191 		ocursor =  ccursor;
1192 		if(length <= 0)
1193 			ccursor++;
1194 		else
1195 			ccursor += length;
1196 	}
1197 	return(ocursor);
1198 }
1199 
1200 int
1201 ixlatctl(int flag)
1202 {
1203 	static struct strioctl sb = {0, 0, 0, 0};
1204 
1205 	if (!(MULTI_BYTE_MAX > 1))
1206 		return (0);
1207 
1208 	switch (flag) {
1209 	case 0:
1210 		sb.ic_cmd = EUC_MSAVE;
1211 		sb.ic_len = 0;
1212 		sb.ic_dp = 0;
1213 		if (ioctl(0, I_STR, &sb) < 0)
1214 			return (-1);
1215 		return (0);
1216 	case 1:
1217 		sb.ic_cmd = EUC_MREST;
1218 		sb.ic_len = 0;
1219 		sb.ic_dp = 0;
1220 		if (ioctl(0, I_STR, &sb) < 0)
1221 			return (-1);
1222 		return (0);
1223 	case 11:
1224 		return (0);
1225 	default:
1226 		return (-1);
1227 	}
1228 }
1229 #ifndef PRESUNEUC
1230 
1231 /* locale specific initialization */
1232 void
1233 localize(void)
1234 {
1235 	wchar_t fillerchar;
1236 	extern int	wdchkind();
1237 	extern int	wdbindf();
1238 	extern wchar_t	*wddelim();
1239 	extern wchar_t	mcfiller();
1240 
1241 	wdwc = wdchkind;
1242 	wdbdg = wdbindf;
1243 	wddlm = wddelim;
1244 	mcfllr = mcfiller;
1245 	mc_wrap = 1;
1246 	fillerchar = mcfiller();
1247 	mc_filler = isascii(fillerchar) ? (fillerchar & 0x7f) : '~';
1248 }
1249 #endif /* PRESUNEUC */
1250