xref: /illumos-gate/usr/src/cmd/vi/port/ex_io.c (revision 9097ca5c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
523a1cceaSRoger A. Faulkner  * Common Development and Distribution License (the "License").
623a1cceaSRoger A. Faulkner  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2123a1cceaSRoger A. Faulkner 
22f6db9f27Scf /*
2323a1cceaSRoger A. Faulkner  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
25f6db9f27Scf  */
26f6db9f27Scf 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "ex.h"
347c478bd9Sstevel@tonic-gate #include "ex_argv.h"
357c478bd9Sstevel@tonic-gate #include "ex_temp.h"
367c478bd9Sstevel@tonic-gate #include "ex_tty.h"
377c478bd9Sstevel@tonic-gate #include "ex_vis.h"
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
39f6db9f27Scf #include <unistd.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * File input/output, source, preserve and recover
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Following remember where . was in the previous file for return
477c478bd9Sstevel@tonic-gate  * on file switching.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate int	altdot;
507c478bd9Sstevel@tonic-gate int	oldadot;
517c478bd9Sstevel@tonic-gate bool	wasalt;
527c478bd9Sstevel@tonic-gate short	isalt;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate long	cntch;			/* Count of characters on unit io */
557c478bd9Sstevel@tonic-gate #ifndef VMUNIX
567c478bd9Sstevel@tonic-gate short	cntln;			/* Count of lines " */
577c478bd9Sstevel@tonic-gate #else
587c478bd9Sstevel@tonic-gate int	cntln;
597c478bd9Sstevel@tonic-gate #endif
607c478bd9Sstevel@tonic-gate long	cntnull;		/* Count of nulls " */
617c478bd9Sstevel@tonic-gate long	cntodd;			/* Count of non-ascii characters " */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static void chkmdln();
64f6db9f27Scf extern int	getchar();
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * Parse file name for command encoded by comm.
687c478bd9Sstevel@tonic-gate  * If comm is E then command is doomed and we are
697c478bd9Sstevel@tonic-gate  * parsing just so user won't have to retype the name.
707c478bd9Sstevel@tonic-gate  */
71f6db9f27Scf void
filename(int comm)72f6db9f27Scf filename(int comm)
737c478bd9Sstevel@tonic-gate {
74f6db9f27Scf 	int c = comm, d;
75f6db9f27Scf 	int i;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	d = getchar();
787c478bd9Sstevel@tonic-gate 	if (endcmd(d)) {
797c478bd9Sstevel@tonic-gate 		if (savedfile[0] == 0 && comm != 'f')
807c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No file") :
817c478bd9Sstevel@tonic-gate gettext("No current filename"));
827c478bd9Sstevel@tonic-gate 		CP(file, savedfile);
837c478bd9Sstevel@tonic-gate 		wasalt = (isalt > 0) ? isalt-1 : 0;
847c478bd9Sstevel@tonic-gate 		isalt = 0;
857c478bd9Sstevel@tonic-gate 		oldadot = altdot;
867c478bd9Sstevel@tonic-gate 		if (c == 'e' || c == 'E')
877c478bd9Sstevel@tonic-gate 			altdot = lineDOT();
887c478bd9Sstevel@tonic-gate 		if (d == EOF)
897c478bd9Sstevel@tonic-gate 			ungetchar(d);
907c478bd9Sstevel@tonic-gate 	} else {
917c478bd9Sstevel@tonic-gate 		ungetchar(d);
927c478bd9Sstevel@tonic-gate 		getone();
937c478bd9Sstevel@tonic-gate 		eol();
947c478bd9Sstevel@tonic-gate 		if (savedfile[0] == 0 && c != 'E' && c != 'e') {
957c478bd9Sstevel@tonic-gate 			c = 'e';
967c478bd9Sstevel@tonic-gate 			edited = 0;
977c478bd9Sstevel@tonic-gate 		}
987c478bd9Sstevel@tonic-gate 		wasalt = strcmp(file, altfile) == 0;
997c478bd9Sstevel@tonic-gate 		oldadot = altdot;
1007c478bd9Sstevel@tonic-gate 		switch (c) {
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 		case 'f':
1037c478bd9Sstevel@tonic-gate 			edited = 0;
104*9097ca5cSToomas Soome 			/* FALLTHROUGH */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 		case 'e':
1077c478bd9Sstevel@tonic-gate 			if (savedfile[0]) {
1087c478bd9Sstevel@tonic-gate 				altdot = lineDOT();
1097c478bd9Sstevel@tonic-gate 				CP(altfile, savedfile);
1107c478bd9Sstevel@tonic-gate 			}
1117c478bd9Sstevel@tonic-gate 			CP(savedfile, file);
1127c478bd9Sstevel@tonic-gate 			break;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 		default:
1157c478bd9Sstevel@tonic-gate 			if (file[0]) {
1167c478bd9Sstevel@tonic-gate 				if (c != 'E')
1177c478bd9Sstevel@tonic-gate 					altdot = lineDOT();
1187c478bd9Sstevel@tonic-gate 				CP(altfile, file);
1197c478bd9Sstevel@tonic-gate 			}
1207c478bd9Sstevel@tonic-gate 			break;
1217c478bd9Sstevel@tonic-gate 		}
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 	if (hush && comm != 'f' || comm == 'E')
1247c478bd9Sstevel@tonic-gate 		return;
1257c478bd9Sstevel@tonic-gate 	if (file[0] != 0) {
1267c478bd9Sstevel@tonic-gate 		lprintf("\"%s\"", file);
1277c478bd9Sstevel@tonic-gate 		if (comm == 'f') {
1287c478bd9Sstevel@tonic-gate 			if (value(vi_READONLY))
129f6db9f27Scf 				viprintf(gettext(" [Read only]"));
1307c478bd9Sstevel@tonic-gate 			if (!edited)
131f6db9f27Scf 				viprintf(gettext(" [Not edited]"));
1327c478bd9Sstevel@tonic-gate 			if (tchng)
133f6db9f27Scf 				viprintf(gettext(" [Modified]"));
1347c478bd9Sstevel@tonic-gate 		}
1357c478bd9Sstevel@tonic-gate 		flush();
1367c478bd9Sstevel@tonic-gate 	} else
137f6db9f27Scf 		viprintf(gettext("No file "));
1387c478bd9Sstevel@tonic-gate 	if (comm == 'f') {
1397c478bd9Sstevel@tonic-gate 		if (!(i = lineDOL()))
1407c478bd9Sstevel@tonic-gate 			i++;
1417c478bd9Sstevel@tonic-gate 		/*
1427c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
1437c478bd9Sstevel@tonic-gate 		 *	Reference order of arguments must not
1447c478bd9Sstevel@tonic-gate 		 *	be changed using '%digit$', since vi's
145f6db9f27Scf 		 *	viprintf() does not support it.
1467c478bd9Sstevel@tonic-gate 		 */
147f6db9f27Scf 		viprintf(gettext(" line %d of %d --%ld%%--"), lineDOT(),
148f6db9f27Scf 		    lineDOL(), (long)(100 * lineDOT() / i));
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*
1537c478bd9Sstevel@tonic-gate  * Get the argument words for a command into genbuf
1547c478bd9Sstevel@tonic-gate  * expanding # and %.
1557c478bd9Sstevel@tonic-gate  */
156f6db9f27Scf int
getargs(void)157f6db9f27Scf getargs(void)
1587c478bd9Sstevel@tonic-gate {
159f6db9f27Scf 	int c;
160f6db9f27Scf 	unsigned char *cp, *fp;
1617c478bd9Sstevel@tonic-gate 	static unsigned char fpatbuf[32];	/* hence limit on :next +/pat */
1627c478bd9Sstevel@tonic-gate 	char	multic[MB_LEN_MAX + 1];
1637c478bd9Sstevel@tonic-gate 	int	len;
1647c478bd9Sstevel@tonic-gate 	wchar_t	wc;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	pastwh();
1677c478bd9Sstevel@tonic-gate 	if (peekchar() == '+') {
1687c478bd9Sstevel@tonic-gate 		for (cp = fpatbuf;;) {
1697c478bd9Sstevel@tonic-gate 			if (!isascii(c = peekchar()) && (c != EOF)) {
1707c478bd9Sstevel@tonic-gate 				if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) {
1717c478bd9Sstevel@tonic-gate 					if ((cp + len) >= &fpatbuf[sizeof(fpatbuf)])
1727c478bd9Sstevel@tonic-gate 						error(gettext("Pattern too long"));
1737c478bd9Sstevel@tonic-gate 					strncpy(cp, multic, len);
1747c478bd9Sstevel@tonic-gate 					cp += len;
1757c478bd9Sstevel@tonic-gate 					continue;
1767c478bd9Sstevel@tonic-gate 				}
1777c478bd9Sstevel@tonic-gate 			}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 			c = getchar();
1807c478bd9Sstevel@tonic-gate 			*cp++ = c;
1817c478bd9Sstevel@tonic-gate 			if (cp >= &fpatbuf[sizeof(fpatbuf)])
1827c478bd9Sstevel@tonic-gate 				error(gettext("Pattern too long"));
1837c478bd9Sstevel@tonic-gate 			if (c == '\\' && isspace(peekchar()))
1847c478bd9Sstevel@tonic-gate 				c = getchar();
1857c478bd9Sstevel@tonic-gate 			if (c == EOF || isspace(c)) {
1867c478bd9Sstevel@tonic-gate 				ungetchar(c);
1877c478bd9Sstevel@tonic-gate 				*--cp = 0;
1887c478bd9Sstevel@tonic-gate 				firstpat = &fpatbuf[1];
1897c478bd9Sstevel@tonic-gate 				break;
1907c478bd9Sstevel@tonic-gate 			}
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 	if (skipend())
1947c478bd9Sstevel@tonic-gate 		return (0);
1957c478bd9Sstevel@tonic-gate 	CP(genbuf, "echo "); cp = &genbuf[5];
1967c478bd9Sstevel@tonic-gate 	for (;;) {
1977c478bd9Sstevel@tonic-gate 		if (!isascii(c = peekchar())) {
1987c478bd9Sstevel@tonic-gate 			if (endcmd(c) && c != '"')
1997c478bd9Sstevel@tonic-gate 				break;
2007c478bd9Sstevel@tonic-gate 			if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) {
2017c478bd9Sstevel@tonic-gate 				if ((cp + len) > &genbuf[LBSIZE - 2])
2027c478bd9Sstevel@tonic-gate 					error(gettext("Argument buffer overflow"));
2037c478bd9Sstevel@tonic-gate 				strncpy(cp, multic, len);
2047c478bd9Sstevel@tonic-gate 				cp += len;
2057c478bd9Sstevel@tonic-gate 				continue;
2067c478bd9Sstevel@tonic-gate 			}
2077c478bd9Sstevel@tonic-gate 		}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		if (endcmd(c) && c != '"')
2107c478bd9Sstevel@tonic-gate 			break;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		c = getchar();
2137c478bd9Sstevel@tonic-gate 		switch (c) {
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 		case '\\':
2167c478bd9Sstevel@tonic-gate 			if (any(peekchar(), "#%|"))
2177c478bd9Sstevel@tonic-gate 				c = getchar();
218*9097ca5cSToomas Soome 			/* FALLTHROUGH */
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		default:
2217c478bd9Sstevel@tonic-gate 			if (cp > &genbuf[LBSIZE - 2])
2227c478bd9Sstevel@tonic-gate flong:
2237c478bd9Sstevel@tonic-gate 				error(gettext("Argument buffer overflow"));
2247c478bd9Sstevel@tonic-gate 			*cp++ = c;
2257c478bd9Sstevel@tonic-gate 			break;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		case '#':
2287c478bd9Sstevel@tonic-gate 			fp = (unsigned char *)altfile;
2297c478bd9Sstevel@tonic-gate 			if (*fp == 0)
2307c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
2317c478bd9Sstevel@tonic-gate gettext("No alternate filename") :
2327c478bd9Sstevel@tonic-gate gettext("No alternate filename to substitute for #"));
2337c478bd9Sstevel@tonic-gate 			goto filexp;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 		case '%':
2367c478bd9Sstevel@tonic-gate 			fp = savedfile;
2377c478bd9Sstevel@tonic-gate 			if (*fp == 0)
2387c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
2397c478bd9Sstevel@tonic-gate gettext("No current filename") :
2407c478bd9Sstevel@tonic-gate gettext("No current filename to substitute for %%"));
2417c478bd9Sstevel@tonic-gate filexp:
2427c478bd9Sstevel@tonic-gate 			while (*fp) {
2437c478bd9Sstevel@tonic-gate 				if (cp > &genbuf[LBSIZE - 2])
2447c478bd9Sstevel@tonic-gate 					goto flong;
2457c478bd9Sstevel@tonic-gate 				*cp++ = *fp++;
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 			break;
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 	*cp = 0;
2517c478bd9Sstevel@tonic-gate 	return (1);
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * Glob the argument words in genbuf, or if no globbing
2567c478bd9Sstevel@tonic-gate  * is implied, just split them up directly.
2577c478bd9Sstevel@tonic-gate  */
258f6db9f27Scf void
glob(struct glob * gp)259f6db9f27Scf glob(struct glob *gp)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	int pvec[2];
262f6db9f27Scf 	unsigned char **argv = gp->argv;
263f6db9f27Scf 	unsigned char *cp = gp->argspac;
264f6db9f27Scf 	int c;
2657c478bd9Sstevel@tonic-gate 	unsigned char ch;
2667c478bd9Sstevel@tonic-gate 	int nleft = NCARGS;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	gp->argc0 = 0;
2697c478bd9Sstevel@tonic-gate 	if (gscan() == 0) {
270f6db9f27Scf 		unsigned char *v = genbuf + 5;		/* strlen("echo ") */
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 		for (;;) {
2737c478bd9Sstevel@tonic-gate 			while (isspace(*v))
2747c478bd9Sstevel@tonic-gate 				v++;
2757c478bd9Sstevel@tonic-gate 			if (!*v)
2767c478bd9Sstevel@tonic-gate 				break;
2777c478bd9Sstevel@tonic-gate 			*argv++ = cp;
2787c478bd9Sstevel@tonic-gate 			while (*v && !isspace(*v))
2797c478bd9Sstevel@tonic-gate 				*cp++ = *v++;
2807c478bd9Sstevel@tonic-gate 			*cp++ = 0;
2817c478bd9Sstevel@tonic-gate 			gp->argc0++;
2827c478bd9Sstevel@tonic-gate 		}
2837c478bd9Sstevel@tonic-gate 		*argv = 0;
2847c478bd9Sstevel@tonic-gate 		return;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	if (pipe(pvec) < 0)
2877c478bd9Sstevel@tonic-gate 		error(gettext("Can't make pipe to glob"));
2887c478bd9Sstevel@tonic-gate 	pid = fork();
2897c478bd9Sstevel@tonic-gate 	io = pvec[0];
2907c478bd9Sstevel@tonic-gate 	if (pid < 0) {
2917c478bd9Sstevel@tonic-gate 		close(pvec[1]);
2927c478bd9Sstevel@tonic-gate 		error(gettext("Can't fork to do glob"));
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	if (pid == 0) {
2957c478bd9Sstevel@tonic-gate 		int oerrno;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		close(1);
2987c478bd9Sstevel@tonic-gate 		dup(pvec[1]);
2997c478bd9Sstevel@tonic-gate 		close(pvec[0]);
3007c478bd9Sstevel@tonic-gate 		close(2);	/* so errors don't mess up the screen */
3017c478bd9Sstevel@tonic-gate 		open("/dev/null", 1);
302f6db9f27Scf 		execlp((char *)svalue(vi_SHELL), "sh", "-c", genbuf, (char *)0);
3037c478bd9Sstevel@tonic-gate 		oerrno = errno; close(1); dup(2); errno = oerrno;
3047c478bd9Sstevel@tonic-gate 		filioerr(svalue(vi_SHELL));
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 	close(pvec[1]);
3077c478bd9Sstevel@tonic-gate 	do {
3087c478bd9Sstevel@tonic-gate 		*argv = cp;
3097c478bd9Sstevel@tonic-gate 		for (;;) {
3107c478bd9Sstevel@tonic-gate 			if (read(io, &ch, 1) != 1) {
3117c478bd9Sstevel@tonic-gate 				close(io);
3127c478bd9Sstevel@tonic-gate 				c = -1;
3137c478bd9Sstevel@tonic-gate 			} else
3147c478bd9Sstevel@tonic-gate 				c = ch;
3157c478bd9Sstevel@tonic-gate 			if (c <= 0 || isspace(c))
3167c478bd9Sstevel@tonic-gate 				break;
3177c478bd9Sstevel@tonic-gate 			*cp++ = c;
3187c478bd9Sstevel@tonic-gate 			if (--nleft <= 0)
3197c478bd9Sstevel@tonic-gate 				error(gettext("Arg list too long"));
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 		if (cp != *argv) {
3227c478bd9Sstevel@tonic-gate 			--nleft;
3237c478bd9Sstevel@tonic-gate 			*cp++ = 0;
3247c478bd9Sstevel@tonic-gate 			gp->argc0++;
3257c478bd9Sstevel@tonic-gate 			if (gp->argc0 >= NARGS)
3267c478bd9Sstevel@tonic-gate 				error(gettext("Arg list too long"));
3277c478bd9Sstevel@tonic-gate 			argv++;
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 	} while (c >= 0);
3307c478bd9Sstevel@tonic-gate 	waitfor();
3317c478bd9Sstevel@tonic-gate 	if (gp->argc0 == 0)
3327c478bd9Sstevel@tonic-gate 		error(gettext("No match"));
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * Scan genbuf for shell metacharacters.
3377c478bd9Sstevel@tonic-gate  * Set is union of v7 shell and csh metas.
3387c478bd9Sstevel@tonic-gate  */
339f6db9f27Scf int
gscan(void)340f6db9f27Scf gscan(void)
3417c478bd9Sstevel@tonic-gate {
342f6db9f27Scf 	unsigned char *cp;
3437c478bd9Sstevel@tonic-gate 	int	len;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	for (cp = genbuf; *cp; cp += len) {
3467c478bd9Sstevel@tonic-gate 		if (any(*cp, "~{[*?$`'\"\\"))
3477c478bd9Sstevel@tonic-gate 			return (1);
3487c478bd9Sstevel@tonic-gate 		if ((len = mblen((char *)cp, MB_CUR_MAX)) <= 0)
3497c478bd9Sstevel@tonic-gate 			len = 1;
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	return (0);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate /*
3557c478bd9Sstevel@tonic-gate  * Parse one filename into file.
3567c478bd9Sstevel@tonic-gate  */
3577c478bd9Sstevel@tonic-gate struct glob G;
358f6db9f27Scf void
getone(void)359f6db9f27Scf getone(void)
3607c478bd9Sstevel@tonic-gate {
361f6db9f27Scf 	unsigned char *str;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	if (getargs() == 0)
3647c478bd9Sstevel@tonic-gate 		error(gettext("Missing filename"));
3657c478bd9Sstevel@tonic-gate 	glob(&G);
3667c478bd9Sstevel@tonic-gate 	if (G.argc0 > 1)
3677c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Ambiguous") :
3687c478bd9Sstevel@tonic-gate gettext("Too many file names"));
3697c478bd9Sstevel@tonic-gate 	if (G.argc0 < 1)
3707c478bd9Sstevel@tonic-gate 		error(gettext("Missing filename"));
3717c478bd9Sstevel@tonic-gate 	str = G.argv[G.argc0 - 1];
3727c478bd9Sstevel@tonic-gate 	if (strlen(str) > FNSIZE - 4)
3737c478bd9Sstevel@tonic-gate 		error(gettext("Filename too long"));
3747c478bd9Sstevel@tonic-gate samef:
3757c478bd9Sstevel@tonic-gate 	CP(file, str);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate  * Read a file from the world.
3807c478bd9Sstevel@tonic-gate  * C is command, 'e' if this really an edit (or a recover).
3817c478bd9Sstevel@tonic-gate  */
382f6db9f27Scf void
rop(int c)383f6db9f27Scf rop(int c)
3847c478bd9Sstevel@tonic-gate {
385f6db9f27Scf 	int i;
3867c478bd9Sstevel@tonic-gate 	struct stat64 stbuf;
3877c478bd9Sstevel@tonic-gate 	short magic;
3887c478bd9Sstevel@tonic-gate 	static int ovro;	/* old value(vi_READONLY) */
3897c478bd9Sstevel@tonic-gate 	static int denied;	/* 1 if READONLY was set due to file permissions */
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	io = open(file, 0);
3927c478bd9Sstevel@tonic-gate 	if (io < 0) {
3937c478bd9Sstevel@tonic-gate 		if (c == 'e' && errno == ENOENT) {
3947c478bd9Sstevel@tonic-gate 			edited++;
3957c478bd9Sstevel@tonic-gate 			/*
39648bbca81SDaniel Hoffman 			 * If the user just did "ex foo" they're probably
3977c478bd9Sstevel@tonic-gate 			 * creating a new file.  Don't be an error, since
3987c478bd9Sstevel@tonic-gate 			 * this is ugly, and it messes up the + option.
3997c478bd9Sstevel@tonic-gate 			 */
4007c478bd9Sstevel@tonic-gate 			if (!seenprompt) {
401f6db9f27Scf 				viprintf(gettext(" [New file]"));
4027c478bd9Sstevel@tonic-gate 				noonl();
4037c478bd9Sstevel@tonic-gate 				return;
4047c478bd9Sstevel@tonic-gate 			}
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		if (value(vi_READONLY) && denied) {
4087c478bd9Sstevel@tonic-gate 			value(vi_READONLY) = ovro;
4097c478bd9Sstevel@tonic-gate 			denied = 0;
4107c478bd9Sstevel@tonic-gate 		}
4117c478bd9Sstevel@tonic-gate 		syserror(0);
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 	if (fstat64(io, &stbuf))
4147c478bd9Sstevel@tonic-gate 		syserror(0);
4157c478bd9Sstevel@tonic-gate 	switch (FTYPE(stbuf) & S_IFMT) {
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	case S_IFBLK:
4187c478bd9Sstevel@tonic-gate 		error(gettext(" Block special file"));
419*9097ca5cSToomas Soome 		/* FALLTHROUGH */
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	case S_IFCHR:
4227c478bd9Sstevel@tonic-gate 		if (isatty(io))
4237c478bd9Sstevel@tonic-gate 			error(gettext(" Teletype"));
4247c478bd9Sstevel@tonic-gate 		if (samei(&stbuf, "/dev/null"))
4257c478bd9Sstevel@tonic-gate 			break;
4267c478bd9Sstevel@tonic-gate 		error(gettext(" Character special file"));
427*9097ca5cSToomas Soome 		/* FALLTHROUGH */
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	case S_IFDIR:
4307c478bd9Sstevel@tonic-gate 		error(gettext(" Directory"));
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 	if (c != 'r') {
4347c478bd9Sstevel@tonic-gate 		if (value(vi_READONLY) && denied) {
4357c478bd9Sstevel@tonic-gate 			value(vi_READONLY) = ovro;
4367c478bd9Sstevel@tonic-gate 			denied = 0;
4377c478bd9Sstevel@tonic-gate 		}
438f6db9f27Scf 		if ((FMODE(stbuf) & 0222) == 0 || access((char *)file, 2) < 0) {
4397c478bd9Sstevel@tonic-gate 			ovro = value(vi_READONLY);
4407c478bd9Sstevel@tonic-gate 			denied = 1;
4417c478bd9Sstevel@tonic-gate 			value(vi_READONLY) = 1;
4427c478bd9Sstevel@tonic-gate 		}
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 	if (hush == 0 && value(vi_READONLY)) {
445f6db9f27Scf 		viprintf(gettext(" [Read only]"));
4467c478bd9Sstevel@tonic-gate 		flush();
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 	if (c == 'r')
4497c478bd9Sstevel@tonic-gate 		setdot();
4507c478bd9Sstevel@tonic-gate 	else
4517c478bd9Sstevel@tonic-gate 		setall();
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/* If it is a read command, then we must set dot to addr1
4547c478bd9Sstevel@tonic-gate 	 * (value of N in :Nr ).  In the default case, addr1 will
4557c478bd9Sstevel@tonic-gate 	 * already be set to dot.
45648bbca81SDaniel Hoffman 	 *
4577c478bd9Sstevel@tonic-gate 	 * Next, it is necessary to mark the beginning (undap1) and
4587c478bd9Sstevel@tonic-gate 	 * ending (undap2) addresses affected (for undo).  Note that
4597c478bd9Sstevel@tonic-gate 	 * rop2() and rop3() will adjust the value of undap2.
4607c478bd9Sstevel@tonic-gate 	 */
4617c478bd9Sstevel@tonic-gate 	if (FIXUNDO && inopen && c == 'r') {
4627c478bd9Sstevel@tonic-gate 		dot = addr1;
4637c478bd9Sstevel@tonic-gate 		undap1 = undap2 = dot + 1;
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	rop2();
4667c478bd9Sstevel@tonic-gate 	rop3(c);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
469f6db9f27Scf void
rop2(void)470f6db9f27Scf rop2(void)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	line *first, *last, *a;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	deletenone();
4757c478bd9Sstevel@tonic-gate 	clrstats();
4767c478bd9Sstevel@tonic-gate 	first = addr2 + 1;
4777c478bd9Sstevel@tonic-gate 	(void)append(getfile, addr2);
4787c478bd9Sstevel@tonic-gate 	last = dot;
4797c478bd9Sstevel@tonic-gate 	if (value(vi_MODELINES))
4807c478bd9Sstevel@tonic-gate 		for (a=first; a<=last; a++) {
4817c478bd9Sstevel@tonic-gate 			if (a==first+5 && last-first > 10)
4827c478bd9Sstevel@tonic-gate 				a = last - 4;
48323a1cceaSRoger A. Faulkner 			getaline(*a);
4847c478bd9Sstevel@tonic-gate 				chkmdln(linebuf);
4857c478bd9Sstevel@tonic-gate 		}
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
488f6db9f27Scf void
rop3(int c)489f6db9f27Scf rop3(int c)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	if (iostats() == 0 && c == 'e')
4937c478bd9Sstevel@tonic-gate 		edited++;
4947c478bd9Sstevel@tonic-gate 	if (c == 'e') {
4957c478bd9Sstevel@tonic-gate 		if (wasalt || firstpat) {
496f6db9f27Scf 			line *addr = zero + oldadot;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 			if (addr > dol)
4997c478bd9Sstevel@tonic-gate 				addr = dol;
5007c478bd9Sstevel@tonic-gate 			if (firstpat) {
5017c478bd9Sstevel@tonic-gate 				globp = (*firstpat) ? firstpat : (unsigned char *)"$";
5027c478bd9Sstevel@tonic-gate 				commands(1,1);
5037c478bd9Sstevel@tonic-gate 				firstpat = 0;
5047c478bd9Sstevel@tonic-gate 			} else if (addr >= one) {
5057c478bd9Sstevel@tonic-gate 				if (inopen)
5067c478bd9Sstevel@tonic-gate 					dot = addr;
5077c478bd9Sstevel@tonic-gate 				markpr(addr);
5087c478bd9Sstevel@tonic-gate 			} else
5097c478bd9Sstevel@tonic-gate 				goto other;
5107c478bd9Sstevel@tonic-gate 		} else
5117c478bd9Sstevel@tonic-gate other:
5127c478bd9Sstevel@tonic-gate 			if (dol > zero) {
5137c478bd9Sstevel@tonic-gate 				if (inopen)
5147c478bd9Sstevel@tonic-gate 					dot = one;
5157c478bd9Sstevel@tonic-gate 				markpr(one);
5167c478bd9Sstevel@tonic-gate 			}
5177c478bd9Sstevel@tonic-gate 		if(FIXUNDO)
5187c478bd9Sstevel@tonic-gate 			undkind = UNDNONE;
5197c478bd9Sstevel@tonic-gate 		if (inopen) {
5207c478bd9Sstevel@tonic-gate 			vcline = 0;
5217c478bd9Sstevel@tonic-gate 			vreplace(0, lines, lineDOL());
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 	if (laste) {
5257c478bd9Sstevel@tonic-gate #ifdef VMUNIX
5267c478bd9Sstevel@tonic-gate 		tlaste();
5277c478bd9Sstevel@tonic-gate #endif
5287c478bd9Sstevel@tonic-gate 		laste = 0;
5297c478bd9Sstevel@tonic-gate 		sync();
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate  * Are these two really the same inode?
5357c478bd9Sstevel@tonic-gate  */
536f6db9f27Scf int
samei(struct stat64 * sp,unsigned char * cp)537f6db9f27Scf samei(struct stat64 *sp, unsigned char *cp)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	struct stat64 stb;
5407c478bd9Sstevel@tonic-gate 
54148bbca81SDaniel Hoffman 	if (stat64((char *)cp, &stb) < 0)
5427c478bd9Sstevel@tonic-gate 		return (0);
5437c478bd9Sstevel@tonic-gate 	return (IDENTICAL((*sp), stb));
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate /* Returns from edited() */
5477c478bd9Sstevel@tonic-gate #define	EDF	0		/* Edited file */
5487c478bd9Sstevel@tonic-gate #define	NOTEDF	-1		/* Not edited file */
5497c478bd9Sstevel@tonic-gate #define	PARTBUF	1		/* Write of partial buffer to Edited file */
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate /*
5527c478bd9Sstevel@tonic-gate  * Write a file.
5537c478bd9Sstevel@tonic-gate  */
554f6db9f27Scf void
wop(dofname)5557c478bd9Sstevel@tonic-gate wop(dofname)
5567c478bd9Sstevel@tonic-gate bool dofname;	/* if 1 call filename, else use savedfile */
5577c478bd9Sstevel@tonic-gate {
558f6db9f27Scf 	int c, exclam, nonexist;
5597c478bd9Sstevel@tonic-gate 	line *saddr1, *saddr2;
5607c478bd9Sstevel@tonic-gate 	struct stat64 stbuf;
5617c478bd9Sstevel@tonic-gate 	char *messagep;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	c = 0;
5647c478bd9Sstevel@tonic-gate 	exclam = 0;
5657c478bd9Sstevel@tonic-gate 	if (dofname) {
5667c478bd9Sstevel@tonic-gate 		if (peekchar() == '!')
5677c478bd9Sstevel@tonic-gate 			exclam++, ignchar();
5687c478bd9Sstevel@tonic-gate 		(void)skipwh();
5697c478bd9Sstevel@tonic-gate 		while (peekchar() == '>')
5707c478bd9Sstevel@tonic-gate 			ignchar(), c++, (void)skipwh();
5717c478bd9Sstevel@tonic-gate 		if (c != 0 && c != 2)
5727c478bd9Sstevel@tonic-gate 			error(gettext("Write forms are 'w' and 'w>>'"));
5737c478bd9Sstevel@tonic-gate 		filename('w');
5747c478bd9Sstevel@tonic-gate 	} else {
5757c478bd9Sstevel@tonic-gate 		if (savedfile[0] == 0)
5767c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No file") :
5777c478bd9Sstevel@tonic-gate gettext("No current filename"));
5787c478bd9Sstevel@tonic-gate 		saddr1=addr1;
5797c478bd9Sstevel@tonic-gate 		saddr2=addr2;
5807c478bd9Sstevel@tonic-gate 		addr1=one;
5817c478bd9Sstevel@tonic-gate 		addr2=dol;
5827c478bd9Sstevel@tonic-gate 		CP(file, savedfile);
5837c478bd9Sstevel@tonic-gate 		if (inopen) {
5847c478bd9Sstevel@tonic-gate 			vclrech(0);
5857c478bd9Sstevel@tonic-gate 			splitw++;
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 		lprintf("\"%s\"", file);
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 	nonexist = stat64((char *)file, &stbuf);
5907c478bd9Sstevel@tonic-gate 	switch (c) {
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	case 0:
5937c478bd9Sstevel@tonic-gate 		if (!exclam && (!value(vi_WRITEANY) || value(vi_READONLY)))
5947c478bd9Sstevel@tonic-gate 		switch (edfile()) {
59548bbca81SDaniel Hoffman 
5967c478bd9Sstevel@tonic-gate 		case NOTEDF:
5977c478bd9Sstevel@tonic-gate 			if (nonexist)
5987c478bd9Sstevel@tonic-gate 				break;
5997c478bd9Sstevel@tonic-gate 			if (ISCHR(stbuf)) {
600f6db9f27Scf 				if (samei(&stbuf, (unsigned char *)"/dev/null"))
6017c478bd9Sstevel@tonic-gate 					break;
602f6db9f27Scf 				if (samei(&stbuf, (unsigned char *)"/dev/tty"))
6037c478bd9Sstevel@tonic-gate 					break;
6047c478bd9Sstevel@tonic-gate 			}
6057c478bd9Sstevel@tonic-gate 			io = open(file, 1);
6067c478bd9Sstevel@tonic-gate 			if (io < 0)
6077c478bd9Sstevel@tonic-gate 				syserror(0);
6087c478bd9Sstevel@tonic-gate 			if (!isatty(io))
609f6db9f27Scf 				serror(value(vi_TERSE) ?
610f6db9f27Scf 				    (unsigned char *)gettext(" File exists") :
611f6db9f27Scf (unsigned char *)gettext(" File exists - use \"w! %s\" to overwrite"),
612f6db9f27Scf 				    file);
6137c478bd9Sstevel@tonic-gate 			close(io);
6147c478bd9Sstevel@tonic-gate 			break;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 		case EDF:
6177c478bd9Sstevel@tonic-gate 			if (value(vi_READONLY))
6187c478bd9Sstevel@tonic-gate 				error(gettext(" File is read only"));
6197c478bd9Sstevel@tonic-gate 			break;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 		case PARTBUF:
6227c478bd9Sstevel@tonic-gate 			if (value(vi_READONLY))
6237c478bd9Sstevel@tonic-gate 				error(gettext(" File is read only"));
6247c478bd9Sstevel@tonic-gate 			error(gettext(" Use \"w!\" to write partial buffer"));
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate cre:
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate 		synctmp();
6297c478bd9Sstevel@tonic-gate */
6307c478bd9Sstevel@tonic-gate 		io = creat(file, 0666);
6317c478bd9Sstevel@tonic-gate 		if (io < 0)
6327c478bd9Sstevel@tonic-gate 			syserror(0);
6337c478bd9Sstevel@tonic-gate 		writing = 1;
6347c478bd9Sstevel@tonic-gate 		if (hush == 0)
6357c478bd9Sstevel@tonic-gate 			if (nonexist)
636f6db9f27Scf 				viprintf(gettext(" [New file]"));
6377c478bd9Sstevel@tonic-gate 			else if (value(vi_WRITEANY) && edfile() != EDF)
638f6db9f27Scf 				viprintf(gettext(" [Existing file]"));
6397c478bd9Sstevel@tonic-gate 		break;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	case 2:
6427c478bd9Sstevel@tonic-gate 		io = open(file, 1);
6437c478bd9Sstevel@tonic-gate 		if (io < 0) {
6447c478bd9Sstevel@tonic-gate 			if (exclam || value(vi_WRITEANY))
6457c478bd9Sstevel@tonic-gate 				goto cre;
6467c478bd9Sstevel@tonic-gate 			syserror(0);
6477c478bd9Sstevel@tonic-gate 		}
6487c478bd9Sstevel@tonic-gate 		lseek(io, 0l, 2);
6497c478bd9Sstevel@tonic-gate 		break;
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	if (write_quit && inopen && (argc == 0 || morargc == argc))
6527c478bd9Sstevel@tonic-gate 		setty(normf);
6537c478bd9Sstevel@tonic-gate 	putfile(0);
6547c478bd9Sstevel@tonic-gate 	if (fsync(io) < 0) {
655f6db9f27Scf 		/*
656f6db9f27Scf 		 * For NFS files write in putfile doesn't return error, but
657f6db9f27Scf 		 * fsync does.  So, catch it here.
658f6db9f27Scf 		 */
659f6db9f27Scf 		messagep = (char *)gettext(
660f6db9f27Scf 		    "\r\nYour file has been preserved\r\n");
661f6db9f27Scf 		(void) preserve();
662f6db9f27Scf 		write(1, messagep, strlen(messagep));
663f6db9f27Scf 
664f6db9f27Scf 		wrerror();
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 	(void)iostats();
6677c478bd9Sstevel@tonic-gate 	if (c != 2 && addr1 == one && addr2 == dol) {
6687c478bd9Sstevel@tonic-gate 		if (eq(file, savedfile))
6697c478bd9Sstevel@tonic-gate 			edited = 1;
6707c478bd9Sstevel@tonic-gate 		sync();
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 	if (!dofname) {
6737c478bd9Sstevel@tonic-gate 		addr1 = saddr1;
6747c478bd9Sstevel@tonic-gate 		addr2 = saddr2;
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 	writing = 0;
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate  * Is file the edited file?
6817c478bd9Sstevel@tonic-gate  * Work here is that it is not considered edited
6827c478bd9Sstevel@tonic-gate  * if this is a partial buffer, and distinguish
6837c478bd9Sstevel@tonic-gate  * all cases.
6847c478bd9Sstevel@tonic-gate  */
685f6db9f27Scf int
edfile(void)686f6db9f27Scf edfile(void)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	if (!edited || !eq(file, savedfile))
6907c478bd9Sstevel@tonic-gate 		return (NOTEDF);
6917c478bd9Sstevel@tonic-gate 	return (addr1 == one && addr2 == dol ? EDF : PARTBUF);
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate  * Extract the next line from the io stream.
6967c478bd9Sstevel@tonic-gate  */
6977c478bd9Sstevel@tonic-gate unsigned char *nextip;
6987c478bd9Sstevel@tonic-gate 
699f6db9f27Scf int
getfile(void)700f6db9f27Scf getfile(void)
7017c478bd9Sstevel@tonic-gate {
702f6db9f27Scf 	short c;
703f6db9f27Scf 	unsigned char *lp;
704f6db9f27Scf 	unsigned char *fp;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	lp = linebuf;
7077c478bd9Sstevel@tonic-gate 	fp = nextip;
7087c478bd9Sstevel@tonic-gate 	do {
7097c478bd9Sstevel@tonic-gate 		if (--ninbuf < 0) {
7107c478bd9Sstevel@tonic-gate 			ninbuf = read(io, genbuf, LBSIZE) - 1;
7117c478bd9Sstevel@tonic-gate 			if (ninbuf < 0) {
7127c478bd9Sstevel@tonic-gate 				if (lp != linebuf) {
7137c478bd9Sstevel@tonic-gate 					lp++;
714f6db9f27Scf 					viprintf(
715f6db9f27Scf 					    gettext(" [Incomplete last line]"));
7167c478bd9Sstevel@tonic-gate 					break;
7177c478bd9Sstevel@tonic-gate 				}
7187c478bd9Sstevel@tonic-gate 				return (EOF);
7197c478bd9Sstevel@tonic-gate 			}
7207c478bd9Sstevel@tonic-gate 			if(crflag == -1) {
7217c478bd9Sstevel@tonic-gate 				if(isencrypt(genbuf, ninbuf + 1))
7227c478bd9Sstevel@tonic-gate 					crflag = 2;
7237c478bd9Sstevel@tonic-gate 				else
7247c478bd9Sstevel@tonic-gate 					crflag = -2;
7257c478bd9Sstevel@tonic-gate 			}
7267c478bd9Sstevel@tonic-gate 			if (crflag > 0 && run_crypt(cntch, genbuf, ninbuf+1, perm) == -1) {
7277c478bd9Sstevel@tonic-gate 					smerror(gettext("Cannot decrypt block of text\n"));
7287c478bd9Sstevel@tonic-gate 					break;
7297c478bd9Sstevel@tonic-gate 			}
7307c478bd9Sstevel@tonic-gate 			fp = genbuf;
7317c478bd9Sstevel@tonic-gate 			cntch += ninbuf+1;
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 		if (lp >= &linebuf[LBSIZE]) {
7347c478bd9Sstevel@tonic-gate 			error(gettext(" Line too long"));
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 		c = *fp++;
7377c478bd9Sstevel@tonic-gate 		if (c == 0) {
7387c478bd9Sstevel@tonic-gate 			cntnull++;
7397c478bd9Sstevel@tonic-gate 			continue;
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 		*lp++ = c;
7427c478bd9Sstevel@tonic-gate 	} while (c != '\n');
7437c478bd9Sstevel@tonic-gate 	*--lp = 0;
7447c478bd9Sstevel@tonic-gate 	nextip = fp;
7457c478bd9Sstevel@tonic-gate 	cntln++;
7467c478bd9Sstevel@tonic-gate 	return (0);
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate  * Write a range onto the io stream.
7517c478bd9Sstevel@tonic-gate  */
752f6db9f27Scf void
putfile(int isfilter)7537c478bd9Sstevel@tonic-gate putfile(int isfilter)
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate 	line *a1;
756f6db9f27Scf 	unsigned char *lp;
757f6db9f27Scf 	unsigned char *fp;
758f6db9f27Scf 	int nib;
759f6db9f27Scf 	bool ochng = chng;
7607c478bd9Sstevel@tonic-gate 	char *messagep;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	chng = 1;		/* set to force file recovery procedures in */
7637c478bd9Sstevel@tonic-gate 				/* the event of an interrupt during write   */
7647c478bd9Sstevel@tonic-gate 	a1 = addr1;
7657c478bd9Sstevel@tonic-gate 	clrstats();
7667c478bd9Sstevel@tonic-gate 	cntln = addr2 - a1 + 1;
7677c478bd9Sstevel@tonic-gate 	nib = BUFSIZE;
7687c478bd9Sstevel@tonic-gate 	fp = genbuf;
7697c478bd9Sstevel@tonic-gate 	do {
77023a1cceaSRoger A. Faulkner 		getaline(*a1++);
7717c478bd9Sstevel@tonic-gate 		lp = linebuf;
7727c478bd9Sstevel@tonic-gate 		for (;;) {
7737c478bd9Sstevel@tonic-gate 			if (--nib < 0) {
7747c478bd9Sstevel@tonic-gate 				nib = fp - genbuf;
7757c478bd9Sstevel@tonic-gate                 		if(kflag && !isfilter)
7767c478bd9Sstevel@tonic-gate                                         if (run_crypt(cntch, genbuf, nib, perm) == -1)
7777c478bd9Sstevel@tonic-gate 					  wrerror();
7787c478bd9Sstevel@tonic-gate 				if (write(io, genbuf, nib) != nib) {
779f6db9f27Scf 				    messagep = (char *)gettext(
780f6db9f27Scf 					"\r\nYour file has been preserved\r\n");
781f6db9f27Scf 				    (void) preserve();
782f6db9f27Scf 				    write(1, messagep, strlen(messagep));
783f6db9f27Scf 
784f6db9f27Scf 				    if (!isfilter)
785f6db9f27Scf 					wrerror();
786f6db9f27Scf 				    return;
7877c478bd9Sstevel@tonic-gate 				}
7887c478bd9Sstevel@tonic-gate 				cntch += nib;
7897c478bd9Sstevel@tonic-gate 				nib = BUFSIZE - 1;
7907c478bd9Sstevel@tonic-gate 				fp = genbuf;
7917c478bd9Sstevel@tonic-gate 			}
7927c478bd9Sstevel@tonic-gate 			if ((*fp++ = *lp++) == 0) {
7937c478bd9Sstevel@tonic-gate 				fp[-1] = '\n';
7947c478bd9Sstevel@tonic-gate 				break;
7957c478bd9Sstevel@tonic-gate 			}
7967c478bd9Sstevel@tonic-gate 		}
7977c478bd9Sstevel@tonic-gate 	} while (a1 <= addr2);
7987c478bd9Sstevel@tonic-gate 	nib = fp - genbuf;
7997c478bd9Sstevel@tonic-gate 	if(kflag && !isfilter)
8007c478bd9Sstevel@tonic-gate 		if (run_crypt(cntch, genbuf, nib, perm) == -1)
8017c478bd9Sstevel@tonic-gate 			wrerror();
8027c478bd9Sstevel@tonic-gate 	if ((cntch == 0) && (nib == 1)) {
8037c478bd9Sstevel@tonic-gate 		cntln = 0;
8047c478bd9Sstevel@tonic-gate 		return;
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 	if (write(io, genbuf, nib) != nib) {
807f6db9f27Scf 		messagep = (char *)gettext(
808f6db9f27Scf 		    "\r\nYour file has been preserved\r\n");
809f6db9f27Scf 		(void) preserve();
810f6db9f27Scf 		write(1, messagep, strlen(messagep));
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		if(!isfilter)
8137c478bd9Sstevel@tonic-gate 			wrerror();
8147c478bd9Sstevel@tonic-gate 		return;
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 	cntch += nib;
8177c478bd9Sstevel@tonic-gate 	chng = ochng;			/* reset chng to original value */
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate  * A write error has occurred;  if the file being written was
8227c478bd9Sstevel@tonic-gate  * the edited file then we consider it to have changed since it is
8237c478bd9Sstevel@tonic-gate  * now likely scrambled.
8247c478bd9Sstevel@tonic-gate  */
825f6db9f27Scf void
wrerror(void)826f6db9f27Scf wrerror(void)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	if (eq(file, savedfile) && edited)
8307c478bd9Sstevel@tonic-gate 		change();
8317c478bd9Sstevel@tonic-gate 	syserror(1);
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate /*
8357c478bd9Sstevel@tonic-gate  * Source command, handles nested sources.
8367c478bd9Sstevel@tonic-gate  * Traps errors since it mungs unit 0 during the source.
8377c478bd9Sstevel@tonic-gate  */
8387c478bd9Sstevel@tonic-gate short slevel;
8397c478bd9Sstevel@tonic-gate short ttyindes;
8407c478bd9Sstevel@tonic-gate 
841f6db9f27Scf void
source(fil,okfail)8427c478bd9Sstevel@tonic-gate source(fil, okfail)
8437c478bd9Sstevel@tonic-gate 	unsigned char *fil;
8447c478bd9Sstevel@tonic-gate 	bool okfail;
8457c478bd9Sstevel@tonic-gate {
8467c478bd9Sstevel@tonic-gate 	jmp_buf osetexit;
847f6db9f27Scf 	int saveinp, ointty, oerrno;
8487c478bd9Sstevel@tonic-gate 	unsigned char *saveglobp;
8497c478bd9Sstevel@tonic-gate 	short savepeekc;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	signal(SIGINT, SIG_IGN);
8527c478bd9Sstevel@tonic-gate 	saveinp = dup(0);
8537c478bd9Sstevel@tonic-gate 	savepeekc = peekc;
8547c478bd9Sstevel@tonic-gate 	saveglobp = globp;
8557c478bd9Sstevel@tonic-gate 	peekc = 0; globp = 0;
8567c478bd9Sstevel@tonic-gate 	if (saveinp < 0)
8577c478bd9Sstevel@tonic-gate 		error(gettext("Too many nested sources"));
8587c478bd9Sstevel@tonic-gate 	if (slevel <= 0)
8597c478bd9Sstevel@tonic-gate 		ttyindes = saveinp;
8607c478bd9Sstevel@tonic-gate 	close(0);
8617c478bd9Sstevel@tonic-gate 	if (open(fil, 0) < 0) {
8627c478bd9Sstevel@tonic-gate 		oerrno = errno;
8637c478bd9Sstevel@tonic-gate 		setrupt();
8647c478bd9Sstevel@tonic-gate 		dup(saveinp);
8657c478bd9Sstevel@tonic-gate 		close(saveinp);
8667c478bd9Sstevel@tonic-gate 		errno = oerrno;
8677c478bd9Sstevel@tonic-gate 		if (!okfail)
8687c478bd9Sstevel@tonic-gate 			filioerr(fil);
8697c478bd9Sstevel@tonic-gate 		return;
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 	slevel++;
8727c478bd9Sstevel@tonic-gate 	ointty = intty;
8737c478bd9Sstevel@tonic-gate 	intty = isatty(0);
8747c478bd9Sstevel@tonic-gate 	oprompt = value(vi_PROMPT);
8757c478bd9Sstevel@tonic-gate 	value(vi_PROMPT) &= intty;
8767c478bd9Sstevel@tonic-gate 	getexit(osetexit);
8777c478bd9Sstevel@tonic-gate 	setrupt();
8787c478bd9Sstevel@tonic-gate 	if (setexit() == 0)
8797c478bd9Sstevel@tonic-gate 		commands(1, 1);
8807c478bd9Sstevel@tonic-gate 	else if (slevel > 1) {
8817c478bd9Sstevel@tonic-gate 		close(0);
8827c478bd9Sstevel@tonic-gate 		dup(saveinp);
8837c478bd9Sstevel@tonic-gate 		close(saveinp);
8847c478bd9Sstevel@tonic-gate 		slevel--;
8857c478bd9Sstevel@tonic-gate 		resexit(osetexit);
8867c478bd9Sstevel@tonic-gate 		reset();
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 	intty = ointty;
8897c478bd9Sstevel@tonic-gate 	value(vi_PROMPT) = oprompt;
8907c478bd9Sstevel@tonic-gate 	close(0);
8917c478bd9Sstevel@tonic-gate 	dup(saveinp);
8927c478bd9Sstevel@tonic-gate 	close(saveinp);
8937c478bd9Sstevel@tonic-gate 	globp = saveglobp;
8947c478bd9Sstevel@tonic-gate 	peekc = savepeekc;
8957c478bd9Sstevel@tonic-gate 	slevel--;
8967c478bd9Sstevel@tonic-gate 	resexit(osetexit);
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate /*
9007c478bd9Sstevel@tonic-gate  * Clear io statistics before a read or write.
9017c478bd9Sstevel@tonic-gate  */
902f6db9f27Scf void
clrstats(void)903f6db9f27Scf clrstats(void)
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	ninbuf = 0;
9077c478bd9Sstevel@tonic-gate 	cntch = 0;
9087c478bd9Sstevel@tonic-gate 	cntln = 0;
9097c478bd9Sstevel@tonic-gate 	cntnull = 0;
9107c478bd9Sstevel@tonic-gate 	cntodd = 0;
9117c478bd9Sstevel@tonic-gate }
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate /*
9147c478bd9Sstevel@tonic-gate  * Io is finished, close the unit and print statistics.
9157c478bd9Sstevel@tonic-gate  */
916f6db9f27Scf int
iostats(void)917f6db9f27Scf iostats(void)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	close(io);
9217c478bd9Sstevel@tonic-gate 	io = -1;
9227c478bd9Sstevel@tonic-gate 	if (hush == 0) {
9237c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE))
924f6db9f27Scf 			viprintf(" %d/%D", cntln, cntch);
9257c478bd9Sstevel@tonic-gate 		else if (cntln == 1 && cntch == 1) {
926f6db9f27Scf 			viprintf(gettext(" 1 line, 1 character"));
9277c478bd9Sstevel@tonic-gate 		} else if (cntln == 1 && cntch != 1) {
928f6db9f27Scf 			viprintf(gettext(" 1 line, %D characters"), cntch);
9297c478bd9Sstevel@tonic-gate 		} else if (cntln != 1 && cntch != 1) {
9307c478bd9Sstevel@tonic-gate 			/*
9317c478bd9Sstevel@tonic-gate 			 * TRANSLATION_NOTE
9327c478bd9Sstevel@tonic-gate 			 *	Reference order of arguments must not
9337c478bd9Sstevel@tonic-gate 			 *	be changed using '%digit$', since vi's
934f6db9f27Scf 			 *	viprintf() does not support it.
9357c478bd9Sstevel@tonic-gate 			 */
936f6db9f27Scf 			viprintf(gettext(" %d lines, %D characters"), cntln,
9377c478bd9Sstevel@tonic-gate 			    cntch);
9387c478bd9Sstevel@tonic-gate 		} else {
9397c478bd9Sstevel@tonic-gate 			/* ridiculous */
940f6db9f27Scf 			viprintf(gettext(" %d lines, 1 character"), cntln);
9417c478bd9Sstevel@tonic-gate 		}
9427c478bd9Sstevel@tonic-gate 		if (cntnull || cntodd) {
943f6db9f27Scf 			viprintf(" (");
9447c478bd9Sstevel@tonic-gate 			if (cntnull) {
945f6db9f27Scf 				viprintf(gettext("%D null"), cntnull);
9467c478bd9Sstevel@tonic-gate 				if (cntodd)
947f6db9f27Scf 					viprintf(", ");
9487c478bd9Sstevel@tonic-gate 			}
9497c478bd9Sstevel@tonic-gate 			if (cntodd)
950f6db9f27Scf 				viprintf(gettext("%D non-ASCII"), cntodd);
9517c478bd9Sstevel@tonic-gate 			putchar(')');
9527c478bd9Sstevel@tonic-gate 		}
9537c478bd9Sstevel@tonic-gate 		noonl();
9547c478bd9Sstevel@tonic-gate 		flush();
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 	return (cntnull != 0 || cntodd != 0);
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 
chkmdln(aline)9607c478bd9Sstevel@tonic-gate static void chkmdln(aline)
9617c478bd9Sstevel@tonic-gate unsigned char *aline;
9627c478bd9Sstevel@tonic-gate {
9637c478bd9Sstevel@tonic-gate 	unsigned char *beg, *end;
9647c478bd9Sstevel@tonic-gate 	unsigned char cmdbuf[1024];
9657c478bd9Sstevel@tonic-gate 	char *strchr(), *strrchr();
9667c478bd9Sstevel@tonic-gate 	bool savetty;
9677c478bd9Sstevel@tonic-gate 	int  savepeekc;
9687c478bd9Sstevel@tonic-gate 	int  savechng;
9697c478bd9Sstevel@tonic-gate 	unsigned char	*savefirstpat;
9707c478bd9Sstevel@tonic-gate 	unsigned char	*p;
9717c478bd9Sstevel@tonic-gate 	int	len;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	beg = (unsigned char *)strchr((char *)aline, ':');
9747c478bd9Sstevel@tonic-gate 	if (beg == NULL)
9757c478bd9Sstevel@tonic-gate 		return;
9767c478bd9Sstevel@tonic-gate 	if ((len = beg - aline) < 2)
9777c478bd9Sstevel@tonic-gate 		return;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	if ((beg - aline) != 2) {
9807c478bd9Sstevel@tonic-gate 		if ((p = beg - ((unsigned int)MB_CUR_MAX * 2) - 2) < aline)
9817c478bd9Sstevel@tonic-gate 			p = aline;
9827c478bd9Sstevel@tonic-gate 		for ( ; p < (beg - 2); p += len) {
9837c478bd9Sstevel@tonic-gate 			if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0)
9847c478bd9Sstevel@tonic-gate 				len = 1;
9857c478bd9Sstevel@tonic-gate 		}
9867c478bd9Sstevel@tonic-gate 		if (p !=  (beg - 2))
9877c478bd9Sstevel@tonic-gate 			return;
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	if (!((beg[-2] == 'e' && p[-1] == 'x')
9917c478bd9Sstevel@tonic-gate 	||    (beg[-2] == 'v' && beg[-1] == 'i')))
9927c478bd9Sstevel@tonic-gate 	 	return;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	strncpy(cmdbuf, beg+1, sizeof cmdbuf);
9957c478bd9Sstevel@tonic-gate 	end = (unsigned char *)strrchr(cmdbuf, ':');
9967c478bd9Sstevel@tonic-gate 	if (end == NULL)
9977c478bd9Sstevel@tonic-gate 		return;
9987c478bd9Sstevel@tonic-gate 	*end = 0;
9997c478bd9Sstevel@tonic-gate 	globp = cmdbuf;
10007c478bd9Sstevel@tonic-gate 	savepeekc = peekc;
10017c478bd9Sstevel@tonic-gate 	peekc = 0;
10027c478bd9Sstevel@tonic-gate 	savetty = intty;
10037c478bd9Sstevel@tonic-gate 	intty = 0;
10047c478bd9Sstevel@tonic-gate 	savechng = chng;
10057c478bd9Sstevel@tonic-gate 	savefirstpat = firstpat;
10067c478bd9Sstevel@tonic-gate 	firstpat = (unsigned char *)"";
10077c478bd9Sstevel@tonic-gate 	commands(1, 1);
10087c478bd9Sstevel@tonic-gate 	peekc = savepeekc;
10097c478bd9Sstevel@tonic-gate 	globp = 0;
10107c478bd9Sstevel@tonic-gate 	intty = savetty;
10117c478bd9Sstevel@tonic-gate 	/* chng being increased indicates that text was changed */
10127c478bd9Sstevel@tonic-gate 	if (savechng < chng)
10137c478bd9Sstevel@tonic-gate 		laste = 0;
10147c478bd9Sstevel@tonic-gate 	firstpat = savefirstpat;
10157c478bd9Sstevel@tonic-gate }
1016