xref: /illumos-gate/usr/src/cmd/vi/port/ex_subr.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
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  * When a hangup occurs our actions are similar to a preserve
928  * command.  If the buffer has not been [Modified], then we do
929  * nothing but remove the temporary files and exit.
930  * Otherwise, we sync the temp file and then attempt a preserve.
931  * If the preserve succeeds, we unlink our temp files.
932  * If the preserve fails, we leave the temp files as they are
933  * as they are a backup even without preservation if they
934  * are not removed.
935  */
936 
937 /*ARGSUSED*/
938 void
939 onhup(sig)
940 int sig;
941 {
942 
943 	/*
944 	 * USG tty driver can send multiple HUP's!!
945 	 */
946 	signal(SIGINT, SIG_IGN);
947 	signal(SIGHUP, SIG_IGN);
948 	if (chng == 0) {
949 		cleanup(1);
950 		exit(++errcnt);
951 	}
952 	if (setexit() == 0) {
953 		if (preserve()) {
954 			cleanup(1);
955 			exit(++errcnt);
956 		}
957 	}
958 	if (kflag)
959 		crypt_close(perm);
960 	if (xtflag)
961 		crypt_close(tperm);
962 	exit(++errcnt);
963 }
964 
965 /*
966  * Similar to onhup.  This happens when any random core dump occurs,
967  * e.g. a bug in vi.  We preserve the file and then generate a core.
968  */
969 void oncore(sig)
970 int sig;
971 {
972 	static int timescalled = 0;
973 	char *messagep;	/* for message localization */
974 
975 	/*
976 	 * USG tty driver can send multiple HUP's!!
977 	 */
978 	signal(SIGINT, SIG_IGN);
979 	signal(SIGHUP, SIG_IGN);
980 	signal(sig, SIG_DFL);	/* Insure that we don't catch it again */
981 	messagep = (char *)gettext("\r\nYour file has been preserved\r\n");
982 	if (timescalled++ == 0 && chng && setexit() == 0) {
983 		if (inopen)
984 			vsave();
985 		(void) preserve();
986 		write(1, messagep, strlen(messagep));
987 	}
988 	if (timescalled < 2) {
989 		normal(normf);
990 		cleanup(2);
991 		kill(getpid(), sig);	/* Resend ourselves the same signal */
992 		/* We won't get past here */
993 	}
994 	if (kflag)
995 		crypt_close(perm);
996 	if (xtflag)
997 		crypt_close(tperm);
998 	exit(++errcnt);
999 }
1000 
1001 /*
1002  * An interrupt occurred.  Drain any output which
1003  * is still in the output buffering pipeline.
1004  * Catch interrupts again.  Unless we are in visual
1005  * reset the output state (out of -nl mode, e.g).
1006  * Then like a normal error (with the \n before Interrupt
1007  * suppressed in visual mode).
1008  */
1009 
1010 /*ARGSUSED*/
1011 void
1012 onintr(sig)
1013 int sig;
1014 {
1015 #ifndef CBREAK
1016 	signal(SIGINT, onintr);
1017 #else
1018 	signal(SIGINT, inopen ? vintr : onintr);
1019 #endif
1020 	cancelalarm();
1021 	draino();
1022 	if (!inopen) {
1023 		pstop();
1024 		setlastchar('\n');
1025 #ifdef CBREAK
1026 	}
1027 #else
1028 	} else
1029 		vraw();
1030 #endif
1031 	error(gettext("\nInterrupt") + (inopen!=0));
1032 }
1033 
1034 /*
1035  * If we are interruptible, enable interrupts again.
1036  * In some critical sections we turn interrupts off,
1037  * but not very often.
1038  */
1039 void
1040 setrupt(void)
1041 {
1042 
1043 	if (ruptible) {
1044 #ifndef CBREAK
1045 		signal(SIGINT, onintr);
1046 #else
1047 		signal(SIGINT, inopen ? vintr : onintr);
1048 #endif
1049 #ifdef SIGTSTP
1050 		if (dosusp)
1051 			signal(SIGTSTP, onsusp);
1052 #endif
1053 	}
1054 }
1055 
1056 int
1057 preserve(void)
1058 {
1059 
1060 #ifdef VMUNIX
1061 	tflush();
1062 #endif
1063 	synctmp();
1064 	pid = fork();
1065 	if (pid < 0)
1066 		return (0);
1067 	if (pid == 0) {
1068 		close(0);
1069 		dup(tfile);
1070 		execlp(EXPRESERVE, "expreserve", (char *) 0);
1071 		exit(++errcnt);
1072 	}
1073 	waitfor();
1074 	if (rpid == pid && status == 0)
1075 		return (1);
1076 	return (0);
1077 }
1078 
1079 #ifndef V6
1080 void exit(i)
1081 	int i;
1082 {
1083 
1084 	extern void _exit(int) __NORETURN;
1085 #ifdef TRACE
1086 	if (trace)
1087 		fclose(trace);
1088 #endif
1089 	_exit(i);
1090 }
1091 #endif
1092 
1093 #ifdef SIGTSTP
1094 /*
1095  * We have just gotten a susp.  Suspend and prepare to resume.
1096  */
1097 extern void redraw();
1098 
1099 /*ARGSUSED*/
1100 void
1101 onsusp(sig)
1102 int sig;
1103 {
1104 	ttymode f;
1105 	int savenormtty;
1106 
1107 	f = setty(normf);
1108 	vnfl();
1109 	putpad((unsigned char *)exit_ca_mode);
1110 	flush();
1111 	resetterm();
1112 	savenormtty = normtty;
1113 	normtty = 0;
1114 
1115 	signal(SIGTSTP, SIG_DFL);
1116 	kill(0, SIGTSTP);
1117 
1118 	/* the pc stops here */
1119 
1120 	signal(SIGTSTP, onsusp);
1121 	normtty = savenormtty;
1122 	vcontin(0);
1123 	flush();
1124 	setty(f);
1125 	if (!inopen)
1126 		syserror(0);
1127 	else {
1128 		if(vcnt < 0) {
1129 			vcnt = -vcnt;
1130 			if(state == VISUAL)
1131 				vclear();
1132 			else if(state == CRTOPEN)
1133 				vcnt = 0;
1134 		}
1135 		vdirty(0, lines);
1136 		if (sig)
1137 			vrepaint(cursor);
1138 	}
1139 }
1140 #endif
1141 
1142 unsigned char *nextchr(cursor)
1143 unsigned char *cursor;
1144 {
1145 
1146 	wchar_t wchar;
1147 	int length;
1148 	length = mbtowc(&wchar, (char *)cursor, MULTI_BYTE_MAX);
1149 	if(length <= 0)
1150 		return(++cursor);
1151 	return(cursor + length);
1152 }
1153 
1154 unsigned char *lastchr(linebuf, cursor)
1155 unsigned char *linebuf, *cursor;
1156 {
1157 	wchar_t wchar;
1158 	int length;
1159 	unsigned char *ccursor, *ocursor;
1160 	if(cursor == linebuf)
1161 		return(linebuf - 1);
1162 	ccursor = ocursor = linebuf;
1163 	while(ccursor < cursor) {
1164 		length = mbtowc(&wchar, (char *)ccursor, MULTI_BYTE_MAX);
1165 		ocursor =  ccursor;
1166 		if(length <= 0)
1167 			ccursor++;
1168 		else
1169 			ccursor += length;
1170 	}
1171 	return(ocursor);
1172 }
1173 
1174 int
1175 ixlatctl(int flag)
1176 {
1177 	static struct strioctl sb = {0, 0, 0, 0};
1178 
1179 	if (!(MULTI_BYTE_MAX > 1))
1180 		return (0);
1181 
1182 	switch (flag) {
1183 	case 0:
1184 		sb.ic_cmd = EUC_MSAVE;
1185 		sb.ic_len = 0;
1186 		sb.ic_dp = 0;
1187 		if (ioctl(0, I_STR, &sb) < 0)
1188 			return (-1);
1189 		return (0);
1190 	case 1:
1191 		sb.ic_cmd = EUC_MREST;
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 11:
1198 		return (0);
1199 	default:
1200 		return (-1);
1201 	}
1202 }
1203 #ifndef PRESUNEUC
1204 
1205 /* locale specific initialization */
1206 void
1207 localize(void)
1208 {
1209 	wchar_t fillerchar;
1210 	extern int	wdchkind();
1211 	extern int	wdbindf();
1212 	extern wchar_t	*wddelim();
1213 	extern wchar_t	mcfiller();
1214 
1215 	wdwc = wdchkind;
1216 	wdbdg = wdbindf;
1217 	wddlm = wddelim;
1218 	mcfllr = mcfiller;
1219 	mc_wrap = 1;
1220 	fillerchar = mcfiller();
1221 	mc_filler = isascii(fillerchar) ? (fillerchar & 0x7f) : '~';
1222 }
1223 #endif /* PRESUNEUC */
1224