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
54int
55any(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
65int
66backtab(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
79void
80change(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 */
93int
94column(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 */
106int
107lcolumn(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 */
119void
120comment(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
131void
132Copy(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
141void
142copyw(line *to, line *from, int size)
143{
144
145	if (size > 0)
146		do
147			*to++ = *from++;
148		while (--size > 0);
149}
150
151void
152copywR(line *to, line *from, int size)
153{
154
155	while (--size >= 0)
156		to[size] = from[size];
157}
158
159int
160ctlof(int c)
161{
162
163	return (c == DELETE ? '?' : c | ('A' - 1));
164}
165
166void
167dingdong(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
176int
177fixindent(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
192void
193filioerr(unsigned char *cp)
194{
195	int oerrno = errno;
196
197	lprintf("\"%s\"", cp);
198	errno = oerrno;
199	syserror(1);
200}
201
202unsigned char *
203genindent(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
215void
216getDOT(void)
217{
218
219	getaline(*dot);
220}
221
222line *
223getmark(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
235void
236ignnEOF(void)
237{
238	int c = getchar();
239
240	if (c == EOF)
241		ungetchar(c);
242	else if (c=='"')
243		comment();
244}
245
246int
247iswhite(int c)
248{
249
250	return (c == ' ' || c == '\t');
251}
252
253int
254junk(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
273void
274killed(void)
275{
276
277	killcnt(addr2 - addr1 + 1);
278}
279
280void
281killcnt(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
304int
305lineno(line *a)
306{
307
308	return (a - zero);
309}
310
311int
312lineDOL(void)
313{
314
315	return (lineno(dol));
316}
317
318int
319lineDOT(void)
320{
321
322	return (lineno(dot));
323}
324
325void
326markDOT(void)
327{
328
329	markpr(dot);
330}
331
332void
333markpr(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
343int
344markreg(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 */
363unsigned char *
364mesg(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*/
391void
392merror(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
414void
415merror1(unsigned char *seekpt)
416{
417
418	strcpy(linebuf, seekpt);
419}
420
421#define MAXDATA (56*1024)
422int
423morelines(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
445void
446nonzero(void)
447{
448
449	if (addr1 == zero) {
450		notempty();
451		error(value(vi_TERSE) ? gettext("Nonzero address required") :
452gettext("Nonzero address required on this command"));
453	}
454}
455
456int
457notable(int i)
458{
459
460	return (hush == 0 && !inglobal && i > value(vi_REPORT));
461}
462
463
464void
465notempty(void)
466{
467
468	if (dol == zero)
469		error(value(vi_TERSE) ? gettext("No lines") :
470gettext("No lines in the buffer"));
471}
472
473
474void
475netchHAD(int cnt)
476{
477
478	netchange(lineDOL() - cnt);
479}
480
481void
482netchange(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 */
503gettext("%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		 */
510gettext("%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 */
517gettext("%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		 */
524gettext("%d fewer lines in file after %s")), i, Command);
525	putNFL();
526}
527
528void
529putmark(line *addr)
530{
531
532	putmk1(addr, putline());
533}
534
535void
536putmk1(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
550unsigned char *
551plural(i)
552	long i;
553{
554
555	return (i == 1 ? (unsigned char *)"" : (unsigned char *)"s");
556}
557
558int	qcount();
559short	vcntcol;
560
561int
562qcolumn(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 */
608int
609nqcolumn(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
647int
648qcount(c)
649wchar_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
678void
679reverse(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
692void
693save(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") :
709gettext("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
726void
727save12(void)
728{
729
730	save(addr1, addr2);
731}
732
733void
734saveall(void)
735{
736
737	save(one, dol);
738}
739
740int
741span(void)
742{
743
744	return (addr2 - addr1 + 1);
745}
746
747void
748sync(void)
749{
750
751	chng = 0;
752	tchng = 0;
753	xchng = 0;
754}
755
756
757int
758skipwh(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*/
771void
772smerror(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
786unsigned char *
787strend(cp)
788	unsigned char *cp;
789{
790
791	while (*cp)
792		cp++;
793	return (cp);
794}
795
796void
797strcLIN(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 */
809void
810syserror(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 */
831int
832tabcol(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
845unsigned char *
846vfindcol(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
875unsigned char *
876vskipwh(cp)
877	unsigned char *cp;
878{
879
880	while (iswhite(*cp) && cp[1])
881		cp++;
882	return (cp);
883}
884
885
886unsigned char *
887vpastwh(cp)
888	unsigned char *cp;
889{
890
891	while (iswhite(*cp))
892		cp++;
893	return (cp);
894}
895
896int
897whitecnt(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
918void
919markit(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*/
938void
939onhup(sig)
940int 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 */
969void oncore(sig)
970int 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*/
1011void
1012onintr(sig)
1013int 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 */
1039void
1040setrupt(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
1056int
1057preserve(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
1080void 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 */
1097extern void redraw();
1098
1099/*ARGSUSED*/
1100void
1101onsusp(sig)
1102int 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
1142unsigned char *nextchr(cursor)
1143unsigned 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
1154unsigned char *lastchr(linebuf, cursor)
1155unsigned 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
1174int
1175ixlatctl(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 */
1206void
1207localize(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