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