ex_subr.c revision 802:73b56fb6544b
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
57int
58any(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
68int
69backtab(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
82void
83change(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 */
96int
97column(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 */
109int
110lcolumn(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 */
122void
123comment(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
134void
135Copy(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
144void
145copyw(line *to, line *from, int size)
146{
147
148	if (size > 0)
149		do
150			*to++ = *from++;
151		while (--size > 0);
152}
153
154void
155copywR(line *to, line *from, int size)
156{
157
158	while (--size >= 0)
159		to[size] = from[size];
160}
161
162int
163ctlof(int c)
164{
165
166	return (c == DELETE ? '?' : c | ('A' - 1));
167}
168
169void
170dingdong(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
179int
180fixindent(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
195void
196filioerr(unsigned char *cp)
197{
198	int oerrno = errno;
199
200	lprintf("\"%s\"", cp);
201	errno = oerrno;
202	syserror(1);
203}
204
205unsigned char *
206genindent(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
218void
219getDOT(void)
220{
221
222	getline(*dot);
223}
224
225line *
226getmark(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
238void
239ignnEOF(void)
240{
241	int c = getchar();
242
243	if (c == EOF)
244		ungetchar(c);
245	else if (c=='"')
246		comment();
247}
248
249int
250iswhite(int c)
251{
252
253	return (c == ' ' || c == '\t');
254}
255
256int
257junk(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
276void
277killed(void)
278{
279
280	killcnt(addr2 - addr1 + 1);
281}
282
283void
284killcnt(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
307int
308lineno(line *a)
309{
310
311	return (a - zero);
312}
313
314int
315lineDOL(void)
316{
317
318	return (lineno(dol));
319}
320
321int
322lineDOT(void)
323{
324
325	return (lineno(dot));
326}
327
328void
329markDOT(void)
330{
331
332	markpr(dot);
333}
334
335void
336markpr(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
346int
347markreg(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 */
366unsigned char *
367mesg(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*/
394void
395merror(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
417void
418merror1(unsigned char *seekpt)
419{
420
421	strcpy(linebuf, seekpt);
422}
423
424#define MAXDATA (56*1024)
425int
426morelines(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
448void
449nonzero(void)
450{
451
452	if (addr1 == zero) {
453		notempty();
454		error(value(vi_TERSE) ? gettext("Nonzero address required") :
455gettext("Nonzero address required on this command"));
456	}
457}
458
459int
460notable(int i)
461{
462
463	return (hush == 0 && !inglobal && i > value(vi_REPORT));
464}
465
466
467void
468notempty(void)
469{
470
471	if (dol == zero)
472		error(value(vi_TERSE) ? gettext("No lines") :
473gettext("No lines in the buffer"));
474}
475
476
477void
478netchHAD(int cnt)
479{
480
481	netchange(lineDOL() - cnt);
482}
483
484void
485netchange(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 */
506gettext("%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		 */
513gettext("%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 */
520gettext("%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		 */
527gettext("%d fewer lines in file after %s")), i, Command);
528	putNFL();
529}
530
531void
532putmark(line *addr)
533{
534
535	putmk1(addr, putline());
536}
537
538void
539putmk1(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
553unsigned char *
554plural(i)
555	long i;
556{
557
558	return (i == 1 ? (unsigned char *)"" : (unsigned char *)"s");
559}
560
561int	qcount();
562short	vcntcol;
563
564int
565qcolumn(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 */
611int
612nqcolumn(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
650int
651qcount(c)
652wchar_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
681void
682reverse(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
695void
696save(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") :
712gettext("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
729void
730save12(void)
731{
732
733	save(addr1, addr2);
734}
735
736void
737saveall(void)
738{
739
740	save(one, dol);
741}
742
743int
744span(void)
745{
746
747	return (addr2 - addr1 + 1);
748}
749
750void
751sync(void)
752{
753
754	chng = 0;
755	tchng = 0;
756	xchng = 0;
757}
758
759
760int
761skipwh(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*/
774void
775smerror(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
789unsigned char *
790strend(cp)
791	unsigned char *cp;
792{
793
794	while (*cp)
795		cp++;
796	return (cp);
797}
798
799void
800strcLIN(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 */
812void
813syserror(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 */
834int
835tabcol(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
848unsigned char *
849vfindcol(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
878unsigned char *
879vskipwh(cp)
880	unsigned char *cp;
881{
882
883	while (iswhite(*cp) && cp[1])
884		cp++;
885	return (cp);
886}
887
888
889unsigned char *
890vpastwh(cp)
891	unsigned char *cp;
892{
893
894	while (iswhite(*cp))
895		cp++;
896	return (cp);
897}
898
899int
900whitecnt(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
921void
922markit(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 */
937int _ovno;
938
939/*ARGSUSED*/
940void
941onemt(sig)
942int 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 ") :
952gettext("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*/
967void
968onhup(sig)
969int 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 */
998void oncore(sig)
999int 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*/
1040void
1041onintr(sig)
1042int 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 */
1068void
1069setrupt(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
1085int
1086preserve(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
1109void 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 */
1126extern void redraw();
1127
1128/*ARGSUSED*/
1129void
1130onsusp(sig)
1131int 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
1171unsigned char *nextchr(cursor)
1172unsigned 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
1183unsigned char *lastchr(linebuf, cursor)
1184unsigned 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
1203int
1204ixlatctl(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 */
1235void
1236localize(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