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