xref: /illumos-gate/usr/src/cmd/vi/port/ex.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include "ex.h"
35*7c478bd9Sstevel@tonic-gate #include "ex_argv.h"
36*7c478bd9Sstevel@tonic-gate #include "ex_temp.h"
37*7c478bd9Sstevel@tonic-gate #include "ex_tty.h"
38*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
39*7c478bd9Sstevel@tonic-gate #include <locale.h>
40*7c478bd9Sstevel@tonic-gate #include <stdio.h>
41*7c478bd9Sstevel@tonic-gate #ifdef TRACE
42*7c478bd9Sstevel@tonic-gate unsigned char	tttrace[BUFSIZ];
43*7c478bd9Sstevel@tonic-gate #endif
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #define	EQ(a, b)	(strcmp(a, b) == 0)
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate char	*strrchr();
48*7c478bd9Sstevel@tonic-gate void	init_re(void);
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * The code for ex is divided as follows:
52*7c478bd9Sstevel@tonic-gate  *
53*7c478bd9Sstevel@tonic-gate  * ex.c			Entry point and routines handling interrupt, hangup
54*7c478bd9Sstevel@tonic-gate  *			signals; initialization code.
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * ex_addr.c		Address parsing routines for command mode decoding.
57*7c478bd9Sstevel@tonic-gate  *			Routines to set and check address ranges on commands.
58*7c478bd9Sstevel@tonic-gate  *
59*7c478bd9Sstevel@tonic-gate  * ex_cmds.c		Command mode command decoding.
60*7c478bd9Sstevel@tonic-gate  *
61*7c478bd9Sstevel@tonic-gate  * ex_cmds2.c		Subroutines for command decoding and processing of
62*7c478bd9Sstevel@tonic-gate  *			file names in the argument list.  Routines to print
63*7c478bd9Sstevel@tonic-gate  *			messages and reset state when errors occur.
64*7c478bd9Sstevel@tonic-gate  *
65*7c478bd9Sstevel@tonic-gate  * ex_cmdsub.c		Subroutines which implement command mode functions
66*7c478bd9Sstevel@tonic-gate  *			such as append, delete, join.
67*7c478bd9Sstevel@tonic-gate  *
68*7c478bd9Sstevel@tonic-gate  * ex_data.c		Initialization of options.
69*7c478bd9Sstevel@tonic-gate  *
70*7c478bd9Sstevel@tonic-gate  * ex_get.c		Command mode input routines.
71*7c478bd9Sstevel@tonic-gate  *
72*7c478bd9Sstevel@tonic-gate  * ex_io.c		General input/output processing: file i/o, unix
73*7c478bd9Sstevel@tonic-gate  *			escapes, filtering, source commands, preserving
74*7c478bd9Sstevel@tonic-gate  *			and recovering.
75*7c478bd9Sstevel@tonic-gate  *
76*7c478bd9Sstevel@tonic-gate  * ex_put.c		Terminal driving and optimizing routines for low-level
77*7c478bd9Sstevel@tonic-gate  *			output (cursor-positioning); output line formatting
78*7c478bd9Sstevel@tonic-gate  *			routines.
79*7c478bd9Sstevel@tonic-gate  *
80*7c478bd9Sstevel@tonic-gate  * ex_re.c		Global commands, substitute, regular expression
81*7c478bd9Sstevel@tonic-gate  *			compilation and execution.
82*7c478bd9Sstevel@tonic-gate  *
83*7c478bd9Sstevel@tonic-gate  * ex_set.c		The set command.
84*7c478bd9Sstevel@tonic-gate  *
85*7c478bd9Sstevel@tonic-gate  * ex_subr.c		Loads of miscellaneous subroutines.
86*7c478bd9Sstevel@tonic-gate  *
87*7c478bd9Sstevel@tonic-gate  * ex_temp.c		Editor buffer routines for main buffer and also
88*7c478bd9Sstevel@tonic-gate  *			for named buffers (Q registers if you will.)
89*7c478bd9Sstevel@tonic-gate  *
90*7c478bd9Sstevel@tonic-gate  * ex_tty.c		Terminal dependent initializations from termcap
91*7c478bd9Sstevel@tonic-gate  *			data base, grabbing of tty modes (at beginning
92*7c478bd9Sstevel@tonic-gate  *			and after escapes).
93*7c478bd9Sstevel@tonic-gate  *
94*7c478bd9Sstevel@tonic-gate  * ex_unix.c		Routines for the ! command and its variations.
95*7c478bd9Sstevel@tonic-gate  *
96*7c478bd9Sstevel@tonic-gate  * ex_v*.c		Visual/open mode routines... see ex_v.c for a
97*7c478bd9Sstevel@tonic-gate  *			guide to the overall organization.
98*7c478bd9Sstevel@tonic-gate  */
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate /*
101*7c478bd9Sstevel@tonic-gate  * This sets the Version of ex/vi for both the exstrings file and
102*7c478bd9Sstevel@tonic-gate  * the version command (":ver").
103*7c478bd9Sstevel@tonic-gate  */
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /* variable used by ":ver" command */
106*7c478bd9Sstevel@tonic-gate unsigned char *Version = (unsigned char *)"Version SVR4.0, Solaris 2.5.0";
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /*
109*7c478bd9Sstevel@tonic-gate  * NOTE: when changing the Version number, it must be changed in the
110*7c478bd9Sstevel@tonic-gate  *	 following files:
111*7c478bd9Sstevel@tonic-gate  *
112*7c478bd9Sstevel@tonic-gate  *			  port/READ_ME
113*7c478bd9Sstevel@tonic-gate  *			  port/ex.c
114*7c478bd9Sstevel@tonic-gate  *			  port/ex.news
115*7c478bd9Sstevel@tonic-gate  *
116*7c478bd9Sstevel@tonic-gate  */
117*7c478bd9Sstevel@tonic-gate #ifdef XPG4
118*7c478bd9Sstevel@tonic-gate unsigned char *savepat = (unsigned char *) NULL; /* firstpat storage	*/
119*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /*
122*7c478bd9Sstevel@tonic-gate  * Main procedure.  Process arguments and then
123*7c478bd9Sstevel@tonic-gate  * transfer control to the main command processing loop
124*7c478bd9Sstevel@tonic-gate  * in the routine commands.  We are entered as either "ex", "edit", "vi"
125*7c478bd9Sstevel@tonic-gate  * or "view" and the distinction is made here. For edit we just diddle options;
126*7c478bd9Sstevel@tonic-gate  * for vi we actually force an early visual command.
127*7c478bd9Sstevel@tonic-gate  */
128*7c478bd9Sstevel@tonic-gate static unsigned char cryptkey[19]; /* contents of encryption key */
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate static void usage(unsigned char *);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate static int validate_exrc(unsigned char *);
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate int
135*7c478bd9Sstevel@tonic-gate main(int ac, unsigned char *av[])
136*7c478bd9Sstevel@tonic-gate {
137*7c478bd9Sstevel@tonic-gate 	extern 	char 	*optarg;
138*7c478bd9Sstevel@tonic-gate 	extern 	int	optind;
139*7c478bd9Sstevel@tonic-gate 	unsigned char	*rcvname = 0;
140*7c478bd9Sstevel@tonic-gate 	unsigned char *cp;
141*7c478bd9Sstevel@tonic-gate 	int c;
142*7c478bd9Sstevel@tonic-gate 	unsigned char	*cmdnam;
143*7c478bd9Sstevel@tonic-gate 	bool recov = 0;
144*7c478bd9Sstevel@tonic-gate 	bool ivis = 0;
145*7c478bd9Sstevel@tonic-gate 	bool itag = 0;
146*7c478bd9Sstevel@tonic-gate 	bool fast = 0;
147*7c478bd9Sstevel@tonic-gate 	extern int verbose;
148*7c478bd9Sstevel@tonic-gate 	int argcounter = 0;
149*7c478bd9Sstevel@tonic-gate 	extern int tags_flag;	/* Set if tag file is not sorted (-S flag) */
150*7c478bd9Sstevel@tonic-gate 	unsigned char scratch [PATH_MAX+1];   /* temp for sourcing rc file(s) */
151*7c478bd9Sstevel@tonic-gate 	int vret = 0;
152*7c478bd9Sstevel@tonic-gate 	unsigned char exrcpath [PATH_MAX+1]; /* temp for sourcing rc file(s) */
153*7c478bd9Sstevel@tonic-gate 	int toptseen = 0;
154*7c478bd9Sstevel@tonic-gate #ifdef TRACE
155*7c478bd9Sstevel@tonic-gate 	unsigned char *tracef;
156*7c478bd9Sstevel@tonic-gate #endif
157*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
158*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
159*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
160*7c478bd9Sstevel@tonic-gate #endif
161*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	/*
164*7c478bd9Sstevel@tonic-gate 	 * Immediately grab the tty modes so that we won't
165*7c478bd9Sstevel@tonic-gate 	 * get messed up if an interrupt comes in quickly.
166*7c478bd9Sstevel@tonic-gate 	 */
167*7c478bd9Sstevel@tonic-gate 	gTTY(2);
168*7c478bd9Sstevel@tonic-gate 	normf = tty;
169*7c478bd9Sstevel@tonic-gate 	ppid = getpid();
170*7c478bd9Sstevel@tonic-gate 	/* Note - this will core dump if you didn't -DSINGLE in CFLAGS */
171*7c478bd9Sstevel@tonic-gate 	lines = 24;
172*7c478bd9Sstevel@tonic-gate 	columns = 80;	/* until defined right by setupterm */
173*7c478bd9Sstevel@tonic-gate 	/*
174*7c478bd9Sstevel@tonic-gate 	 * Defend against d's, v's, w's, and a's in directories of
175*7c478bd9Sstevel@tonic-gate 	 * path leading to our true name.
176*7c478bd9Sstevel@tonic-gate 	 */
177*7c478bd9Sstevel@tonic-gate 	if ((cmdnam = (unsigned char *)strrchr(av[0], '/')) != 0)
178*7c478bd9Sstevel@tonic-gate 		cmdnam++;
179*7c478bd9Sstevel@tonic-gate 	else
180*7c478bd9Sstevel@tonic-gate 		cmdnam = av[0];
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	if (EQ(cmdnam, "vi"))
183*7c478bd9Sstevel@tonic-gate 		ivis = 1;
184*7c478bd9Sstevel@tonic-gate 	else if (EQ(cmdnam, "view")) {
185*7c478bd9Sstevel@tonic-gate 		ivis = 1;
186*7c478bd9Sstevel@tonic-gate 		value(vi_READONLY) = 1;
187*7c478bd9Sstevel@tonic-gate 	} else if (EQ(cmdnam, "vedit")) {
188*7c478bd9Sstevel@tonic-gate 		ivis = 1;
189*7c478bd9Sstevel@tonic-gate 		value(vi_NOVICE) = 1;
190*7c478bd9Sstevel@tonic-gate 		value(vi_REPORT) = 1;
191*7c478bd9Sstevel@tonic-gate 		value(vi_MAGIC) = 0;
192*7c478bd9Sstevel@tonic-gate 		value(vi_SHOWMODE) = 1;
193*7c478bd9Sstevel@tonic-gate 	} else if (EQ(cmdnam, "edit")) {
194*7c478bd9Sstevel@tonic-gate 		value(vi_NOVICE) = 1;
195*7c478bd9Sstevel@tonic-gate 		value(vi_REPORT) = 1;
196*7c478bd9Sstevel@tonic-gate 		value(vi_MAGIC) = 0;
197*7c478bd9Sstevel@tonic-gate 		value(vi_SHOWMODE) = 1;
198*7c478bd9Sstevel@tonic-gate 	}
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate #ifdef	XPG4
201*7c478bd9Sstevel@tonic-gate 	{
202*7c478bd9Sstevel@tonic-gate 		struct winsize jwin;
203*7c478bd9Sstevel@tonic-gate 		char *envptr;
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 		envlines = envcolumns = -1;
206*7c478bd9Sstevel@tonic-gate 		oldlines = oldcolumns = -1;
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 		if (ioctl(0, TIOCGWINSZ, &jwin) != -1) {
209*7c478bd9Sstevel@tonic-gate 			oldlines = jwin.ws_row;
210*7c478bd9Sstevel@tonic-gate 			oldcolumns = jwin.ws_col;
211*7c478bd9Sstevel@tonic-gate 		}
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 		if ((envptr = getenv("LINES")) != NULL &&
214*7c478bd9Sstevel@tonic-gate 		    *envptr != '\0' && isdigit(*envptr)) {
215*7c478bd9Sstevel@tonic-gate 			if ((envlines = atoi(envptr)) <= 0) {
216*7c478bd9Sstevel@tonic-gate 				envlines = -1;
217*7c478bd9Sstevel@tonic-gate 			}
218*7c478bd9Sstevel@tonic-gate 		}
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 		if ((envptr = getenv("COLUMNS")) != NULL &&
221*7c478bd9Sstevel@tonic-gate 		    *envptr != '\0' && isdigit(*envptr)) {
222*7c478bd9Sstevel@tonic-gate 			if ((envcolumns = atoi(envptr)) <= 0) {
223*7c478bd9Sstevel@tonic-gate 				envcolumns = -1;
224*7c478bd9Sstevel@tonic-gate 			}
225*7c478bd9Sstevel@tonic-gate 		}
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	draino();
230*7c478bd9Sstevel@tonic-gate 	pstop();
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	/*
233*7c478bd9Sstevel@tonic-gate 	 * Initialize interrupt handling.
234*7c478bd9Sstevel@tonic-gate 	 */
235*7c478bd9Sstevel@tonic-gate 	oldhup = signal(SIGHUP, SIG_IGN);
236*7c478bd9Sstevel@tonic-gate 	if (oldhup == SIG_DFL)
237*7c478bd9Sstevel@tonic-gate 		signal(SIGHUP, onhup);
238*7c478bd9Sstevel@tonic-gate 	oldquit = signal(SIGQUIT, SIG_IGN);
239*7c478bd9Sstevel@tonic-gate 	ruptible = signal(SIGINT, SIG_IGN) == SIG_DFL;
240*7c478bd9Sstevel@tonic-gate 	if (signal(SIGTERM, SIG_IGN) == SIG_DFL)
241*7c478bd9Sstevel@tonic-gate 		signal(SIGTERM, onhup);
242*7c478bd9Sstevel@tonic-gate 	if (signal(SIGEMT, SIG_IGN) == SIG_DFL)
243*7c478bd9Sstevel@tonic-gate 		signal(SIGEMT, onemt);
244*7c478bd9Sstevel@tonic-gate 	signal(SIGILL, oncore);
245*7c478bd9Sstevel@tonic-gate 	signal(SIGTRAP, oncore);
246*7c478bd9Sstevel@tonic-gate 	signal(SIGIOT, oncore);
247*7c478bd9Sstevel@tonic-gate 	signal(SIGFPE, oncore);
248*7c478bd9Sstevel@tonic-gate 	signal(SIGBUS, oncore);
249*7c478bd9Sstevel@tonic-gate 	signal(SIGSEGV, oncore);
250*7c478bd9Sstevel@tonic-gate 	signal(SIGPIPE, oncore);
251*7c478bd9Sstevel@tonic-gate 	init_re();
252*7c478bd9Sstevel@tonic-gate 	while (1) {
253*7c478bd9Sstevel@tonic-gate #ifdef TRACE
254*7c478bd9Sstevel@tonic-gate 		while ((c = getopt(ac, (char **)av, "VU:Lc:Tvt:rlw:xRCsS")) !=
255*7c478bd9Sstevel@tonic-gate 		    EOF)
256*7c478bd9Sstevel@tonic-gate #else
257*7c478bd9Sstevel@tonic-gate 		while ((c = getopt(ac, (char **)av,
258*7c478bd9Sstevel@tonic-gate 			    "VLc:vt:rlw:xRCsS")) != EOF)
259*7c478bd9Sstevel@tonic-gate #endif
260*7c478bd9Sstevel@tonic-gate 			switch (c) {
261*7c478bd9Sstevel@tonic-gate 			case 's':
262*7c478bd9Sstevel@tonic-gate 				hush = 1;
263*7c478bd9Sstevel@tonic-gate 				value(vi_AUTOPRINT) = 0;
264*7c478bd9Sstevel@tonic-gate 				fast++;
265*7c478bd9Sstevel@tonic-gate 				break;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 			case 'R':
268*7c478bd9Sstevel@tonic-gate 				value(vi_READONLY) = 1;
269*7c478bd9Sstevel@tonic-gate 				break;
270*7c478bd9Sstevel@tonic-gate 			case 'S':
271*7c478bd9Sstevel@tonic-gate 				tags_flag = 1;
272*7c478bd9Sstevel@tonic-gate 				break;
273*7c478bd9Sstevel@tonic-gate #ifdef TRACE
274*7c478bd9Sstevel@tonic-gate 			case 'T':
275*7c478bd9Sstevel@tonic-gate 				tracef = (unsigned char *)"trace";
276*7c478bd9Sstevel@tonic-gate 				goto trace;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 			case 'U':
279*7c478bd9Sstevel@tonic-gate 				tracef = tttrace;
280*7c478bd9Sstevel@tonic-gate 				strcpy(tracef, optarg);
281*7c478bd9Sstevel@tonic-gate 		trace:
282*7c478bd9Sstevel@tonic-gate 				trace = fopen((char *)tracef, "w");
283*7c478bd9Sstevel@tonic-gate #define	tracbuf	NULL
284*7c478bd9Sstevel@tonic-gate 				if (trace == NULL)
285*7c478bd9Sstevel@tonic-gate 					printf("Trace create error\n");
286*7c478bd9Sstevel@tonic-gate 				else
287*7c478bd9Sstevel@tonic-gate 					setbuf(trace, (char *)tracbuf);
288*7c478bd9Sstevel@tonic-gate 				break;
289*7c478bd9Sstevel@tonic-gate #endif
290*7c478bd9Sstevel@tonic-gate 			case 'c':
291*7c478bd9Sstevel@tonic-gate 				if (optarg != NULL)
292*7c478bd9Sstevel@tonic-gate 					firstpat = (unsigned char *)optarg;
293*7c478bd9Sstevel@tonic-gate 				else
294*7c478bd9Sstevel@tonic-gate 					firstpat = (unsigned char *)"";
295*7c478bd9Sstevel@tonic-gate 				break;
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 			case 'l':
298*7c478bd9Sstevel@tonic-gate 				value(vi_LISP) = 1;
299*7c478bd9Sstevel@tonic-gate 				value(vi_SHOWMATCH) = 1;
300*7c478bd9Sstevel@tonic-gate 				break;
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 			case 'r':
303*7c478bd9Sstevel@tonic-gate 				if (av[optind] && (c = av[optind][0]) &&
304*7c478bd9Sstevel@tonic-gate 				    c != '-') {
305*7c478bd9Sstevel@tonic-gate 					if ((strlen(av[optind])) >=
306*7c478bd9Sstevel@tonic-gate 					    sizeof (savedfile)) {
307*7c478bd9Sstevel@tonic-gate 						(void) fprintf(stderr, gettext(
308*7c478bd9Sstevel@tonic-gate 							"Recovered file name"
309*7c478bd9Sstevel@tonic-gate 							" too long\n"));
310*7c478bd9Sstevel@tonic-gate 						exit(1);
311*7c478bd9Sstevel@tonic-gate 					}
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 					rcvname = (unsigned char *)av[optind];
314*7c478bd9Sstevel@tonic-gate 					optind++;
315*7c478bd9Sstevel@tonic-gate 				}
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 			case 'L':
318*7c478bd9Sstevel@tonic-gate 				recov++;
319*7c478bd9Sstevel@tonic-gate 				break;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 			case 'V':
322*7c478bd9Sstevel@tonic-gate 				verbose = 1;
323*7c478bd9Sstevel@tonic-gate 				break;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 			case 't':
326*7c478bd9Sstevel@tonic-gate 				if (toptseen) {
327*7c478bd9Sstevel@tonic-gate 					usage(cmdnam);
328*7c478bd9Sstevel@tonic-gate 					exit(1);
329*7c478bd9Sstevel@tonic-gate 				} else {
330*7c478bd9Sstevel@tonic-gate 					toptseen++;
331*7c478bd9Sstevel@tonic-gate 				}
332*7c478bd9Sstevel@tonic-gate 				itag = 1;
333*7c478bd9Sstevel@tonic-gate 				if (strlcpy(lasttag, optarg,
334*7c478bd9Sstevel@tonic-gate 				    sizeof (lasttag)) >= sizeof (lasttag)) {
335*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext("Tag"
336*7c478bd9Sstevel@tonic-gate 					    " file name too long\n"));
337*7c478bd9Sstevel@tonic-gate 					exit(1);
338*7c478bd9Sstevel@tonic-gate 				}
339*7c478bd9Sstevel@tonic-gate 				break;
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 			case 'w':
342*7c478bd9Sstevel@tonic-gate 				defwind = 0;
343*7c478bd9Sstevel@tonic-gate 				if (optarg[0] == NULL)
344*7c478bd9Sstevel@tonic-gate 					defwind = 3;
345*7c478bd9Sstevel@tonic-gate 				else for (cp = (unsigned char *)optarg;
346*7c478bd9Sstevel@tonic-gate 				    isdigit(*cp); cp++)
347*7c478bd9Sstevel@tonic-gate 					defwind = 10*defwind + *cp - '0';
348*7c478bd9Sstevel@tonic-gate 				if (defwind < 0)
349*7c478bd9Sstevel@tonic-gate 					defwind = 3;
350*7c478bd9Sstevel@tonic-gate 				break;
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 			case 'C':
353*7c478bd9Sstevel@tonic-gate 				crflag = 1;
354*7c478bd9Sstevel@tonic-gate 				xflag = 1;
355*7c478bd9Sstevel@tonic-gate 				break;
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 			case 'x':
358*7c478bd9Sstevel@tonic-gate 				/* encrypted mode */
359*7c478bd9Sstevel@tonic-gate 				xflag = 1;
360*7c478bd9Sstevel@tonic-gate 				crflag = -1;
361*7c478bd9Sstevel@tonic-gate 				break;
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 			case 'v':
364*7c478bd9Sstevel@tonic-gate 				ivis = 1;
365*7c478bd9Sstevel@tonic-gate 				break;
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 			default:
368*7c478bd9Sstevel@tonic-gate 				usage(cmdnam);
369*7c478bd9Sstevel@tonic-gate 				exit(1);
370*7c478bd9Sstevel@tonic-gate 			}
371*7c478bd9Sstevel@tonic-gate 		if (av[optind] && av[optind][0] == '+' &&
372*7c478bd9Sstevel@tonic-gate 		    av[optind-1] && strcmp(av[optind-1], "--")) {
373*7c478bd9Sstevel@tonic-gate 				firstpat = &av[optind][1];
374*7c478bd9Sstevel@tonic-gate 				optind++;
375*7c478bd9Sstevel@tonic-gate 				continue;
376*7c478bd9Sstevel@tonic-gate 		} else if (av[optind] && av[optind][0] == '-' &&
377*7c478bd9Sstevel@tonic-gate 		    av[optind-1] && strcmp(av[optind-1], "--")) {
378*7c478bd9Sstevel@tonic-gate 			hush = 1;
379*7c478bd9Sstevel@tonic-gate 			value(vi_AUTOPRINT) = 0;
380*7c478bd9Sstevel@tonic-gate 			fast++;
381*7c478bd9Sstevel@tonic-gate 			optind++;
382*7c478bd9Sstevel@tonic-gate 			continue;
383*7c478bd9Sstevel@tonic-gate 		}
384*7c478bd9Sstevel@tonic-gate 		break;
385*7c478bd9Sstevel@tonic-gate 	}
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	/*
388*7c478bd9Sstevel@tonic-gate 	 * If -V option is set and input is coming in via
389*7c478bd9Sstevel@tonic-gate 	 * stdin then vi behavior should be ignored. The vi
390*7c478bd9Sstevel@tonic-gate 	 * command should act like ex and only process ex commands
391*7c478bd9Sstevel@tonic-gate 	 * and echo the input ex commands to stderr
392*7c478bd9Sstevel@tonic-gate 	 */
393*7c478bd9Sstevel@tonic-gate 	if (verbose == 1 && isatty(0) == 0) {
394*7c478bd9Sstevel@tonic-gate 		ivis = 0;
395*7c478bd9Sstevel@tonic-gate 	}
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	ac -= optind;
398*7c478bd9Sstevel@tonic-gate 	av  = &av[optind];
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	for (argcounter = 0; argcounter < ac; argcounter++) {
401*7c478bd9Sstevel@tonic-gate 		if ((strlen(av[argcounter])) >= sizeof (savedfile)) {
402*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("File argument"
403*7c478bd9Sstevel@tonic-gate 				" too long\n"));
404*7c478bd9Sstevel@tonic-gate 			exit(1);
405*7c478bd9Sstevel@tonic-gate 		}
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
409*7c478bd9Sstevel@tonic-gate 	if (!hush && signal(SIGTSTP, SIG_IGN) == SIG_DFL)
410*7c478bd9Sstevel@tonic-gate 		signal(SIGTSTP, onsusp), dosusp++;
411*7c478bd9Sstevel@tonic-gate #endif
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	if (xflag) {
414*7c478bd9Sstevel@tonic-gate 		permflag = 1;
415*7c478bd9Sstevel@tonic-gate 		if ((kflag = run_setkey(perm,
416*7c478bd9Sstevel@tonic-gate 		    (key = (unsigned char *)getpass(
417*7c478bd9Sstevel@tonic-gate 		    gettext("Enter key:"))))) == -1) {
418*7c478bd9Sstevel@tonic-gate 			kflag = 0;
419*7c478bd9Sstevel@tonic-gate 			xflag = 0;
420*7c478bd9Sstevel@tonic-gate 			smerror(gettext("Encryption facility not available\n"));
421*7c478bd9Sstevel@tonic-gate 		}
422*7c478bd9Sstevel@tonic-gate 		if (kflag == 0)
423*7c478bd9Sstevel@tonic-gate 			crflag = 0;
424*7c478bd9Sstevel@tonic-gate 		else {
425*7c478bd9Sstevel@tonic-gate 			strcpy(cryptkey, "CrYpTkEy=XXXXXXXXX");
426*7c478bd9Sstevel@tonic-gate 			strcpy(cryptkey + 9, key);
427*7c478bd9Sstevel@tonic-gate 			if (putenv((char *)cryptkey) != 0)
428*7c478bd9Sstevel@tonic-gate 			smerror(gettext(" Cannot copy key to environment"));
429*7c478bd9Sstevel@tonic-gate 		}
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC
433*7c478bd9Sstevel@tonic-gate 	/*
434*7c478bd9Sstevel@tonic-gate 	 * Perform locale-specific initialization
435*7c478bd9Sstevel@tonic-gate 	 */
436*7c478bd9Sstevel@tonic-gate 	(void) localize();
437*7c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	/*
440*7c478bd9Sstevel@tonic-gate 	 * Initialize end of core pointers.
441*7c478bd9Sstevel@tonic-gate 	 * Normally we avoid breaking back to fendcore after each
442*7c478bd9Sstevel@tonic-gate 	 * file since this can be expensive (much core-core copying).
443*7c478bd9Sstevel@tonic-gate 	 * If your system can scatter load processes you could do
444*7c478bd9Sstevel@tonic-gate 	 * this as ed does, saving a little core, but it will probably
445*7c478bd9Sstevel@tonic-gate 	 * not often make much difference.
446*7c478bd9Sstevel@tonic-gate 	 */
447*7c478bd9Sstevel@tonic-gate 	fendcore = (line *) sbrk(0);
448*7c478bd9Sstevel@tonic-gate 	endcore = fendcore - 2;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	/*
451*7c478bd9Sstevel@tonic-gate 	 * If we are doing a recover and no filename
452*7c478bd9Sstevel@tonic-gate 	 * was given, then execute an exrecover command with
453*7c478bd9Sstevel@tonic-gate 	 * the -r option to type out the list of saved file names.
454*7c478bd9Sstevel@tonic-gate 	 * Otherwise set the remembered file name to the first argument
455*7c478bd9Sstevel@tonic-gate 	 * file name so the "recover" initial command will find it.
456*7c478bd9Sstevel@tonic-gate 	 */
457*7c478bd9Sstevel@tonic-gate 	if (recov) {
458*7c478bd9Sstevel@tonic-gate 		if (ac == 0 && (rcvname == NULL || *rcvname == NULL)) {
459*7c478bd9Sstevel@tonic-gate 			ppid = 0;
460*7c478bd9Sstevel@tonic-gate 			setrupt();
461*7c478bd9Sstevel@tonic-gate 			execlp(EXRECOVER, "exrecover", "-r", (char *)0);
462*7c478bd9Sstevel@tonic-gate 			filioerr(EXRECOVER);
463*7c478bd9Sstevel@tonic-gate 			exit(++errcnt);
464*7c478bd9Sstevel@tonic-gate 		}
465*7c478bd9Sstevel@tonic-gate 		if (rcvname && *rcvname)
466*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(savedfile, rcvname, sizeof (savedfile));
467*7c478bd9Sstevel@tonic-gate 		else {
468*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(savedfile, *av++, sizeof (savedfile));
469*7c478bd9Sstevel@tonic-gate 			ac--;
470*7c478bd9Sstevel@tonic-gate 		}
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	/*
474*7c478bd9Sstevel@tonic-gate 	 * Initialize the argument list.
475*7c478bd9Sstevel@tonic-gate 	 */
476*7c478bd9Sstevel@tonic-gate 	argv0 = av;
477*7c478bd9Sstevel@tonic-gate 	argc0 = ac;
478*7c478bd9Sstevel@tonic-gate 	args0 = av[0];
479*7c478bd9Sstevel@tonic-gate 	erewind();
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	/*
482*7c478bd9Sstevel@tonic-gate 	 * Initialize a temporary file (buffer) and
483*7c478bd9Sstevel@tonic-gate 	 * set up terminal environment.  Read user startup commands.
484*7c478bd9Sstevel@tonic-gate 	 */
485*7c478bd9Sstevel@tonic-gate 	if (setexit() == 0) {
486*7c478bd9Sstevel@tonic-gate 		setrupt();
487*7c478bd9Sstevel@tonic-gate 		intty = isatty(0);
488*7c478bd9Sstevel@tonic-gate 		value(vi_PROMPT) = intty;
489*7c478bd9Sstevel@tonic-gate 		if (((cp = (unsigned char *)getenv("SHELL")) != NULL) &&
490*7c478bd9Sstevel@tonic-gate 		    (*cp != '\0')) {
491*7c478bd9Sstevel@tonic-gate 			if (strlen(cp) < sizeof (shell)) {
492*7c478bd9Sstevel@tonic-gate 				(void) strlcpy(shell, cp, sizeof (shell));
493*7c478bd9Sstevel@tonic-gate 			}
494*7c478bd9Sstevel@tonic-gate 		}
495*7c478bd9Sstevel@tonic-gate 		if (fast)
496*7c478bd9Sstevel@tonic-gate 			setterm("dumb");
497*7c478bd9Sstevel@tonic-gate 		else {
498*7c478bd9Sstevel@tonic-gate 			gettmode();
499*7c478bd9Sstevel@tonic-gate 			cp = (unsigned char *)getenv("TERM");
500*7c478bd9Sstevel@tonic-gate 			if (cp == NULL || *cp == '\0')
501*7c478bd9Sstevel@tonic-gate 				cp = (unsigned char *)"unknown";
502*7c478bd9Sstevel@tonic-gate 			setterm(cp);
503*7c478bd9Sstevel@tonic-gate 		}
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	/*
507*7c478bd9Sstevel@tonic-gate 	 * Bring up some code from init()
508*7c478bd9Sstevel@tonic-gate 	 * This is still done in init later. This
509*7c478bd9Sstevel@tonic-gate 	 * avoids null pointer problems
510*7c478bd9Sstevel@tonic-gate 	 */
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	dot = zero = truedol = unddol = dol = fendcore;
513*7c478bd9Sstevel@tonic-gate 	one = zero+1;
514*7c478bd9Sstevel@tonic-gate 	{
515*7c478bd9Sstevel@tonic-gate 	register int i;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= 'z'-'a'+1; i++)
518*7c478bd9Sstevel@tonic-gate 		names[i] = 1;
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	if (setexit() == 0 && !fast) {
522*7c478bd9Sstevel@tonic-gate 		if ((globp =
523*7c478bd9Sstevel@tonic-gate 			(unsigned char *) getenv("EXINIT")) && *globp) {
524*7c478bd9Sstevel@tonic-gate 			if (ivis)
525*7c478bd9Sstevel@tonic-gate 				inexrc = 1;
526*7c478bd9Sstevel@tonic-gate 			commands(1, 1);
527*7c478bd9Sstevel@tonic-gate 			inexrc = 0;
528*7c478bd9Sstevel@tonic-gate 		} else {
529*7c478bd9Sstevel@tonic-gate 			globp = 0;
530*7c478bd9Sstevel@tonic-gate 			if ((cp = (unsigned char *) getenv("HOME")) !=
531*7c478bd9Sstevel@tonic-gate 			    0 && *cp) {
532*7c478bd9Sstevel@tonic-gate 				strncpy(scratch, cp, sizeof (scratch) - 1);
533*7c478bd9Sstevel@tonic-gate 				strncat(scratch, "/.exrc",
534*7c478bd9Sstevel@tonic-gate 				    sizeof (scratch) - 1 - strlen(scratch));
535*7c478bd9Sstevel@tonic-gate 				if (ivis)
536*7c478bd9Sstevel@tonic-gate 				    inexrc = 1;
537*7c478bd9Sstevel@tonic-gate 				if ((vret = validate_exrc(scratch)) == 0) {
538*7c478bd9Sstevel@tonic-gate 					source(scratch, 1);
539*7c478bd9Sstevel@tonic-gate 				} else {
540*7c478bd9Sstevel@tonic-gate 					if (vret == -1) {
541*7c478bd9Sstevel@tonic-gate 						error(gettext(
542*7c478bd9Sstevel@tonic-gate 						    "Not owner of .exrc "
543*7c478bd9Sstevel@tonic-gate 						    "or .exrc is group or "
544*7c478bd9Sstevel@tonic-gate 						    "world writable"));
545*7c478bd9Sstevel@tonic-gate 					}
546*7c478bd9Sstevel@tonic-gate 				}
547*7c478bd9Sstevel@tonic-gate 				inexrc = 0;
548*7c478bd9Sstevel@tonic-gate 			}
549*7c478bd9Sstevel@tonic-gate 		}
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		/*
552*7c478bd9Sstevel@tonic-gate 		 * Allow local .exrc if the "exrc" option was set. This
553*7c478bd9Sstevel@tonic-gate 		 * loses if . is $HOME, but nobody should notice unless
554*7c478bd9Sstevel@tonic-gate 		 * they do stupid things like putting a version command
555*7c478bd9Sstevel@tonic-gate 		 * in .exrc.
556*7c478bd9Sstevel@tonic-gate 		 * Besides, they should be using EXINIT, not .exrc, right?
557*7c478bd9Sstevel@tonic-gate 		 */
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		if (value(vi_EXRC)) {
560*7c478bd9Sstevel@tonic-gate 			if (ivis)
561*7c478bd9Sstevel@tonic-gate 				inexrc = 1;
562*7c478bd9Sstevel@tonic-gate 			if ((cp = (unsigned char *) getenv("PWD")) != 0 &&
563*7c478bd9Sstevel@tonic-gate 			    *cp) {
564*7c478bd9Sstevel@tonic-gate 				strncpy(exrcpath, cp, sizeof (exrcpath) - 1);
565*7c478bd9Sstevel@tonic-gate 				strncat(exrcpath, "/.exrc",
566*7c478bd9Sstevel@tonic-gate 				    sizeof (exrcpath) - 1 - strlen(exrcpath));
567*7c478bd9Sstevel@tonic-gate 				if (strcmp(scratch, exrcpath) != 0) {
568*7c478bd9Sstevel@tonic-gate 					if ((vret =
569*7c478bd9Sstevel@tonic-gate 					    validate_exrc(exrcpath)) == 0) {
570*7c478bd9Sstevel@tonic-gate 						source(exrcpath, 1);
571*7c478bd9Sstevel@tonic-gate 					} else {
572*7c478bd9Sstevel@tonic-gate 						if (vret == -1) {
573*7c478bd9Sstevel@tonic-gate 							error(gettext(
574*7c478bd9Sstevel@tonic-gate 							    "Not owner of "
575*7c478bd9Sstevel@tonic-gate 							    ".exrc or .exrc "
576*7c478bd9Sstevel@tonic-gate 							    "is group or world "
577*7c478bd9Sstevel@tonic-gate 							    "writable"));
578*7c478bd9Sstevel@tonic-gate 						}
579*7c478bd9Sstevel@tonic-gate 					}
580*7c478bd9Sstevel@tonic-gate 				}
581*7c478bd9Sstevel@tonic-gate 			}
582*7c478bd9Sstevel@tonic-gate 			inexrc = 0;
583*7c478bd9Sstevel@tonic-gate 		}
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	init();	/* moved after prev 2 chunks to fix directory option */
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	/*
589*7c478bd9Sstevel@tonic-gate 	 * Initial processing.  Handle tag, recover, and file argument
590*7c478bd9Sstevel@tonic-gate 	 * implied next commands.  If going in as 'vi', then don't do
591*7c478bd9Sstevel@tonic-gate 	 * anything, just set initev so we will do it later (from within
592*7c478bd9Sstevel@tonic-gate 	 * visual).
593*7c478bd9Sstevel@tonic-gate 	 */
594*7c478bd9Sstevel@tonic-gate 	if (setexit() == 0) {
595*7c478bd9Sstevel@tonic-gate 		if (recov)
596*7c478bd9Sstevel@tonic-gate 			globp = (unsigned char *)"recover";
597*7c478bd9Sstevel@tonic-gate 		else if (itag) {
598*7c478bd9Sstevel@tonic-gate 			globp = ivis ? (unsigned char *)"tag" :
599*7c478bd9Sstevel@tonic-gate 			    (unsigned char *)"tag|p";
600*7c478bd9Sstevel@tonic-gate #ifdef	XPG4
601*7c478bd9Sstevel@tonic-gate 			if (firstpat != NULL) {
602*7c478bd9Sstevel@tonic-gate 				/*
603*7c478bd9Sstevel@tonic-gate 				 * if the user specified the -t and -c
604*7c478bd9Sstevel@tonic-gate 				 * flags together, then we service these
605*7c478bd9Sstevel@tonic-gate 				 * commands here. -t is handled first.
606*7c478bd9Sstevel@tonic-gate 				 */
607*7c478bd9Sstevel@tonic-gate 				savepat = firstpat;
608*7c478bd9Sstevel@tonic-gate 				firstpat = NULL;
609*7c478bd9Sstevel@tonic-gate 				inglobal = 1;
610*7c478bd9Sstevel@tonic-gate 				commands(1, 1);
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 				/* now handle the -c argument: */
613*7c478bd9Sstevel@tonic-gate 				globp = savepat;
614*7c478bd9Sstevel@tonic-gate 				commands(1, 1);
615*7c478bd9Sstevel@tonic-gate 				inglobal = 0;
616*7c478bd9Sstevel@tonic-gate 				globp = savepat = NULL;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 				/* the above isn't sufficient for ex mode: */
619*7c478bd9Sstevel@tonic-gate 				if (!ivis) {
620*7c478bd9Sstevel@tonic-gate 					setdot();
621*7c478bd9Sstevel@tonic-gate 					nonzero();
622*7c478bd9Sstevel@tonic-gate 					plines(addr1, addr2, 1);
623*7c478bd9Sstevel@tonic-gate 				}
624*7c478bd9Sstevel@tonic-gate 			}
625*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */
626*7c478bd9Sstevel@tonic-gate 		} else if (argc)
627*7c478bd9Sstevel@tonic-gate 			globp = (unsigned char *)"next";
628*7c478bd9Sstevel@tonic-gate 		if (ivis)
629*7c478bd9Sstevel@tonic-gate 			initev = globp;
630*7c478bd9Sstevel@tonic-gate 		else if (globp) {
631*7c478bd9Sstevel@tonic-gate 			inglobal = 1;
632*7c478bd9Sstevel@tonic-gate 			commands(1, 1);
633*7c478bd9Sstevel@tonic-gate 			inglobal = 0;
634*7c478bd9Sstevel@tonic-gate 		}
635*7c478bd9Sstevel@tonic-gate 	}
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	/*
638*7c478bd9Sstevel@tonic-gate 	 * Vi command... go into visual.
639*7c478bd9Sstevel@tonic-gate 	 */
640*7c478bd9Sstevel@tonic-gate 	if (ivis) {
641*7c478bd9Sstevel@tonic-gate 		/*
642*7c478bd9Sstevel@tonic-gate 		 * Don't have to be upward compatible
643*7c478bd9Sstevel@tonic-gate 		 * by starting editing at line $.
644*7c478bd9Sstevel@tonic-gate 		 */
645*7c478bd9Sstevel@tonic-gate #ifdef	XPG4
646*7c478bd9Sstevel@tonic-gate 		if (!itag && (dol > zero))
647*7c478bd9Sstevel@tonic-gate #else /* XPG4 */
648*7c478bd9Sstevel@tonic-gate 		if (dol > zero)
649*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */
650*7c478bd9Sstevel@tonic-gate 			dot = one;
651*7c478bd9Sstevel@tonic-gate 		globp = (unsigned char *)"visual";
652*7c478bd9Sstevel@tonic-gate 		if (setexit() == 0)
653*7c478bd9Sstevel@tonic-gate 			commands(1, 1);
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	/*
657*7c478bd9Sstevel@tonic-gate 	 * Clear out trash in state accumulated by startup,
658*7c478bd9Sstevel@tonic-gate 	 * and then do the main command loop for a normal edit.
659*7c478bd9Sstevel@tonic-gate 	 * If you quit out of a 'vi' command by doing Q or ^\,
660*7c478bd9Sstevel@tonic-gate 	 * you also fall through to here.
661*7c478bd9Sstevel@tonic-gate 	 */
662*7c478bd9Sstevel@tonic-gate 	seenprompt = 1;
663*7c478bd9Sstevel@tonic-gate 	ungetchar(0);
664*7c478bd9Sstevel@tonic-gate 	globp = 0;
665*7c478bd9Sstevel@tonic-gate 	initev = 0;
666*7c478bd9Sstevel@tonic-gate 	setlastchar('\n');
667*7c478bd9Sstevel@tonic-gate 	setexit();
668*7c478bd9Sstevel@tonic-gate 	commands(0, 0);
669*7c478bd9Sstevel@tonic-gate 	cleanup(1);
670*7c478bd9Sstevel@tonic-gate 	exit(errcnt);
671*7c478bd9Sstevel@tonic-gate }
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate /*
674*7c478bd9Sstevel@tonic-gate  * Initialization, before editing a new file.
675*7c478bd9Sstevel@tonic-gate  * Main thing here is to get a new buffer (in fileinit),
676*7c478bd9Sstevel@tonic-gate  * rest is peripheral state resetting.
677*7c478bd9Sstevel@tonic-gate  */
678*7c478bd9Sstevel@tonic-gate init()
679*7c478bd9Sstevel@tonic-gate {
680*7c478bd9Sstevel@tonic-gate 	register int i;
681*7c478bd9Sstevel@tonic-gate 	void (*pstat)();
682*7c478bd9Sstevel@tonic-gate 	fileinit();
683*7c478bd9Sstevel@tonic-gate 	dot = zero = truedol = unddol = dol = fendcore;
684*7c478bd9Sstevel@tonic-gate 	one = zero+1;
685*7c478bd9Sstevel@tonic-gate 	undkind = UNDNONE;
686*7c478bd9Sstevel@tonic-gate 	chng = 0;
687*7c478bd9Sstevel@tonic-gate 	edited = 0;
688*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= 'z'-'a'+1; i++)
689*7c478bd9Sstevel@tonic-gate 		names[i] = 1;
690*7c478bd9Sstevel@tonic-gate 	anymarks = 0;
691*7c478bd9Sstevel@tonic-gate 	if (xflag) {
692*7c478bd9Sstevel@tonic-gate 		xtflag = 1;
693*7c478bd9Sstevel@tonic-gate 		/* ignore SIGINT before crypt process */
694*7c478bd9Sstevel@tonic-gate 		pstat = signal(SIGINT, SIG_IGN);
695*7c478bd9Sstevel@tonic-gate 		if (tpermflag)
696*7c478bd9Sstevel@tonic-gate 			(void) crypt_close(tperm);
697*7c478bd9Sstevel@tonic-gate 		tpermflag = 1;
698*7c478bd9Sstevel@tonic-gate 		if (makekey(tperm) != 0) {
699*7c478bd9Sstevel@tonic-gate 			xtflag = 0;
700*7c478bd9Sstevel@tonic-gate 			smerror(gettext(
701*7c478bd9Sstevel@tonic-gate 			    "Warning--Cannot encrypt temporary buffer\n"));
702*7c478bd9Sstevel@tonic-gate 		}
703*7c478bd9Sstevel@tonic-gate 		signal(SIGINT, pstat);
704*7c478bd9Sstevel@tonic-gate 	}
705*7c478bd9Sstevel@tonic-gate }
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate /*
708*7c478bd9Sstevel@tonic-gate  * Return last component of unix path name p.
709*7c478bd9Sstevel@tonic-gate  */
710*7c478bd9Sstevel@tonic-gate unsigned char *
711*7c478bd9Sstevel@tonic-gate tailpath(p)
712*7c478bd9Sstevel@tonic-gate register unsigned char *p;
713*7c478bd9Sstevel@tonic-gate {
714*7c478bd9Sstevel@tonic-gate 	register unsigned char *r;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	for (r = p; *p; p++)
717*7c478bd9Sstevel@tonic-gate 		if (*p == '/')
718*7c478bd9Sstevel@tonic-gate 			r = p+1;
719*7c478bd9Sstevel@tonic-gate 	return (r);
720*7c478bd9Sstevel@tonic-gate }
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate /*
724*7c478bd9Sstevel@tonic-gate  * validate_exrc - verify .exrc as belonging to the user.
725*7c478bd9Sstevel@tonic-gate  * The file uid should match the process ruid,
726*7c478bd9Sstevel@tonic-gate  * and the file should be writable only by the owner.
727*7c478bd9Sstevel@tonic-gate  */
728*7c478bd9Sstevel@tonic-gate static int
729*7c478bd9Sstevel@tonic-gate validate_exrc(unsigned char *exrc_path)
730*7c478bd9Sstevel@tonic-gate {
731*7c478bd9Sstevel@tonic-gate 	struct stat64 exrc_stat;
732*7c478bd9Sstevel@tonic-gate 	int process_uid;
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	if (stat64((char *)exrc_path, &exrc_stat) == -1)
735*7c478bd9Sstevel@tonic-gate 		return (0); /* ignore if .exrec is not found */
736*7c478bd9Sstevel@tonic-gate 	process_uid = geteuid();
737*7c478bd9Sstevel@tonic-gate 	/* if not root, uid must match file owner */
738*7c478bd9Sstevel@tonic-gate 	if (process_uid && process_uid != exrc_stat.st_uid)
739*7c478bd9Sstevel@tonic-gate 		return (-1);
740*7c478bd9Sstevel@tonic-gate 	if ((exrc_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)
741*7c478bd9Sstevel@tonic-gate 		return (-1);
742*7c478bd9Sstevel@tonic-gate 	return (0);
743*7c478bd9Sstevel@tonic-gate }
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate /*
746*7c478bd9Sstevel@tonic-gate  * print usage message to stdout
747*7c478bd9Sstevel@tonic-gate  */
748*7c478bd9Sstevel@tonic-gate static void
749*7c478bd9Sstevel@tonic-gate usage(unsigned char *name)
750*7c478bd9Sstevel@tonic-gate {
751*7c478bd9Sstevel@tonic-gate 	char buf[160];
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate #ifdef TRACE
754*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), gettext(
755*7c478bd9Sstevel@tonic-gate 		    "Usage: %s [- | -s] [-l] [-L] [-wn] "
756*7c478bd9Sstevel@tonic-gate 		    "[-R] [-S] [-r [file]] [-t tag] [-T] [-U tracefile]\n"
757*7c478bd9Sstevel@tonic-gate 		    "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name);
758*7c478bd9Sstevel@tonic-gate #else
759*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), gettext(
760*7c478bd9Sstevel@tonic-gate 		    "Usage: %s [- | -s] [-l] [-L] [-wn] "
761*7c478bd9Sstevel@tonic-gate 		    "[-R] [-S] [-r [file]] [-t tag]\n"
762*7c478bd9Sstevel@tonic-gate 		    "[-v] [-V] [-x] [-C] [+cmd | -c cmd] file...\n"), name);
763*7c478bd9Sstevel@tonic-gate #endif
764*7c478bd9Sstevel@tonic-gate 	(void) write(2, buf, strlen(buf));
765*7c478bd9Sstevel@tonic-gate }
766