xref: /titanic_50/usr/src/cmd/vi/port/ex_io.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
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
5*23a1cceaSRoger A. Faulkner  * Common Development and Distribution License (the "License").
6*23a1cceaSRoger 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  */
21*23a1cceaSRoger A. Faulkner 
22f6db9f27Scf46844 /*
23*23a1cceaSRoger A. Faulkner  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24f6db9f27Scf46844  */
25f6db9f27Scf46844 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "ex.h"
337c478bd9Sstevel@tonic-gate #include "ex_argv.h"
347c478bd9Sstevel@tonic-gate #include "ex_temp.h"
357c478bd9Sstevel@tonic-gate #include "ex_tty.h"
367c478bd9Sstevel@tonic-gate #include "ex_vis.h"
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
38f6db9f27Scf46844 #include <unistd.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * File input/output, source, preserve and recover
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  * Following remember where . was in the previous file for return
467c478bd9Sstevel@tonic-gate  * on file switching.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate int	altdot;
497c478bd9Sstevel@tonic-gate int	oldadot;
507c478bd9Sstevel@tonic-gate bool	wasalt;
517c478bd9Sstevel@tonic-gate short	isalt;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate long	cntch;			/* Count of characters on unit io */
547c478bd9Sstevel@tonic-gate #ifndef VMUNIX
557c478bd9Sstevel@tonic-gate short	cntln;			/* Count of lines " */
567c478bd9Sstevel@tonic-gate #else
577c478bd9Sstevel@tonic-gate int	cntln;
587c478bd9Sstevel@tonic-gate #endif
597c478bd9Sstevel@tonic-gate long	cntnull;		/* Count of nulls " */
607c478bd9Sstevel@tonic-gate long	cntodd;			/* Count of non-ascii characters " */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static void chkmdln();
63f6db9f27Scf46844 extern int	getchar();
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate  * Parse file name for command encoded by comm.
677c478bd9Sstevel@tonic-gate  * If comm is E then command is doomed and we are
687c478bd9Sstevel@tonic-gate  * parsing just so user won't have to retype the name.
697c478bd9Sstevel@tonic-gate  */
70f6db9f27Scf46844 void
filename(int comm)71f6db9f27Scf46844 filename(int comm)
727c478bd9Sstevel@tonic-gate {
73f6db9f27Scf46844 	int c = comm, d;
74f6db9f27Scf46844 	int i;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	d = getchar();
777c478bd9Sstevel@tonic-gate 	if (endcmd(d)) {
787c478bd9Sstevel@tonic-gate 		if (savedfile[0] == 0 && comm != 'f')
797c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No file") :
807c478bd9Sstevel@tonic-gate gettext("No current filename"));
817c478bd9Sstevel@tonic-gate 		CP(file, savedfile);
827c478bd9Sstevel@tonic-gate 		wasalt = (isalt > 0) ? isalt-1 : 0;
837c478bd9Sstevel@tonic-gate 		isalt = 0;
847c478bd9Sstevel@tonic-gate 		oldadot = altdot;
857c478bd9Sstevel@tonic-gate 		if (c == 'e' || c == 'E')
867c478bd9Sstevel@tonic-gate 			altdot = lineDOT();
877c478bd9Sstevel@tonic-gate 		if (d == EOF)
887c478bd9Sstevel@tonic-gate 			ungetchar(d);
897c478bd9Sstevel@tonic-gate 	} else {
907c478bd9Sstevel@tonic-gate 		ungetchar(d);
917c478bd9Sstevel@tonic-gate 		getone();
927c478bd9Sstevel@tonic-gate 		eol();
937c478bd9Sstevel@tonic-gate 		if (savedfile[0] == 0 && c != 'E' && c != 'e') {
947c478bd9Sstevel@tonic-gate 			c = 'e';
957c478bd9Sstevel@tonic-gate 			edited = 0;
967c478bd9Sstevel@tonic-gate 		}
977c478bd9Sstevel@tonic-gate 		wasalt = strcmp(file, altfile) == 0;
987c478bd9Sstevel@tonic-gate 		oldadot = altdot;
997c478bd9Sstevel@tonic-gate 		switch (c) {
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 		case 'f':
1027c478bd9Sstevel@tonic-gate 			edited = 0;
1037c478bd9Sstevel@tonic-gate 			/* fall into ... */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 		case 'e':
1067c478bd9Sstevel@tonic-gate 			if (savedfile[0]) {
1077c478bd9Sstevel@tonic-gate 				altdot = lineDOT();
1087c478bd9Sstevel@tonic-gate 				CP(altfile, savedfile);
1097c478bd9Sstevel@tonic-gate 			}
1107c478bd9Sstevel@tonic-gate 			CP(savedfile, file);
1117c478bd9Sstevel@tonic-gate 			break;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 		default:
1147c478bd9Sstevel@tonic-gate 			if (file[0]) {
1157c478bd9Sstevel@tonic-gate 				if (c != 'E')
1167c478bd9Sstevel@tonic-gate 					altdot = lineDOT();
1177c478bd9Sstevel@tonic-gate 				CP(altfile, file);
1187c478bd9Sstevel@tonic-gate 			}
1197c478bd9Sstevel@tonic-gate 			break;
1207c478bd9Sstevel@tonic-gate 		}
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 	if (hush && comm != 'f' || comm == 'E')
1237c478bd9Sstevel@tonic-gate 		return;
1247c478bd9Sstevel@tonic-gate 	if (file[0] != 0) {
1257c478bd9Sstevel@tonic-gate 		lprintf("\"%s\"", file);
1267c478bd9Sstevel@tonic-gate 		if (comm == 'f') {
1277c478bd9Sstevel@tonic-gate 			if (value(vi_READONLY))
128f6db9f27Scf46844 				viprintf(gettext(" [Read only]"));
1297c478bd9Sstevel@tonic-gate 			if (!edited)
130f6db9f27Scf46844 				viprintf(gettext(" [Not edited]"));
1317c478bd9Sstevel@tonic-gate 			if (tchng)
132f6db9f27Scf46844 				viprintf(gettext(" [Modified]"));
1337c478bd9Sstevel@tonic-gate 		}
1347c478bd9Sstevel@tonic-gate 		flush();
1357c478bd9Sstevel@tonic-gate 	} else
136f6db9f27Scf46844 		viprintf(gettext("No file "));
1377c478bd9Sstevel@tonic-gate 	if (comm == 'f') {
1387c478bd9Sstevel@tonic-gate 		if (!(i = lineDOL()))
1397c478bd9Sstevel@tonic-gate 			i++;
1407c478bd9Sstevel@tonic-gate 		/*
1417c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
1427c478bd9Sstevel@tonic-gate 		 *	Reference order of arguments must not
1437c478bd9Sstevel@tonic-gate 		 *	be changed using '%digit$', since vi's
144f6db9f27Scf46844 		 *	viprintf() does not support it.
1457c478bd9Sstevel@tonic-gate 		 */
146f6db9f27Scf46844 		viprintf(gettext(" line %d of %d --%ld%%--"), lineDOT(),
147f6db9f27Scf46844 		    lineDOL(), (long)(100 * lineDOT() / i));
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Get the argument words for a command into genbuf
1537c478bd9Sstevel@tonic-gate  * expanding # and %.
1547c478bd9Sstevel@tonic-gate  */
155f6db9f27Scf46844 int
getargs(void)156f6db9f27Scf46844 getargs(void)
1577c478bd9Sstevel@tonic-gate {
158f6db9f27Scf46844 	int c;
159f6db9f27Scf46844 	unsigned char *cp, *fp;
1607c478bd9Sstevel@tonic-gate 	static unsigned char fpatbuf[32];	/* hence limit on :next +/pat */
1617c478bd9Sstevel@tonic-gate 	char	multic[MB_LEN_MAX + 1];
1627c478bd9Sstevel@tonic-gate 	int	len;
1637c478bd9Sstevel@tonic-gate 	wchar_t	wc;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	pastwh();
1667c478bd9Sstevel@tonic-gate 	if (peekchar() == '+') {
1677c478bd9Sstevel@tonic-gate 		for (cp = fpatbuf;;) {
1687c478bd9Sstevel@tonic-gate 			if (!isascii(c = peekchar()) && (c != EOF)) {
1697c478bd9Sstevel@tonic-gate 				if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) {
1707c478bd9Sstevel@tonic-gate 					if ((cp + len) >= &fpatbuf[sizeof(fpatbuf)])
1717c478bd9Sstevel@tonic-gate 						error(gettext("Pattern too long"));
1727c478bd9Sstevel@tonic-gate 					strncpy(cp, multic, len);
1737c478bd9Sstevel@tonic-gate 					cp += len;
1747c478bd9Sstevel@tonic-gate 					continue;
1757c478bd9Sstevel@tonic-gate 				}
1767c478bd9Sstevel@tonic-gate 			}
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 			c = getchar();
1797c478bd9Sstevel@tonic-gate 			*cp++ = c;
1807c478bd9Sstevel@tonic-gate 			if (cp >= &fpatbuf[sizeof(fpatbuf)])
1817c478bd9Sstevel@tonic-gate 				error(gettext("Pattern too long"));
1827c478bd9Sstevel@tonic-gate 			if (c == '\\' && isspace(peekchar()))
1837c478bd9Sstevel@tonic-gate 				c = getchar();
1847c478bd9Sstevel@tonic-gate 			if (c == EOF || isspace(c)) {
1857c478bd9Sstevel@tonic-gate 				ungetchar(c);
1867c478bd9Sstevel@tonic-gate 				*--cp = 0;
1877c478bd9Sstevel@tonic-gate 				firstpat = &fpatbuf[1];
1887c478bd9Sstevel@tonic-gate 				break;
1897c478bd9Sstevel@tonic-gate 			}
1907c478bd9Sstevel@tonic-gate 		}
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 	if (skipend())
1937c478bd9Sstevel@tonic-gate 		return (0);
1947c478bd9Sstevel@tonic-gate 	CP(genbuf, "echo "); cp = &genbuf[5];
1957c478bd9Sstevel@tonic-gate 	for (;;) {
1967c478bd9Sstevel@tonic-gate 		if (!isascii(c = peekchar())) {
1977c478bd9Sstevel@tonic-gate 			if (endcmd(c) && c != '"')
1987c478bd9Sstevel@tonic-gate 				break;
1997c478bd9Sstevel@tonic-gate 			if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) {
2007c478bd9Sstevel@tonic-gate 				if ((cp + len) > &genbuf[LBSIZE - 2])
2017c478bd9Sstevel@tonic-gate 					error(gettext("Argument buffer overflow"));
2027c478bd9Sstevel@tonic-gate 				strncpy(cp, multic, len);
2037c478bd9Sstevel@tonic-gate 				cp += len;
2047c478bd9Sstevel@tonic-gate 				continue;
2057c478bd9Sstevel@tonic-gate 			}
2067c478bd9Sstevel@tonic-gate 		}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 		if (endcmd(c) && c != '"')
2097c478bd9Sstevel@tonic-gate 			break;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 		c = getchar();
2127c478bd9Sstevel@tonic-gate 		switch (c) {
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 		case '\\':
2157c478bd9Sstevel@tonic-gate 			if (any(peekchar(), "#%|"))
2167c478bd9Sstevel@tonic-gate 				c = getchar();
2177c478bd9Sstevel@tonic-gate 			/* fall into... */
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 		default:
2207c478bd9Sstevel@tonic-gate 			if (cp > &genbuf[LBSIZE - 2])
2217c478bd9Sstevel@tonic-gate flong:
2227c478bd9Sstevel@tonic-gate 				error(gettext("Argument buffer overflow"));
2237c478bd9Sstevel@tonic-gate 			*cp++ = c;
2247c478bd9Sstevel@tonic-gate 			break;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		case '#':
2277c478bd9Sstevel@tonic-gate 			fp = (unsigned char *)altfile;
2287c478bd9Sstevel@tonic-gate 			if (*fp == 0)
2297c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
2307c478bd9Sstevel@tonic-gate gettext("No alternate filename") :
2317c478bd9Sstevel@tonic-gate gettext("No alternate filename to substitute for #"));
2327c478bd9Sstevel@tonic-gate 			goto filexp;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		case '%':
2357c478bd9Sstevel@tonic-gate 			fp = savedfile;
2367c478bd9Sstevel@tonic-gate 			if (*fp == 0)
2377c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
2387c478bd9Sstevel@tonic-gate gettext("No current filename") :
2397c478bd9Sstevel@tonic-gate gettext("No current filename to substitute for %%"));
2407c478bd9Sstevel@tonic-gate filexp:
2417c478bd9Sstevel@tonic-gate 			while (*fp) {
2427c478bd9Sstevel@tonic-gate 				if (cp > &genbuf[LBSIZE - 2])
2437c478bd9Sstevel@tonic-gate 					goto flong;
2447c478bd9Sstevel@tonic-gate 				*cp++ = *fp++;
2457c478bd9Sstevel@tonic-gate 			}
2467c478bd9Sstevel@tonic-gate 			break;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	*cp = 0;
2507c478bd9Sstevel@tonic-gate 	return (1);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Glob the argument words in genbuf, or if no globbing
2557c478bd9Sstevel@tonic-gate  * is implied, just split them up directly.
2567c478bd9Sstevel@tonic-gate  */
257f6db9f27Scf46844 void
glob(struct glob * gp)258f6db9f27Scf46844 glob(struct glob *gp)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	int pvec[2];
261f6db9f27Scf46844 	unsigned char **argv = gp->argv;
262f6db9f27Scf46844 	unsigned char *cp = gp->argspac;
263f6db9f27Scf46844 	int c;
2647c478bd9Sstevel@tonic-gate 	unsigned char ch;
2657c478bd9Sstevel@tonic-gate 	int nleft = NCARGS;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	gp->argc0 = 0;
2687c478bd9Sstevel@tonic-gate 	if (gscan() == 0) {
269f6db9f27Scf46844 		unsigned char *v = genbuf + 5;		/* strlen("echo ") */
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		for (;;) {
2727c478bd9Sstevel@tonic-gate 			while (isspace(*v))
2737c478bd9Sstevel@tonic-gate 				v++;
2747c478bd9Sstevel@tonic-gate 			if (!*v)
2757c478bd9Sstevel@tonic-gate 				break;
2767c478bd9Sstevel@tonic-gate 			*argv++ = cp;
2777c478bd9Sstevel@tonic-gate 			while (*v && !isspace(*v))
2787c478bd9Sstevel@tonic-gate 				*cp++ = *v++;
2797c478bd9Sstevel@tonic-gate 			*cp++ = 0;
2807c478bd9Sstevel@tonic-gate 			gp->argc0++;
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 		*argv = 0;
2837c478bd9Sstevel@tonic-gate 		return;
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate 	if (pipe(pvec) < 0)
2867c478bd9Sstevel@tonic-gate 		error(gettext("Can't make pipe to glob"));
2877c478bd9Sstevel@tonic-gate 	pid = fork();
2887c478bd9Sstevel@tonic-gate 	io = pvec[0];
2897c478bd9Sstevel@tonic-gate 	if (pid < 0) {
2907c478bd9Sstevel@tonic-gate 		close(pvec[1]);
2917c478bd9Sstevel@tonic-gate 		error(gettext("Can't fork to do glob"));
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 	if (pid == 0) {
2947c478bd9Sstevel@tonic-gate 		int oerrno;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 		close(1);
2977c478bd9Sstevel@tonic-gate 		dup(pvec[1]);
2987c478bd9Sstevel@tonic-gate 		close(pvec[0]);
2997c478bd9Sstevel@tonic-gate 		close(2);	/* so errors don't mess up the screen */
3007c478bd9Sstevel@tonic-gate 		open("/dev/null", 1);
301f6db9f27Scf46844 		execlp((char *)svalue(vi_SHELL), "sh", "-c", genbuf, (char *)0);
3027c478bd9Sstevel@tonic-gate 		oerrno = errno; close(1); dup(2); errno = oerrno;
3037c478bd9Sstevel@tonic-gate 		filioerr(svalue(vi_SHELL));
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	close(pvec[1]);
3067c478bd9Sstevel@tonic-gate 	do {
3077c478bd9Sstevel@tonic-gate 		*argv = cp;
3087c478bd9Sstevel@tonic-gate 		for (;;) {
3097c478bd9Sstevel@tonic-gate 			if (read(io, &ch, 1) != 1) {
3107c478bd9Sstevel@tonic-gate 				close(io);
3117c478bd9Sstevel@tonic-gate 				c = -1;
3127c478bd9Sstevel@tonic-gate 			} else
3137c478bd9Sstevel@tonic-gate 				c = ch;
3147c478bd9Sstevel@tonic-gate 			if (c <= 0 || isspace(c))
3157c478bd9Sstevel@tonic-gate 				break;
3167c478bd9Sstevel@tonic-gate 			*cp++ = c;
3177c478bd9Sstevel@tonic-gate 			if (--nleft <= 0)
3187c478bd9Sstevel@tonic-gate 				error(gettext("Arg list too long"));
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 		if (cp != *argv) {
3217c478bd9Sstevel@tonic-gate 			--nleft;
3227c478bd9Sstevel@tonic-gate 			*cp++ = 0;
3237c478bd9Sstevel@tonic-gate 			gp->argc0++;
3247c478bd9Sstevel@tonic-gate 			if (gp->argc0 >= NARGS)
3257c478bd9Sstevel@tonic-gate 				error(gettext("Arg list too long"));
3267c478bd9Sstevel@tonic-gate 			argv++;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 	} while (c >= 0);
3297c478bd9Sstevel@tonic-gate 	waitfor();
3307c478bd9Sstevel@tonic-gate 	if (gp->argc0 == 0)
3317c478bd9Sstevel@tonic-gate 		error(gettext("No match"));
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate  * Scan genbuf for shell metacharacters.
3367c478bd9Sstevel@tonic-gate  * Set is union of v7 shell and csh metas.
3377c478bd9Sstevel@tonic-gate  */
338f6db9f27Scf46844 int
gscan(void)339f6db9f27Scf46844 gscan(void)
3407c478bd9Sstevel@tonic-gate {
341f6db9f27Scf46844 	unsigned char *cp;
3427c478bd9Sstevel@tonic-gate 	int	len;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	for (cp = genbuf; *cp; cp += len) {
3457c478bd9Sstevel@tonic-gate 		if (any(*cp, "~{[*?$`'\"\\"))
3467c478bd9Sstevel@tonic-gate 			return (1);
3477c478bd9Sstevel@tonic-gate 		if ((len = mblen((char *)cp, MB_CUR_MAX)) <= 0)
3487c478bd9Sstevel@tonic-gate 			len = 1;
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 	return (0);
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate  * Parse one filename into file.
3557c478bd9Sstevel@tonic-gate  */
3567c478bd9Sstevel@tonic-gate struct glob G;
357f6db9f27Scf46844 void
getone(void)358f6db9f27Scf46844 getone(void)
3597c478bd9Sstevel@tonic-gate {
360f6db9f27Scf46844 	unsigned char *str;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (getargs() == 0)
3637c478bd9Sstevel@tonic-gate 		error(gettext("Missing filename"));
3647c478bd9Sstevel@tonic-gate 	glob(&G);
3657c478bd9Sstevel@tonic-gate 	if (G.argc0 > 1)
3667c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ? gettext("Ambiguous") :
3677c478bd9Sstevel@tonic-gate gettext("Too many file names"));
3687c478bd9Sstevel@tonic-gate 	if (G.argc0 < 1)
3697c478bd9Sstevel@tonic-gate 		error(gettext("Missing filename"));
3707c478bd9Sstevel@tonic-gate 	str = G.argv[G.argc0 - 1];
3717c478bd9Sstevel@tonic-gate 	if (strlen(str) > FNSIZE - 4)
3727c478bd9Sstevel@tonic-gate 		error(gettext("Filename too long"));
3737c478bd9Sstevel@tonic-gate samef:
3747c478bd9Sstevel@tonic-gate 	CP(file, str);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /*
3787c478bd9Sstevel@tonic-gate  * Read a file from the world.
3797c478bd9Sstevel@tonic-gate  * C is command, 'e' if this really an edit (or a recover).
3807c478bd9Sstevel@tonic-gate  */
381f6db9f27Scf46844 void
rop(int c)382f6db9f27Scf46844 rop(int c)
3837c478bd9Sstevel@tonic-gate {
384f6db9f27Scf46844 	int i;
3857c478bd9Sstevel@tonic-gate 	struct stat64 stbuf;
3867c478bd9Sstevel@tonic-gate 	short magic;
3877c478bd9Sstevel@tonic-gate 	static int ovro;	/* old value(vi_READONLY) */
3887c478bd9Sstevel@tonic-gate 	static int denied;	/* 1 if READONLY was set due to file permissions */
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	io = open(file, 0);
3917c478bd9Sstevel@tonic-gate 	if (io < 0) {
3927c478bd9Sstevel@tonic-gate 		if (c == 'e' && errno == ENOENT) {
3937c478bd9Sstevel@tonic-gate 			edited++;
3947c478bd9Sstevel@tonic-gate 			/*
3957c478bd9Sstevel@tonic-gate 			 * If the user just did "ex foo" he is probably
3967c478bd9Sstevel@tonic-gate 			 * creating a new file.  Don't be an error, since
3977c478bd9Sstevel@tonic-gate 			 * this is ugly, and it messes up the + option.
3987c478bd9Sstevel@tonic-gate 			 */
3997c478bd9Sstevel@tonic-gate 			if (!seenprompt) {
400f6db9f27Scf46844 				viprintf(gettext(" [New file]"));
4017c478bd9Sstevel@tonic-gate 				noonl();
4027c478bd9Sstevel@tonic-gate 				return;
4037c478bd9Sstevel@tonic-gate 			}
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		if (value(vi_READONLY) && denied) {
4077c478bd9Sstevel@tonic-gate 			value(vi_READONLY) = ovro;
4087c478bd9Sstevel@tonic-gate 			denied = 0;
4097c478bd9Sstevel@tonic-gate 		}
4107c478bd9Sstevel@tonic-gate 		syserror(0);
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 	if (fstat64(io, &stbuf))
4137c478bd9Sstevel@tonic-gate 		syserror(0);
4147c478bd9Sstevel@tonic-gate 	switch (FTYPE(stbuf) & S_IFMT) {
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	case S_IFBLK:
4177c478bd9Sstevel@tonic-gate 		error(gettext(" Block special file"));
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	case S_IFCHR:
4207c478bd9Sstevel@tonic-gate 		if (isatty(io))
4217c478bd9Sstevel@tonic-gate 			error(gettext(" Teletype"));
4227c478bd9Sstevel@tonic-gate 		if (samei(&stbuf, "/dev/null"))
4237c478bd9Sstevel@tonic-gate 			break;
4247c478bd9Sstevel@tonic-gate 		error(gettext(" Character special file"));
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	case S_IFDIR:
4277c478bd9Sstevel@tonic-gate 		error(gettext(" Directory"));
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 	if (c != 'r') {
4317c478bd9Sstevel@tonic-gate 		if (value(vi_READONLY) && denied) {
4327c478bd9Sstevel@tonic-gate 			value(vi_READONLY) = ovro;
4337c478bd9Sstevel@tonic-gate 			denied = 0;
4347c478bd9Sstevel@tonic-gate 		}
435f6db9f27Scf46844 		if ((FMODE(stbuf) & 0222) == 0 || access((char *)file, 2) < 0) {
4367c478bd9Sstevel@tonic-gate 			ovro = value(vi_READONLY);
4377c478bd9Sstevel@tonic-gate 			denied = 1;
4387c478bd9Sstevel@tonic-gate 			value(vi_READONLY) = 1;
4397c478bd9Sstevel@tonic-gate 		}
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 	if (hush == 0 && value(vi_READONLY)) {
442f6db9f27Scf46844 		viprintf(gettext(" [Read only]"));
4437c478bd9Sstevel@tonic-gate 		flush();
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 	if (c == 'r')
4467c478bd9Sstevel@tonic-gate 		setdot();
4477c478bd9Sstevel@tonic-gate 	else
4487c478bd9Sstevel@tonic-gate 		setall();
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/* If it is a read command, then we must set dot to addr1
4517c478bd9Sstevel@tonic-gate 	 * (value of N in :Nr ).  In the default case, addr1 will
4527c478bd9Sstevel@tonic-gate 	 * already be set to dot.
4537c478bd9Sstevel@tonic-gate 	 *
4547c478bd9Sstevel@tonic-gate 	 * Next, it is necessary to mark the beginning (undap1) and
4557c478bd9Sstevel@tonic-gate 	 * ending (undap2) addresses affected (for undo).  Note that
4567c478bd9Sstevel@tonic-gate 	 * rop2() and rop3() will adjust the value of undap2.
4577c478bd9Sstevel@tonic-gate 	 */
4587c478bd9Sstevel@tonic-gate 	if (FIXUNDO && inopen && c == 'r') {
4597c478bd9Sstevel@tonic-gate 		dot = addr1;
4607c478bd9Sstevel@tonic-gate 		undap1 = undap2 = dot + 1;
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 	rop2();
4637c478bd9Sstevel@tonic-gate 	rop3(c);
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
466f6db9f27Scf46844 void
rop2(void)467f6db9f27Scf46844 rop2(void)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate 	line *first, *last, *a;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	deletenone();
4727c478bd9Sstevel@tonic-gate 	clrstats();
4737c478bd9Sstevel@tonic-gate 	first = addr2 + 1;
4747c478bd9Sstevel@tonic-gate 	(void)append(getfile, addr2);
4757c478bd9Sstevel@tonic-gate 	last = dot;
4767c478bd9Sstevel@tonic-gate 	if (value(vi_MODELINES))
4777c478bd9Sstevel@tonic-gate 		for (a=first; a<=last; a++) {
4787c478bd9Sstevel@tonic-gate 			if (a==first+5 && last-first > 10)
4797c478bd9Sstevel@tonic-gate 				a = last - 4;
480*23a1cceaSRoger A. Faulkner 			getaline(*a);
4817c478bd9Sstevel@tonic-gate 				chkmdln(linebuf);
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
485f6db9f27Scf46844 void
rop3(int c)486f6db9f27Scf46844 rop3(int c)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	if (iostats() == 0 && c == 'e')
4907c478bd9Sstevel@tonic-gate 		edited++;
4917c478bd9Sstevel@tonic-gate 	if (c == 'e') {
4927c478bd9Sstevel@tonic-gate 		if (wasalt || firstpat) {
493f6db9f27Scf46844 			line *addr = zero + oldadot;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 			if (addr > dol)
4967c478bd9Sstevel@tonic-gate 				addr = dol;
4977c478bd9Sstevel@tonic-gate 			if (firstpat) {
4987c478bd9Sstevel@tonic-gate 				globp = (*firstpat) ? firstpat : (unsigned char *)"$";
4997c478bd9Sstevel@tonic-gate 				commands(1,1);
5007c478bd9Sstevel@tonic-gate 				firstpat = 0;
5017c478bd9Sstevel@tonic-gate 			} else if (addr >= one) {
5027c478bd9Sstevel@tonic-gate 				if (inopen)
5037c478bd9Sstevel@tonic-gate 					dot = addr;
5047c478bd9Sstevel@tonic-gate 				markpr(addr);
5057c478bd9Sstevel@tonic-gate 			} else
5067c478bd9Sstevel@tonic-gate 				goto other;
5077c478bd9Sstevel@tonic-gate 		} else
5087c478bd9Sstevel@tonic-gate other:
5097c478bd9Sstevel@tonic-gate 			if (dol > zero) {
5107c478bd9Sstevel@tonic-gate 				if (inopen)
5117c478bd9Sstevel@tonic-gate 					dot = one;
5127c478bd9Sstevel@tonic-gate 				markpr(one);
5137c478bd9Sstevel@tonic-gate 			}
5147c478bd9Sstevel@tonic-gate 		if(FIXUNDO)
5157c478bd9Sstevel@tonic-gate 			undkind = UNDNONE;
5167c478bd9Sstevel@tonic-gate 		if (inopen) {
5177c478bd9Sstevel@tonic-gate 			vcline = 0;
5187c478bd9Sstevel@tonic-gate 			vreplace(0, lines, lineDOL());
5197c478bd9Sstevel@tonic-gate 		}
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 	if (laste) {
5227c478bd9Sstevel@tonic-gate #ifdef VMUNIX
5237c478bd9Sstevel@tonic-gate 		tlaste();
5247c478bd9Sstevel@tonic-gate #endif
5257c478bd9Sstevel@tonic-gate 		laste = 0;
5267c478bd9Sstevel@tonic-gate 		sync();
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate /*
5317c478bd9Sstevel@tonic-gate  * Are these two really the same inode?
5327c478bd9Sstevel@tonic-gate  */
533f6db9f27Scf46844 int
samei(struct stat64 * sp,unsigned char * cp)534f6db9f27Scf46844 samei(struct stat64 *sp, unsigned char *cp)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	struct stat64 stb;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	if (stat64((char *)cp, &stb) < 0)
5397c478bd9Sstevel@tonic-gate 		return (0);
5407c478bd9Sstevel@tonic-gate 	return (IDENTICAL((*sp), stb));
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate /* Returns from edited() */
5447c478bd9Sstevel@tonic-gate #define	EDF	0		/* Edited file */
5457c478bd9Sstevel@tonic-gate #define	NOTEDF	-1		/* Not edited file */
5467c478bd9Sstevel@tonic-gate #define	PARTBUF	1		/* Write of partial buffer to Edited file */
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate  * Write a file.
5507c478bd9Sstevel@tonic-gate  */
551f6db9f27Scf46844 void
wop(dofname)5527c478bd9Sstevel@tonic-gate wop(dofname)
5537c478bd9Sstevel@tonic-gate bool dofname;	/* if 1 call filename, else use savedfile */
5547c478bd9Sstevel@tonic-gate {
555f6db9f27Scf46844 	int c, exclam, nonexist;
5567c478bd9Sstevel@tonic-gate 	line *saddr1, *saddr2;
5577c478bd9Sstevel@tonic-gate 	struct stat64 stbuf;
5587c478bd9Sstevel@tonic-gate 	char *messagep;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	c = 0;
5617c478bd9Sstevel@tonic-gate 	exclam = 0;
5627c478bd9Sstevel@tonic-gate 	if (dofname) {
5637c478bd9Sstevel@tonic-gate 		if (peekchar() == '!')
5647c478bd9Sstevel@tonic-gate 			exclam++, ignchar();
5657c478bd9Sstevel@tonic-gate 		(void)skipwh();
5667c478bd9Sstevel@tonic-gate 		while (peekchar() == '>')
5677c478bd9Sstevel@tonic-gate 			ignchar(), c++, (void)skipwh();
5687c478bd9Sstevel@tonic-gate 		if (c != 0 && c != 2)
5697c478bd9Sstevel@tonic-gate 			error(gettext("Write forms are 'w' and 'w>>'"));
5707c478bd9Sstevel@tonic-gate 		filename('w');
5717c478bd9Sstevel@tonic-gate 	} else {
5727c478bd9Sstevel@tonic-gate 		if (savedfile[0] == 0)
5737c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No file") :
5747c478bd9Sstevel@tonic-gate gettext("No current filename"));
5757c478bd9Sstevel@tonic-gate 		saddr1=addr1;
5767c478bd9Sstevel@tonic-gate 		saddr2=addr2;
5777c478bd9Sstevel@tonic-gate 		addr1=one;
5787c478bd9Sstevel@tonic-gate 		addr2=dol;
5797c478bd9Sstevel@tonic-gate 		CP(file, savedfile);
5807c478bd9Sstevel@tonic-gate 		if (inopen) {
5817c478bd9Sstevel@tonic-gate 			vclrech(0);
5827c478bd9Sstevel@tonic-gate 			splitw++;
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 		lprintf("\"%s\"", file);
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 	nonexist = stat64((char *)file, &stbuf);
5877c478bd9Sstevel@tonic-gate 	switch (c) {
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	case 0:
5907c478bd9Sstevel@tonic-gate 		if (!exclam && (!value(vi_WRITEANY) || value(vi_READONLY)))
5917c478bd9Sstevel@tonic-gate 		switch (edfile()) {
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 		case NOTEDF:
5947c478bd9Sstevel@tonic-gate 			if (nonexist)
5957c478bd9Sstevel@tonic-gate 				break;
5967c478bd9Sstevel@tonic-gate 			if (ISCHR(stbuf)) {
597f6db9f27Scf46844 				if (samei(&stbuf, (unsigned char *)"/dev/null"))
5987c478bd9Sstevel@tonic-gate 					break;
599f6db9f27Scf46844 				if (samei(&stbuf, (unsigned char *)"/dev/tty"))
6007c478bd9Sstevel@tonic-gate 					break;
6017c478bd9Sstevel@tonic-gate 			}
6027c478bd9Sstevel@tonic-gate 			io = open(file, 1);
6037c478bd9Sstevel@tonic-gate 			if (io < 0)
6047c478bd9Sstevel@tonic-gate 				syserror(0);
6057c478bd9Sstevel@tonic-gate 			if (!isatty(io))
606f6db9f27Scf46844 				serror(value(vi_TERSE) ?
607f6db9f27Scf46844 				    (unsigned char *)gettext(" File exists") :
608f6db9f27Scf46844 (unsigned char *)gettext(" File exists - use \"w! %s\" to overwrite"),
609f6db9f27Scf46844 				    file);
6107c478bd9Sstevel@tonic-gate 			close(io);
6117c478bd9Sstevel@tonic-gate 			break;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 		case EDF:
6147c478bd9Sstevel@tonic-gate 			if (value(vi_READONLY))
6157c478bd9Sstevel@tonic-gate 				error(gettext(" File is read only"));
6167c478bd9Sstevel@tonic-gate 			break;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 		case PARTBUF:
6197c478bd9Sstevel@tonic-gate 			if (value(vi_READONLY))
6207c478bd9Sstevel@tonic-gate 				error(gettext(" File is read only"));
6217c478bd9Sstevel@tonic-gate 			error(gettext(" Use \"w!\" to write partial buffer"));
6227c478bd9Sstevel@tonic-gate 		}
6237c478bd9Sstevel@tonic-gate cre:
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate 		synctmp();
6267c478bd9Sstevel@tonic-gate */
6277c478bd9Sstevel@tonic-gate 		io = creat(file, 0666);
6287c478bd9Sstevel@tonic-gate 		if (io < 0)
6297c478bd9Sstevel@tonic-gate 			syserror(0);
6307c478bd9Sstevel@tonic-gate 		writing = 1;
6317c478bd9Sstevel@tonic-gate 		if (hush == 0)
6327c478bd9Sstevel@tonic-gate 			if (nonexist)
633f6db9f27Scf46844 				viprintf(gettext(" [New file]"));
6347c478bd9Sstevel@tonic-gate 			else if (value(vi_WRITEANY) && edfile() != EDF)
635f6db9f27Scf46844 				viprintf(gettext(" [Existing file]"));
6367c478bd9Sstevel@tonic-gate 		break;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	case 2:
6397c478bd9Sstevel@tonic-gate 		io = open(file, 1);
6407c478bd9Sstevel@tonic-gate 		if (io < 0) {
6417c478bd9Sstevel@tonic-gate 			if (exclam || value(vi_WRITEANY))
6427c478bd9Sstevel@tonic-gate 				goto cre;
6437c478bd9Sstevel@tonic-gate 			syserror(0);
6447c478bd9Sstevel@tonic-gate 		}
6457c478bd9Sstevel@tonic-gate 		lseek(io, 0l, 2);
6467c478bd9Sstevel@tonic-gate 		break;
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 	if (write_quit && inopen && (argc == 0 || morargc == argc))
6497c478bd9Sstevel@tonic-gate 		setty(normf);
6507c478bd9Sstevel@tonic-gate 	putfile(0);
6517c478bd9Sstevel@tonic-gate 	if (fsync(io) < 0) {
652f6db9f27Scf46844 		/*
653f6db9f27Scf46844 		 * For NFS files write in putfile doesn't return error, but
654f6db9f27Scf46844 		 * fsync does.  So, catch it here.
655f6db9f27Scf46844 		 */
656f6db9f27Scf46844 		messagep = (char *)gettext(
657f6db9f27Scf46844 		    "\r\nYour file has been preserved\r\n");
658f6db9f27Scf46844 		(void) preserve();
6597c478bd9Sstevel@tonic-gate 		write(1, messagep, strlen(messagep));
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		wrerror();
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 	(void)iostats();
6647c478bd9Sstevel@tonic-gate 	if (c != 2 && addr1 == one && addr2 == dol) {
6657c478bd9Sstevel@tonic-gate 		if (eq(file, savedfile))
6667c478bd9Sstevel@tonic-gate 			edited = 1;
6677c478bd9Sstevel@tonic-gate 		sync();
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 	if (!dofname) {
6707c478bd9Sstevel@tonic-gate 		addr1 = saddr1;
6717c478bd9Sstevel@tonic-gate 		addr2 = saddr2;
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 	writing = 0;
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate /*
6777c478bd9Sstevel@tonic-gate  * Is file the edited file?
6787c478bd9Sstevel@tonic-gate  * Work here is that it is not considered edited
6797c478bd9Sstevel@tonic-gate  * if this is a partial buffer, and distinguish
6807c478bd9Sstevel@tonic-gate  * all cases.
6817c478bd9Sstevel@tonic-gate  */
682f6db9f27Scf46844 int
edfile(void)683f6db9f27Scf46844 edfile(void)
6847c478bd9Sstevel@tonic-gate {
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	if (!edited || !eq(file, savedfile))
6877c478bd9Sstevel@tonic-gate 		return (NOTEDF);
6887c478bd9Sstevel@tonic-gate 	return (addr1 == one && addr2 == dol ? EDF : PARTBUF);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate  * Extract the next line from the io stream.
6937c478bd9Sstevel@tonic-gate  */
6947c478bd9Sstevel@tonic-gate unsigned char *nextip;
6957c478bd9Sstevel@tonic-gate 
696f6db9f27Scf46844 int
getfile(void)697f6db9f27Scf46844 getfile(void)
6987c478bd9Sstevel@tonic-gate {
699f6db9f27Scf46844 	short c;
700f6db9f27Scf46844 	unsigned char *lp;
701f6db9f27Scf46844 	unsigned char *fp;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	lp = linebuf;
7047c478bd9Sstevel@tonic-gate 	fp = nextip;
7057c478bd9Sstevel@tonic-gate 	do {
7067c478bd9Sstevel@tonic-gate 		if (--ninbuf < 0) {
7077c478bd9Sstevel@tonic-gate 			ninbuf = read(io, genbuf, LBSIZE) - 1;
7087c478bd9Sstevel@tonic-gate 			if (ninbuf < 0) {
7097c478bd9Sstevel@tonic-gate 				if (lp != linebuf) {
7107c478bd9Sstevel@tonic-gate 					lp++;
711f6db9f27Scf46844 					viprintf(
712f6db9f27Scf46844 					    gettext(" [Incomplete last line]"));
7137c478bd9Sstevel@tonic-gate 					break;
7147c478bd9Sstevel@tonic-gate 				}
7157c478bd9Sstevel@tonic-gate 				return (EOF);
7167c478bd9Sstevel@tonic-gate 			}
7177c478bd9Sstevel@tonic-gate 			if(crflag == -1) {
7187c478bd9Sstevel@tonic-gate 				if(isencrypt(genbuf, ninbuf + 1))
7197c478bd9Sstevel@tonic-gate 					crflag = 2;
7207c478bd9Sstevel@tonic-gate 				else
7217c478bd9Sstevel@tonic-gate 					crflag = -2;
7227c478bd9Sstevel@tonic-gate 			}
7237c478bd9Sstevel@tonic-gate 			if (crflag > 0 && run_crypt(cntch, genbuf, ninbuf+1, perm) == -1) {
7247c478bd9Sstevel@tonic-gate 					smerror(gettext("Cannot decrypt block of text\n"));
7257c478bd9Sstevel@tonic-gate 					break;
7267c478bd9Sstevel@tonic-gate 			}
7277c478bd9Sstevel@tonic-gate 			fp = genbuf;
7287c478bd9Sstevel@tonic-gate 			cntch += ninbuf+1;
7297c478bd9Sstevel@tonic-gate 		}
7307c478bd9Sstevel@tonic-gate 		if (lp >= &linebuf[LBSIZE]) {
7317c478bd9Sstevel@tonic-gate 			error(gettext(" Line too long"));
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 		c = *fp++;
7347c478bd9Sstevel@tonic-gate 		if (c == 0) {
7357c478bd9Sstevel@tonic-gate 			cntnull++;
7367c478bd9Sstevel@tonic-gate 			continue;
7377c478bd9Sstevel@tonic-gate 		}
7387c478bd9Sstevel@tonic-gate 		*lp++ = c;
7397c478bd9Sstevel@tonic-gate 	} while (c != '\n');
7407c478bd9Sstevel@tonic-gate 	*--lp = 0;
7417c478bd9Sstevel@tonic-gate 	nextip = fp;
7427c478bd9Sstevel@tonic-gate 	cntln++;
7437c478bd9Sstevel@tonic-gate 	return (0);
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate /*
7477c478bd9Sstevel@tonic-gate  * Write a range onto the io stream.
7487c478bd9Sstevel@tonic-gate  */
749f6db9f27Scf46844 void
putfile(int isfilter)7507c478bd9Sstevel@tonic-gate putfile(int isfilter)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	line *a1;
753f6db9f27Scf46844 	unsigned char *lp;
754f6db9f27Scf46844 	unsigned char *fp;
755f6db9f27Scf46844 	int nib;
756f6db9f27Scf46844 	bool ochng = chng;
7577c478bd9Sstevel@tonic-gate 	char *messagep;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	chng = 1;		/* set to force file recovery procedures in */
7607c478bd9Sstevel@tonic-gate 				/* the event of an interrupt during write   */
7617c478bd9Sstevel@tonic-gate 	a1 = addr1;
7627c478bd9Sstevel@tonic-gate 	clrstats();
7637c478bd9Sstevel@tonic-gate 	cntln = addr2 - a1 + 1;
7647c478bd9Sstevel@tonic-gate 	nib = BUFSIZE;
7657c478bd9Sstevel@tonic-gate 	fp = genbuf;
7667c478bd9Sstevel@tonic-gate 	do {
767*23a1cceaSRoger A. Faulkner 		getaline(*a1++);
7687c478bd9Sstevel@tonic-gate 		lp = linebuf;
7697c478bd9Sstevel@tonic-gate 		for (;;) {
7707c478bd9Sstevel@tonic-gate 			if (--nib < 0) {
7717c478bd9Sstevel@tonic-gate 				nib = fp - genbuf;
7727c478bd9Sstevel@tonic-gate                 		if(kflag && !isfilter)
7737c478bd9Sstevel@tonic-gate                                         if (run_crypt(cntch, genbuf, nib, perm) == -1)
7747c478bd9Sstevel@tonic-gate 					  wrerror();
7757c478bd9Sstevel@tonic-gate 				if (write(io, genbuf, nib) != nib) {
776f6db9f27Scf46844 				    messagep = (char *)gettext(
777f6db9f27Scf46844 					"\r\nYour file has been preserved\r\n");
778f6db9f27Scf46844 				    (void) preserve();
7797c478bd9Sstevel@tonic-gate 				    write(1, messagep, strlen(messagep));
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 				    if (!isfilter)
7827c478bd9Sstevel@tonic-gate 					wrerror();
7837c478bd9Sstevel@tonic-gate 				    return;
7847c478bd9Sstevel@tonic-gate 				}
7857c478bd9Sstevel@tonic-gate 				cntch += nib;
7867c478bd9Sstevel@tonic-gate 				nib = BUFSIZE - 1;
7877c478bd9Sstevel@tonic-gate 				fp = genbuf;
7887c478bd9Sstevel@tonic-gate 			}
7897c478bd9Sstevel@tonic-gate 			if ((*fp++ = *lp++) == 0) {
7907c478bd9Sstevel@tonic-gate 				fp[-1] = '\n';
7917c478bd9Sstevel@tonic-gate 				break;
7927c478bd9Sstevel@tonic-gate 			}
7937c478bd9Sstevel@tonic-gate 		}
7947c478bd9Sstevel@tonic-gate 	} while (a1 <= addr2);
7957c478bd9Sstevel@tonic-gate 	nib = fp - genbuf;
7967c478bd9Sstevel@tonic-gate 	if(kflag && !isfilter)
7977c478bd9Sstevel@tonic-gate 		if (run_crypt(cntch, genbuf, nib, perm) == -1)
7987c478bd9Sstevel@tonic-gate 			wrerror();
7997c478bd9Sstevel@tonic-gate 	if ((cntch == 0) && (nib == 1)) {
8007c478bd9Sstevel@tonic-gate 		cntln = 0;
8017c478bd9Sstevel@tonic-gate 		return;
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 	if (write(io, genbuf, nib) != nib) {
804f6db9f27Scf46844 		messagep = (char *)gettext(
805f6db9f27Scf46844 		    "\r\nYour file has been preserved\r\n");
806f6db9f27Scf46844 		(void) preserve();
8077c478bd9Sstevel@tonic-gate 		write(1, messagep, strlen(messagep));
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 		if(!isfilter)
8107c478bd9Sstevel@tonic-gate 			wrerror();
8117c478bd9Sstevel@tonic-gate 		return;
8127c478bd9Sstevel@tonic-gate 	}
8137c478bd9Sstevel@tonic-gate 	cntch += nib;
8147c478bd9Sstevel@tonic-gate 	chng = ochng;			/* reset chng to original value */
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate /*
8187c478bd9Sstevel@tonic-gate  * A write error has occurred;  if the file being written was
8197c478bd9Sstevel@tonic-gate  * the edited file then we consider it to have changed since it is
8207c478bd9Sstevel@tonic-gate  * now likely scrambled.
8217c478bd9Sstevel@tonic-gate  */
822f6db9f27Scf46844 void
wrerror(void)823f6db9f27Scf46844 wrerror(void)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	if (eq(file, savedfile) && edited)
8277c478bd9Sstevel@tonic-gate 		change();
8287c478bd9Sstevel@tonic-gate 	syserror(1);
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate /*
8327c478bd9Sstevel@tonic-gate  * Source command, handles nested sources.
8337c478bd9Sstevel@tonic-gate  * Traps errors since it mungs unit 0 during the source.
8347c478bd9Sstevel@tonic-gate  */
8357c478bd9Sstevel@tonic-gate short slevel;
8367c478bd9Sstevel@tonic-gate short ttyindes;
8377c478bd9Sstevel@tonic-gate 
838f6db9f27Scf46844 void
source(fil,okfail)8397c478bd9Sstevel@tonic-gate source(fil, okfail)
8407c478bd9Sstevel@tonic-gate 	unsigned char *fil;
8417c478bd9Sstevel@tonic-gate 	bool okfail;
8427c478bd9Sstevel@tonic-gate {
8437c478bd9Sstevel@tonic-gate 	jmp_buf osetexit;
844f6db9f27Scf46844 	int saveinp, ointty, oerrno;
8457c478bd9Sstevel@tonic-gate 	unsigned char *saveglobp;
8467c478bd9Sstevel@tonic-gate 	short savepeekc;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	signal(SIGINT, SIG_IGN);
8497c478bd9Sstevel@tonic-gate 	saveinp = dup(0);
8507c478bd9Sstevel@tonic-gate 	savepeekc = peekc;
8517c478bd9Sstevel@tonic-gate 	saveglobp = globp;
8527c478bd9Sstevel@tonic-gate 	peekc = 0; globp = 0;
8537c478bd9Sstevel@tonic-gate 	if (saveinp < 0)
8547c478bd9Sstevel@tonic-gate 		error(gettext("Too many nested sources"));
8557c478bd9Sstevel@tonic-gate 	if (slevel <= 0)
8567c478bd9Sstevel@tonic-gate 		ttyindes = saveinp;
8577c478bd9Sstevel@tonic-gate 	close(0);
8587c478bd9Sstevel@tonic-gate 	if (open(fil, 0) < 0) {
8597c478bd9Sstevel@tonic-gate 		oerrno = errno;
8607c478bd9Sstevel@tonic-gate 		setrupt();
8617c478bd9Sstevel@tonic-gate 		dup(saveinp);
8627c478bd9Sstevel@tonic-gate 		close(saveinp);
8637c478bd9Sstevel@tonic-gate 		errno = oerrno;
8647c478bd9Sstevel@tonic-gate 		if (!okfail)
8657c478bd9Sstevel@tonic-gate 			filioerr(fil);
8667c478bd9Sstevel@tonic-gate 		return;
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate 	slevel++;
8697c478bd9Sstevel@tonic-gate 	ointty = intty;
8707c478bd9Sstevel@tonic-gate 	intty = isatty(0);
8717c478bd9Sstevel@tonic-gate 	oprompt = value(vi_PROMPT);
8727c478bd9Sstevel@tonic-gate 	value(vi_PROMPT) &= intty;
8737c478bd9Sstevel@tonic-gate 	getexit(osetexit);
8747c478bd9Sstevel@tonic-gate 	setrupt();
8757c478bd9Sstevel@tonic-gate 	if (setexit() == 0)
8767c478bd9Sstevel@tonic-gate 		commands(1, 1);
8777c478bd9Sstevel@tonic-gate 	else if (slevel > 1) {
8787c478bd9Sstevel@tonic-gate 		close(0);
8797c478bd9Sstevel@tonic-gate 		dup(saveinp);
8807c478bd9Sstevel@tonic-gate 		close(saveinp);
8817c478bd9Sstevel@tonic-gate 		slevel--;
8827c478bd9Sstevel@tonic-gate 		resexit(osetexit);
8837c478bd9Sstevel@tonic-gate 		reset();
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 	intty = ointty;
8867c478bd9Sstevel@tonic-gate 	value(vi_PROMPT) = oprompt;
8877c478bd9Sstevel@tonic-gate 	close(0);
8887c478bd9Sstevel@tonic-gate 	dup(saveinp);
8897c478bd9Sstevel@tonic-gate 	close(saveinp);
8907c478bd9Sstevel@tonic-gate 	globp = saveglobp;
8917c478bd9Sstevel@tonic-gate 	peekc = savepeekc;
8927c478bd9Sstevel@tonic-gate 	slevel--;
8937c478bd9Sstevel@tonic-gate 	resexit(osetexit);
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate /*
8977c478bd9Sstevel@tonic-gate  * Clear io statistics before a read or write.
8987c478bd9Sstevel@tonic-gate  */
899f6db9f27Scf46844 void
clrstats(void)900f6db9f27Scf46844 clrstats(void)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	ninbuf = 0;
9047c478bd9Sstevel@tonic-gate 	cntch = 0;
9057c478bd9Sstevel@tonic-gate 	cntln = 0;
9067c478bd9Sstevel@tonic-gate 	cntnull = 0;
9077c478bd9Sstevel@tonic-gate 	cntodd = 0;
9087c478bd9Sstevel@tonic-gate }
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate /*
9117c478bd9Sstevel@tonic-gate  * Io is finished, close the unit and print statistics.
9127c478bd9Sstevel@tonic-gate  */
913f6db9f27Scf46844 int
iostats(void)914f6db9f27Scf46844 iostats(void)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	close(io);
9187c478bd9Sstevel@tonic-gate 	io = -1;
9197c478bd9Sstevel@tonic-gate 	if (hush == 0) {
9207c478bd9Sstevel@tonic-gate 		if (value(vi_TERSE))
921f6db9f27Scf46844 			viprintf(" %d/%D", cntln, cntch);
9227c478bd9Sstevel@tonic-gate 		else if (cntln == 1 && cntch == 1) {
923f6db9f27Scf46844 			viprintf(gettext(" 1 line, 1 character"));
9247c478bd9Sstevel@tonic-gate 		} else if (cntln == 1 && cntch != 1) {
925f6db9f27Scf46844 			viprintf(gettext(" 1 line, %D characters"), cntch);
9267c478bd9Sstevel@tonic-gate 		} else if (cntln != 1 && cntch != 1) {
9277c478bd9Sstevel@tonic-gate 			/*
9287c478bd9Sstevel@tonic-gate 			 * TRANSLATION_NOTE
9297c478bd9Sstevel@tonic-gate 			 *	Reference order of arguments must not
9307c478bd9Sstevel@tonic-gate 			 *	be changed using '%digit$', since vi's
931f6db9f27Scf46844 			 *	viprintf() does not support it.
9327c478bd9Sstevel@tonic-gate 			 */
933f6db9f27Scf46844 			viprintf(gettext(" %d lines, %D characters"), cntln,
9347c478bd9Sstevel@tonic-gate 			    cntch);
9357c478bd9Sstevel@tonic-gate 		} else {
9367c478bd9Sstevel@tonic-gate 			/* ridiculous */
937f6db9f27Scf46844 			viprintf(gettext(" %d lines, 1 character"), cntln);
9387c478bd9Sstevel@tonic-gate 		}
9397c478bd9Sstevel@tonic-gate 		if (cntnull || cntodd) {
940f6db9f27Scf46844 			viprintf(" (");
9417c478bd9Sstevel@tonic-gate 			if (cntnull) {
942f6db9f27Scf46844 				viprintf(gettext("%D null"), cntnull);
9437c478bd9Sstevel@tonic-gate 				if (cntodd)
944f6db9f27Scf46844 					viprintf(", ");
9457c478bd9Sstevel@tonic-gate 			}
9467c478bd9Sstevel@tonic-gate 			if (cntodd)
947f6db9f27Scf46844 				viprintf(gettext("%D non-ASCII"), cntodd);
9487c478bd9Sstevel@tonic-gate 			putchar(')');
9497c478bd9Sstevel@tonic-gate 		}
9507c478bd9Sstevel@tonic-gate 		noonl();
9517c478bd9Sstevel@tonic-gate 		flush();
9527c478bd9Sstevel@tonic-gate 	}
9537c478bd9Sstevel@tonic-gate 	return (cntnull != 0 || cntodd != 0);
9547c478bd9Sstevel@tonic-gate }
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 
chkmdln(aline)9577c478bd9Sstevel@tonic-gate static void chkmdln(aline)
9587c478bd9Sstevel@tonic-gate unsigned char *aline;
9597c478bd9Sstevel@tonic-gate {
9607c478bd9Sstevel@tonic-gate 	unsigned char *beg, *end;
9617c478bd9Sstevel@tonic-gate 	unsigned char cmdbuf[1024];
9627c478bd9Sstevel@tonic-gate 	char *strchr(), *strrchr();
9637c478bd9Sstevel@tonic-gate 	bool savetty;
9647c478bd9Sstevel@tonic-gate 	int  savepeekc;
9657c478bd9Sstevel@tonic-gate 	int  savechng;
9667c478bd9Sstevel@tonic-gate 	unsigned char	*savefirstpat;
9677c478bd9Sstevel@tonic-gate 	unsigned char	*p;
9687c478bd9Sstevel@tonic-gate 	int	len;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	beg = (unsigned char *)strchr((char *)aline, ':');
9717c478bd9Sstevel@tonic-gate 	if (beg == NULL)
9727c478bd9Sstevel@tonic-gate 		return;
9737c478bd9Sstevel@tonic-gate 	if ((len = beg - aline) < 2)
9747c478bd9Sstevel@tonic-gate 		return;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	if ((beg - aline) != 2) {
9777c478bd9Sstevel@tonic-gate 		if ((p = beg - ((unsigned int)MB_CUR_MAX * 2) - 2) < aline)
9787c478bd9Sstevel@tonic-gate 			p = aline;
9797c478bd9Sstevel@tonic-gate 		for ( ; p < (beg - 2); p += len) {
9807c478bd9Sstevel@tonic-gate 			if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0)
9817c478bd9Sstevel@tonic-gate 				len = 1;
9827c478bd9Sstevel@tonic-gate 		}
9837c478bd9Sstevel@tonic-gate 		if (p !=  (beg - 2))
9847c478bd9Sstevel@tonic-gate 			return;
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	if (!((beg[-2] == 'e' && p[-1] == 'x')
9887c478bd9Sstevel@tonic-gate 	||    (beg[-2] == 'v' && beg[-1] == 'i')))
9897c478bd9Sstevel@tonic-gate 	 	return;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	strncpy(cmdbuf, beg+1, sizeof cmdbuf);
9927c478bd9Sstevel@tonic-gate 	end = (unsigned char *)strrchr(cmdbuf, ':');
9937c478bd9Sstevel@tonic-gate 	if (end == NULL)
9947c478bd9Sstevel@tonic-gate 		return;
9957c478bd9Sstevel@tonic-gate 	*end = 0;
9967c478bd9Sstevel@tonic-gate 	globp = cmdbuf;
9977c478bd9Sstevel@tonic-gate 	savepeekc = peekc;
9987c478bd9Sstevel@tonic-gate 	peekc = 0;
9997c478bd9Sstevel@tonic-gate 	savetty = intty;
10007c478bd9Sstevel@tonic-gate 	intty = 0;
10017c478bd9Sstevel@tonic-gate 	savechng = chng;
10027c478bd9Sstevel@tonic-gate 	savefirstpat = firstpat;
10037c478bd9Sstevel@tonic-gate 	firstpat = (unsigned char *)"";
10047c478bd9Sstevel@tonic-gate 	commands(1, 1);
10057c478bd9Sstevel@tonic-gate 	peekc = savepeekc;
10067c478bd9Sstevel@tonic-gate 	globp = 0;
10077c478bd9Sstevel@tonic-gate 	intty = savetty;
10087c478bd9Sstevel@tonic-gate 	/* chng being increased indicates that text was changed */
10097c478bd9Sstevel@tonic-gate 	if (savechng < chng)
10107c478bd9Sstevel@tonic-gate 		laste = 0;
10117c478bd9Sstevel@tonic-gate 	firstpat = savefirstpat;
10127c478bd9Sstevel@tonic-gate }
1013