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