xref: /dflybsd-src/contrib/nvi2/common/main.c (revision 07bc39c2f4bbca56f12568e06d89da17f2eeb965)
1e0b8e63eSJohn Marino /*-
2e0b8e63eSJohn Marino  * Copyright (c) 1992, 1993, 1994
3e0b8e63eSJohn Marino  *	The Regents of the University of California.  All rights reserved.
4e0b8e63eSJohn Marino  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5e0b8e63eSJohn Marino  *	Keith Bostic.  All rights reserved.
6e0b8e63eSJohn Marino  *
7e0b8e63eSJohn Marino  * See the LICENSE file for redistribution information.
8e0b8e63eSJohn Marino  */
9e0b8e63eSJohn Marino 
10e0b8e63eSJohn Marino #include "config.h"
11e0b8e63eSJohn Marino 
12e0b8e63eSJohn Marino #include <sys/types.h>
13e0b8e63eSJohn Marino #include <sys/queue.h>
14e0b8e63eSJohn Marino #include <sys/stat.h>
15e0b8e63eSJohn Marino 
16e0b8e63eSJohn Marino #include <bitstring.h>
17*b1ac2ebbSDaniel Fojt #include <err.h>
18e0b8e63eSJohn Marino #include <errno.h>
19e0b8e63eSJohn Marino #include <fcntl.h>
20e0b8e63eSJohn Marino #include <limits.h>
21e0b8e63eSJohn Marino #include <stdio.h>
22e0b8e63eSJohn Marino #include <stdlib.h>
23e0b8e63eSJohn Marino #include <string.h>
24e0b8e63eSJohn Marino #include <unistd.h>
25e0b8e63eSJohn Marino 
26e0b8e63eSJohn Marino #include "common.h"
27e0b8e63eSJohn Marino #include "../vi/vi.h"
28e0b8e63eSJohn Marino #include "pathnames.h"
29e0b8e63eSJohn Marino 
30e0b8e63eSJohn Marino static void	 attach(GS *);
31*b1ac2ebbSDaniel Fojt static int	 v_obsolete(char *[]);
32e0b8e63eSJohn Marino 
33e0b8e63eSJohn Marino /*
34e0b8e63eSJohn Marino  * editor --
35e0b8e63eSJohn Marino  *	Main editor routine.
36e0b8e63eSJohn Marino  *
37e0b8e63eSJohn Marino  * PUBLIC: int editor(GS *, int, char *[]);
38e0b8e63eSJohn Marino  */
39e0b8e63eSJohn Marino int
editor(GS * gp,int argc,char * argv[])40*b1ac2ebbSDaniel Fojt editor(GS *gp, int argc, char *argv[])
41e0b8e63eSJohn Marino {
42e0b8e63eSJohn Marino 	extern int optind;
43e0b8e63eSJohn Marino 	extern char *optarg;
44e0b8e63eSJohn Marino 	const char *p;
45e0b8e63eSJohn Marino 	EVENT ev;
46e0b8e63eSJohn Marino 	FREF *frp;
47e0b8e63eSJohn Marino 	SCR *sp;
48e0b8e63eSJohn Marino 	size_t len;
49e0b8e63eSJohn Marino 	u_int flags;
50e0b8e63eSJohn Marino 	int ch, flagchk, lflag, secure, startup, readonly, rval, silent;
51e0b8e63eSJohn Marino 	char *tag_f, *wsizearg, path[256];
52e0b8e63eSJohn Marino 	CHAR_T *w;
53e0b8e63eSJohn Marino 	size_t wlen;
54e0b8e63eSJohn Marino 
55e0b8e63eSJohn Marino 	/* Initialize the busy routine, if not defined by the screen. */
56e0b8e63eSJohn Marino 	if (gp->scr_busy == NULL)
57e0b8e63eSJohn Marino 		gp->scr_busy = vs_busy;
58e0b8e63eSJohn Marino 	/* Initialize the message routine, if not defined by the screen. */
59e0b8e63eSJohn Marino 	if (gp->scr_msg == NULL)
60e0b8e63eSJohn Marino 		gp->scr_msg = vs_msg;
61e0b8e63eSJohn Marino 	gp->catd = (nl_catd)-1;
62e0b8e63eSJohn Marino 
63e0b8e63eSJohn Marino 	/* Common global structure initialization. */
64e0b8e63eSJohn Marino 	TAILQ_INIT(gp->dq);
65e0b8e63eSJohn Marino 	TAILQ_INIT(gp->hq);
66e0b8e63eSJohn Marino 	SLIST_INIT(gp->ecq);
67e0b8e63eSJohn Marino 	SLIST_INSERT_HEAD(gp->ecq, &gp->excmd, q);
68e0b8e63eSJohn Marino 	gp->noprint = DEFAULT_NOPRINT;
69e0b8e63eSJohn Marino 
70e0b8e63eSJohn Marino 	/* Structures shared by screens so stored in the GS structure. */
71e0b8e63eSJohn Marino 	TAILQ_INIT(gp->frefq);
72e0b8e63eSJohn Marino 	TAILQ_INIT(gp->dcb_store.textq);
73e0b8e63eSJohn Marino 	SLIST_INIT(gp->cutq);
74e0b8e63eSJohn Marino 	SLIST_INIT(gp->seqq);
75e0b8e63eSJohn Marino 
76e0b8e63eSJohn Marino 	/* Set initial screen type and mode based on the program name. */
77e0b8e63eSJohn Marino 	readonly = 0;
78*b1ac2ebbSDaniel Fojt 	if (!strcmp(getprogname(), "ex") || !strcmp(getprogname(), "nex"))
79e0b8e63eSJohn Marino 		LF_INIT(SC_EX);
80e0b8e63eSJohn Marino 	else {
81e0b8e63eSJohn Marino 		/* Nview, view are readonly. */
82*b1ac2ebbSDaniel Fojt 		if (!strcmp(getprogname(), "nview") ||
83*b1ac2ebbSDaniel Fojt 		    !strcmp(getprogname(), "view"))
84e0b8e63eSJohn Marino 			readonly = 1;
85e0b8e63eSJohn Marino 
86e0b8e63eSJohn Marino 		/* Vi is the default. */
87e0b8e63eSJohn Marino 		LF_INIT(SC_VI);
88e0b8e63eSJohn Marino 	}
89e0b8e63eSJohn Marino 
90e0b8e63eSJohn Marino 	/* Convert old-style arguments into new-style ones. */
91*b1ac2ebbSDaniel Fojt 	if (v_obsolete(argv))
92e0b8e63eSJohn Marino 		return (1);
93e0b8e63eSJohn Marino 
94e0b8e63eSJohn Marino 	/* Parse the arguments. */
95e0b8e63eSJohn Marino 	flagchk = '\0';
96e0b8e63eSJohn Marino 	tag_f = wsizearg = NULL;
97e0b8e63eSJohn Marino 	lflag = secure = silent = 0;
98e0b8e63eSJohn Marino 	startup = 1;
99e0b8e63eSJohn Marino 
100e0b8e63eSJohn Marino 	/* Set the file snapshot flag. */
101e0b8e63eSJohn Marino 	F_SET(gp, G_SNAPSHOT);
102e0b8e63eSJohn Marino 
103e0b8e63eSJohn Marino #ifdef DEBUG
104e0b8e63eSJohn Marino 	while ((ch = getopt(argc, argv, "c:D:eFlRrSsT:t:vw:")) != EOF)
105e0b8e63eSJohn Marino #else
106e0b8e63eSJohn Marino 	while ((ch = getopt(argc, argv, "c:eFlRrSst:vw:")) != EOF)
107e0b8e63eSJohn Marino #endif
108e0b8e63eSJohn Marino 		switch (ch) {
109e0b8e63eSJohn Marino 		case 'c':		/* Run the command. */
110e0b8e63eSJohn Marino 			/*
111e0b8e63eSJohn Marino 			 * XXX
112e0b8e63eSJohn Marino 			 * We should support multiple -c options.
113e0b8e63eSJohn Marino 			 */
114e0b8e63eSJohn Marino 			if (gp->c_option != NULL) {
115*b1ac2ebbSDaniel Fojt 				warnx("only one -c command may be specified.");
116e0b8e63eSJohn Marino 				return (1);
117e0b8e63eSJohn Marino 			}
118e0b8e63eSJohn Marino 			gp->c_option = optarg;
119e0b8e63eSJohn Marino 			break;
120e0b8e63eSJohn Marino #ifdef DEBUG
121e0b8e63eSJohn Marino 		case 'D':
122e0b8e63eSJohn Marino 			switch (optarg[0]) {
123e0b8e63eSJohn Marino 			case 's':
124e0b8e63eSJohn Marino 				startup = 0;
125e0b8e63eSJohn Marino 				break;
126e0b8e63eSJohn Marino 			case 'w':
127e0b8e63eSJohn Marino 				attach(gp);
128e0b8e63eSJohn Marino 				break;
129e0b8e63eSJohn Marino 			default:
130*b1ac2ebbSDaniel Fojt 				warnx("usage: -D requires s or w argument.");
131e0b8e63eSJohn Marino 				return (1);
132e0b8e63eSJohn Marino 			}
133e0b8e63eSJohn Marino 			break;
134e0b8e63eSJohn Marino #endif
135e0b8e63eSJohn Marino 		case 'e':		/* Ex mode. */
136e0b8e63eSJohn Marino 			LF_CLR(SC_VI);
137e0b8e63eSJohn Marino 			LF_SET(SC_EX);
138e0b8e63eSJohn Marino 			break;
139e0b8e63eSJohn Marino 		case 'F':		/* No snapshot. */
140e0b8e63eSJohn Marino 			F_CLR(gp, G_SNAPSHOT);
141e0b8e63eSJohn Marino 			break;
142e0b8e63eSJohn Marino 		case 'l':		/* Set lisp, showmatch options. */
143e0b8e63eSJohn Marino 			lflag = 1;
144e0b8e63eSJohn Marino 			break;
145e0b8e63eSJohn Marino 		case 'R':		/* Readonly. */
146e0b8e63eSJohn Marino 			readonly = 1;
147e0b8e63eSJohn Marino 			break;
148e0b8e63eSJohn Marino 		case 'r':		/* Recover. */
149e0b8e63eSJohn Marino 			if (flagchk == 't') {
150*b1ac2ebbSDaniel Fojt 				warnx("only one of -r and -t may be specified.");
151e0b8e63eSJohn Marino 				return (1);
152e0b8e63eSJohn Marino 			}
153e0b8e63eSJohn Marino 			flagchk = 'r';
154e0b8e63eSJohn Marino 			break;
155e0b8e63eSJohn Marino 		case 'S':
156e0b8e63eSJohn Marino 			secure = 1;
157e0b8e63eSJohn Marino 			break;
158e0b8e63eSJohn Marino 		case 's':
159e0b8e63eSJohn Marino 			silent = 1;
160e0b8e63eSJohn Marino 			break;
161e0b8e63eSJohn Marino #ifdef DEBUG
162e0b8e63eSJohn Marino 		case 'T':		/* Trace. */
163e0b8e63eSJohn Marino 			if ((gp->tracefp = fopen(optarg, "w")) == NULL) {
164*b1ac2ebbSDaniel Fojt 				warn("%s", optarg);
165e0b8e63eSJohn Marino 				goto err;
166e0b8e63eSJohn Marino 			}
167e0b8e63eSJohn Marino 			(void)fprintf(gp->tracefp,
168e0b8e63eSJohn Marino 			    "\n===\ntrace: open %s\n", optarg);
169e0b8e63eSJohn Marino 			break;
170e0b8e63eSJohn Marino #endif
171e0b8e63eSJohn Marino 		case 't':		/* Tag. */
172e0b8e63eSJohn Marino 			if (flagchk == 'r') {
173*b1ac2ebbSDaniel Fojt 				warnx("only one of -r and -t may be specified.");
174e0b8e63eSJohn Marino 				return (1);
175e0b8e63eSJohn Marino 			}
176e0b8e63eSJohn Marino 			if (flagchk == 't') {
177*b1ac2ebbSDaniel Fojt 				warnx("only one tag file may be specified.");
178e0b8e63eSJohn Marino 				return (1);
179e0b8e63eSJohn Marino 			}
180e0b8e63eSJohn Marino 			flagchk = 't';
181e0b8e63eSJohn Marino 			tag_f = optarg;
182e0b8e63eSJohn Marino 			break;
183e0b8e63eSJohn Marino 		case 'v':		/* Vi mode. */
184e0b8e63eSJohn Marino 			LF_CLR(SC_EX);
185e0b8e63eSJohn Marino 			LF_SET(SC_VI);
186e0b8e63eSJohn Marino 			break;
187e0b8e63eSJohn Marino 		case 'w':
188e0b8e63eSJohn Marino 			wsizearg = optarg;
189e0b8e63eSJohn Marino 			break;
190e0b8e63eSJohn Marino 		case '?':
191e0b8e63eSJohn Marino 		default:
192e0b8e63eSJohn Marino 			(void)gp->scr_usage();
193e0b8e63eSJohn Marino 			return (1);
194e0b8e63eSJohn Marino 		}
195e0b8e63eSJohn Marino 	argc -= optind;
196e0b8e63eSJohn Marino 	argv += optind;
197e0b8e63eSJohn Marino 
198e0b8e63eSJohn Marino 	/*
199e0b8e63eSJohn Marino 	 * -s option is only meaningful to ex.
200e0b8e63eSJohn Marino 	 *
201e0b8e63eSJohn Marino 	 * If not reading from a terminal, it's like -s was specified.
202e0b8e63eSJohn Marino 	 */
203e0b8e63eSJohn Marino 	if (silent && !LF_ISSET(SC_EX)) {
204*b1ac2ebbSDaniel Fojt 		warnx("-s option is only applicable to ex.");
205e0b8e63eSJohn Marino 		goto err;
206e0b8e63eSJohn Marino 	}
207e0b8e63eSJohn Marino 	if (LF_ISSET(SC_EX) && F_ISSET(gp, G_SCRIPTED))
208e0b8e63eSJohn Marino 		silent = 1;
209e0b8e63eSJohn Marino 
210e0b8e63eSJohn Marino 	/*
211e0b8e63eSJohn Marino 	 * Build and initialize the first/current screen.  This is a bit
212e0b8e63eSJohn Marino 	 * tricky.  If an error is returned, we may or may not have a
213e0b8e63eSJohn Marino 	 * screen structure.  If we have a screen structure, put it on a
214e0b8e63eSJohn Marino 	 * display queue so that the error messages get displayed.
215e0b8e63eSJohn Marino 	 *
216e0b8e63eSJohn Marino 	 * !!!
217e0b8e63eSJohn Marino 	 * Everything we do until we go interactive is done in ex mode.
218e0b8e63eSJohn Marino 	 */
219e0b8e63eSJohn Marino 	if (screen_init(gp, NULL, &sp)) {
220e0b8e63eSJohn Marino 		if (sp != NULL)
221e0b8e63eSJohn Marino 			TAILQ_INSERT_HEAD(gp->dq, sp, q);
222e0b8e63eSJohn Marino 		goto err;
223e0b8e63eSJohn Marino 	}
224e0b8e63eSJohn Marino 	F_SET(sp, SC_EX);
225e0b8e63eSJohn Marino 	TAILQ_INSERT_HEAD(gp->dq, sp, q);
226e0b8e63eSJohn Marino 
227e0b8e63eSJohn Marino 	if (v_key_init(sp))		/* Special key initialization. */
228e0b8e63eSJohn Marino 		goto err;
229e0b8e63eSJohn Marino 
230e0b8e63eSJohn Marino 	{ int oargs[5], *oargp = oargs;
231e0b8e63eSJohn Marino 	if (lflag) {			/* Command-line options. */
232e0b8e63eSJohn Marino 		*oargp++ = O_LISP;
233e0b8e63eSJohn Marino 		*oargp++ = O_SHOWMATCH;
234e0b8e63eSJohn Marino 	}
235e0b8e63eSJohn Marino 	if (readonly)
236e0b8e63eSJohn Marino 		*oargp++ = O_READONLY;
237e0b8e63eSJohn Marino 	if (secure)
238e0b8e63eSJohn Marino 		*oargp++ = O_SECURE;
239e0b8e63eSJohn Marino 	*oargp = -1;			/* Options initialization. */
240e0b8e63eSJohn Marino 	if (opts_init(sp, oargs))
241e0b8e63eSJohn Marino 		goto err;
242e0b8e63eSJohn Marino 	}
243e0b8e63eSJohn Marino 	if (wsizearg != NULL) {
244e0b8e63eSJohn Marino 		ARGS *av[2], a, b;
245e0b8e63eSJohn Marino 		(void)snprintf(path, sizeof(path), "window=%s", wsizearg);
246e0b8e63eSJohn Marino 		a.bp = (CHAR_T *)path;
247e0b8e63eSJohn Marino 		a.len = strlen(path);
248e0b8e63eSJohn Marino 		b.bp = NULL;
249e0b8e63eSJohn Marino 		b.len = 0;
250e0b8e63eSJohn Marino 		av[0] = &a;
251e0b8e63eSJohn Marino 		av[1] = &b;
252e0b8e63eSJohn Marino 		(void)opts_set(sp, av, NULL);
253e0b8e63eSJohn Marino 	}
254e0b8e63eSJohn Marino 	if (silent) {			/* Ex batch mode option values. */
255e0b8e63eSJohn Marino 		O_CLR(sp, O_AUTOPRINT);
256e0b8e63eSJohn Marino 		O_CLR(sp, O_PROMPT);
257e0b8e63eSJohn Marino 		O_CLR(sp, O_VERBOSE);
258e0b8e63eSJohn Marino 		O_CLR(sp, O_WARN);
259e0b8e63eSJohn Marino 		F_SET(sp, SC_EX_SILENT);
260e0b8e63eSJohn Marino 	}
261e0b8e63eSJohn Marino 
262e0b8e63eSJohn Marino 	sp->rows = O_VAL(sp, O_LINES);	/* Make ex formatting work. */
263e0b8e63eSJohn Marino 	sp->cols = O_VAL(sp, O_COLUMNS);
264e0b8e63eSJohn Marino 
265e0b8e63eSJohn Marino 	if (!silent && startup) {	/* Read EXINIT, exrc files. */
266e0b8e63eSJohn Marino 		if (ex_exrc(sp))
267e0b8e63eSJohn Marino 			goto err;
268e0b8e63eSJohn Marino 		if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
269e0b8e63eSJohn Marino 			if (screen_end(sp))
270e0b8e63eSJohn Marino 				goto err;
271e0b8e63eSJohn Marino 			goto done;
272e0b8e63eSJohn Marino 		}
273e0b8e63eSJohn Marino 	}
274e0b8e63eSJohn Marino 
275e0b8e63eSJohn Marino 	/*
276e0b8e63eSJohn Marino 	 * List recovery files if -r specified without file arguments.
277e0b8e63eSJohn Marino 	 * Note, options must be initialized and startup information
278e0b8e63eSJohn Marino 	 * read before doing this.
279e0b8e63eSJohn Marino 	 */
280e0b8e63eSJohn Marino 	if (flagchk == 'r' && argv[0] == NULL) {
281e0b8e63eSJohn Marino 		if (rcv_list(sp))
282e0b8e63eSJohn Marino 			goto err;
283e0b8e63eSJohn Marino 		if (screen_end(sp))
284e0b8e63eSJohn Marino 			goto err;
285e0b8e63eSJohn Marino 		goto done;
286e0b8e63eSJohn Marino 	}
287e0b8e63eSJohn Marino 
288e0b8e63eSJohn Marino 	/*
289e0b8e63eSJohn Marino 	 * !!!
290e0b8e63eSJohn Marino 	 * Initialize the default ^D, ^U scrolling value here, after the
291e0b8e63eSJohn Marino 	 * user has had every opportunity to set the window option.
292e0b8e63eSJohn Marino 	 *
293e0b8e63eSJohn Marino 	 * It's historic practice that changing the value of the window
294e0b8e63eSJohn Marino 	 * option did not alter the default scrolling value, only giving
295e0b8e63eSJohn Marino 	 * a count to ^D/^U did that.
296e0b8e63eSJohn Marino 	 */
297e0b8e63eSJohn Marino 	sp->defscroll = (O_VAL(sp, O_WINDOW) + 1) / 2;
298e0b8e63eSJohn Marino 
299e0b8e63eSJohn Marino 	/*
300e0b8e63eSJohn Marino 	 * If we don't have a command-line option, switch into the right
301e0b8e63eSJohn Marino 	 * editor now, so that we position default files correctly, and
302e0b8e63eSJohn Marino 	 * so that any tags file file-already-locked messages are in the
303e0b8e63eSJohn Marino 	 * vi screen, not the ex screen.
304e0b8e63eSJohn Marino 	 *
305e0b8e63eSJohn Marino 	 * XXX
306e0b8e63eSJohn Marino 	 * If we have a command-line option, the error message can end
307e0b8e63eSJohn Marino 	 * up in the wrong place, but I think that the combination is
308e0b8e63eSJohn Marino 	 * unlikely.
309e0b8e63eSJohn Marino 	 */
310e0b8e63eSJohn Marino 	if (gp->c_option == NULL) {
311e0b8e63eSJohn Marino 		F_CLR(sp, SC_EX | SC_VI);
312e0b8e63eSJohn Marino 		F_SET(sp, LF_ISSET(SC_EX | SC_VI));
313e0b8e63eSJohn Marino 	}
314e0b8e63eSJohn Marino 
315e0b8e63eSJohn Marino 	/* Open a tag file if specified. */
316e0b8e63eSJohn Marino 	if (tag_f != NULL) {
317e0b8e63eSJohn Marino 		CHAR2INT(sp, tag_f, strlen(tag_f) + 1, w, wlen);
318e0b8e63eSJohn Marino 		if (ex_tag_first(sp, w))
319e0b8e63eSJohn Marino 			goto err;
320e0b8e63eSJohn Marino 	}
321e0b8e63eSJohn Marino 
322e0b8e63eSJohn Marino 	/*
323e0b8e63eSJohn Marino 	 * Append any remaining arguments as file names.  Files are recovery
324e0b8e63eSJohn Marino 	 * files if -r specified.  If the tag option or ex startup commands
325e0b8e63eSJohn Marino 	 * loaded a file, then any file arguments are going to come after it.
326e0b8e63eSJohn Marino 	 */
327e0b8e63eSJohn Marino 	if (*argv != NULL) {
328e0b8e63eSJohn Marino 		if (sp->frp != NULL) {
329e0b8e63eSJohn Marino 			/* Cheat -- we know we have an extra argv slot. */
330e0b8e63eSJohn Marino 			*--argv = strdup(sp->frp->name);
331e0b8e63eSJohn Marino 			if (*argv == NULL) {
332*b1ac2ebbSDaniel Fojt 				warn(NULL);
333e0b8e63eSJohn Marino 				goto err;
334e0b8e63eSJohn Marino 			}
335e0b8e63eSJohn Marino 		}
336e0b8e63eSJohn Marino 		sp->argv = sp->cargv = argv;
337e0b8e63eSJohn Marino 		F_SET(sp, SC_ARGNOFREE);
338e0b8e63eSJohn Marino 		if (flagchk == 'r')
339e0b8e63eSJohn Marino 			F_SET(sp, SC_ARGRECOVER);
340e0b8e63eSJohn Marino 	}
341e0b8e63eSJohn Marino 
342e0b8e63eSJohn Marino 	/*
343e0b8e63eSJohn Marino 	 * If the ex startup commands and or/the tag option haven't already
344e0b8e63eSJohn Marino 	 * created a file, create one.  If no command-line files were given,
345e0b8e63eSJohn Marino 	 * use a temporary file.
346e0b8e63eSJohn Marino 	 */
347e0b8e63eSJohn Marino 	if (sp->frp == NULL) {
348e0b8e63eSJohn Marino 		if (sp->argv == NULL) {
349e0b8e63eSJohn Marino 			if ((frp = file_add(sp, NULL)) == NULL)
350e0b8e63eSJohn Marino 				goto err;
351e0b8e63eSJohn Marino 		} else  {
352e0b8e63eSJohn Marino 			if ((frp = file_add(sp, sp->argv[0])) == NULL)
353e0b8e63eSJohn Marino 				goto err;
354e0b8e63eSJohn Marino 			if (F_ISSET(sp, SC_ARGRECOVER))
355e0b8e63eSJohn Marino 				F_SET(frp, FR_RECOVER);
356e0b8e63eSJohn Marino 		}
357e0b8e63eSJohn Marino 
358e0b8e63eSJohn Marino 		if (file_init(sp, frp, NULL, 0))
359e0b8e63eSJohn Marino 			goto err;
360e0b8e63eSJohn Marino 		if (EXCMD_RUNNING(gp)) {
361e0b8e63eSJohn Marino 			(void)ex_cmd(sp);
362e0b8e63eSJohn Marino 			if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) {
363e0b8e63eSJohn Marino 				if (screen_end(sp))
364e0b8e63eSJohn Marino 					goto err;
365e0b8e63eSJohn Marino 				goto done;
366e0b8e63eSJohn Marino 			}
367e0b8e63eSJohn Marino 		}
368e0b8e63eSJohn Marino 	}
369e0b8e63eSJohn Marino 
370e0b8e63eSJohn Marino 	/*
371e0b8e63eSJohn Marino 	 * Check to see if we need to wait for ex.  If SC_SCR_EX is set, ex
372e0b8e63eSJohn Marino 	 * was forced to initialize the screen during startup.  We'd like to
373e0b8e63eSJohn Marino 	 * wait for a single character from the user, but we can't because
374e0b8e63eSJohn Marino 	 * we're not in raw mode.  We can't switch to raw mode because the
375e0b8e63eSJohn Marino 	 * vi initialization will switch to xterm's alternate screen, causing
376e0b8e63eSJohn Marino 	 * us to lose the messages we're pausing to make sure the user read.
377e0b8e63eSJohn Marino 	 * So, wait for a complete line.
378e0b8e63eSJohn Marino 	 */
379e0b8e63eSJohn Marino 	if (F_ISSET(sp, SC_SCR_EX)) {
380e0b8e63eSJohn Marino 		p = msg_cmsg(sp, CMSG_CONT_R, &len);
381e0b8e63eSJohn Marino 		(void)write(STDOUT_FILENO, p, len);
382e0b8e63eSJohn Marino 		for (;;) {
383e0b8e63eSJohn Marino 			if (v_event_get(sp, &ev, 0, 0))
384e0b8e63eSJohn Marino 				goto err;
385e0b8e63eSJohn Marino 			if (ev.e_event == E_INTERRUPT ||
386e0b8e63eSJohn Marino 			    (ev.e_event == E_CHARACTER &&
387e0b8e63eSJohn Marino 			     (ev.e_value == K_CR || ev.e_value == K_NL)))
388e0b8e63eSJohn Marino 				break;
389e0b8e63eSJohn Marino 			(void)gp->scr_bell(sp);
390e0b8e63eSJohn Marino 		}
391e0b8e63eSJohn Marino 	}
392e0b8e63eSJohn Marino 
393e0b8e63eSJohn Marino 	/* Switch into the right editor, regardless. */
394e0b8e63eSJohn Marino 	F_CLR(sp, SC_EX | SC_VI);
395e0b8e63eSJohn Marino 	F_SET(sp, LF_ISSET(SC_EX | SC_VI) | SC_STATUS_CNT);
396e0b8e63eSJohn Marino 
397e0b8e63eSJohn Marino 	/*
398e0b8e63eSJohn Marino 	 * Main edit loop.  Vi handles split screens itself, we only return
399e0b8e63eSJohn Marino 	 * here when switching editor modes or restarting the screen.
400e0b8e63eSJohn Marino 	 */
401e0b8e63eSJohn Marino 	while (sp != NULL)
402e0b8e63eSJohn Marino 		if (F_ISSET(sp, SC_EX) ? ex(&sp) : vi(&sp))
403e0b8e63eSJohn Marino 			goto err;
404e0b8e63eSJohn Marino 
405e0b8e63eSJohn Marino done:	rval = 0;
406e0b8e63eSJohn Marino 	if (0)
407e0b8e63eSJohn Marino err:		rval = 1;
408e0b8e63eSJohn Marino 
409e0b8e63eSJohn Marino 	/* Clean out the global structure. */
410e0b8e63eSJohn Marino 	v_end(gp);
411e0b8e63eSJohn Marino 
412e0b8e63eSJohn Marino 	return (rval);
413e0b8e63eSJohn Marino }
414e0b8e63eSJohn Marino 
415e0b8e63eSJohn Marino /*
416e0b8e63eSJohn Marino  * v_end --
417e0b8e63eSJohn Marino  *	End the program, discarding screens and most of the global area.
418e0b8e63eSJohn Marino  *
419e0b8e63eSJohn Marino  * PUBLIC: void v_end(GS *);
420e0b8e63eSJohn Marino  */
421e0b8e63eSJohn Marino void
v_end(gp)422e0b8e63eSJohn Marino v_end(gp)
423e0b8e63eSJohn Marino 	GS *gp;
424e0b8e63eSJohn Marino {
425e0b8e63eSJohn Marino 	MSGS *mp;
426e0b8e63eSJohn Marino 	SCR *sp;
427e0b8e63eSJohn Marino 
428e0b8e63eSJohn Marino 	/* If there are any remaining screens, kill them off. */
429e0b8e63eSJohn Marino 	if (gp->ccl_sp != NULL) {
430e0b8e63eSJohn Marino 		(void)file_end(gp->ccl_sp, NULL, 1);
431e0b8e63eSJohn Marino 		(void)screen_end(gp->ccl_sp);
432e0b8e63eSJohn Marino 	}
433e0b8e63eSJohn Marino 	while ((sp = TAILQ_FIRST(gp->dq)) != NULL)
434e0b8e63eSJohn Marino 		(void)screen_end(sp);
435e0b8e63eSJohn Marino 	while ((sp = TAILQ_FIRST(gp->hq)) != NULL)
436e0b8e63eSJohn Marino 		(void)screen_end(sp);
437e0b8e63eSJohn Marino 
438e0b8e63eSJohn Marino #if defined(DEBUG) || defined(PURIFY)
439e0b8e63eSJohn Marino 	{ FREF *frp;
440e0b8e63eSJohn Marino 		/* Free FREF's. */
441e0b8e63eSJohn Marino 		while ((frp = TAILQ_FIRST(gp->frefq)) != NULL) {
442e0b8e63eSJohn Marino 			TAILQ_REMOVE(gp->frefq, frp, q);
443e0b8e63eSJohn Marino 			free(frp->name);
444e0b8e63eSJohn Marino 			free(frp->tname);
445e0b8e63eSJohn Marino 			free(frp);
446e0b8e63eSJohn Marino 		}
447e0b8e63eSJohn Marino 	}
448e0b8e63eSJohn Marino 
449e0b8e63eSJohn Marino 	/* Free key input queue. */
450e0b8e63eSJohn Marino 	free(gp->i_event);
451e0b8e63eSJohn Marino 
452e0b8e63eSJohn Marino 	/* Free cut buffers. */
453e0b8e63eSJohn Marino 	cut_close(gp);
454e0b8e63eSJohn Marino 
455e0b8e63eSJohn Marino 	/* Free map sequences. */
456e0b8e63eSJohn Marino 	seq_close(gp);
457e0b8e63eSJohn Marino 
458e0b8e63eSJohn Marino 	/* Free default buffer storage. */
459e0b8e63eSJohn Marino 	(void)text_lfree(gp->dcb_store.textq);
460e0b8e63eSJohn Marino 
461e0b8e63eSJohn Marino 	/* Close message catalogs. */
462e0b8e63eSJohn Marino 	msg_close(gp);
463e0b8e63eSJohn Marino #endif
464e0b8e63eSJohn Marino 
465e0b8e63eSJohn Marino 	/* Ring the bell if scheduled. */
466e0b8e63eSJohn Marino 	if (F_ISSET(gp, G_BELLSCHED))
467e0b8e63eSJohn Marino 		(void)fprintf(stderr, "\07");		/* \a */
468e0b8e63eSJohn Marino 
469e0b8e63eSJohn Marino 	/*
470e0b8e63eSJohn Marino 	 * Flush any remaining messages.  If a message is here, it's almost
471e0b8e63eSJohn Marino 	 * certainly the message about the event that killed us (although
472e0b8e63eSJohn Marino 	 * it's possible that the user is sourcing a file that exits from the
473e0b8e63eSJohn Marino 	 * editor).
474e0b8e63eSJohn Marino 	 */
475e0b8e63eSJohn Marino 	while ((mp = SLIST_FIRST(gp->msgq)) != NULL) {
476e0b8e63eSJohn Marino 		(void)fprintf(stderr, "%s%.*s",
477e0b8e63eSJohn Marino 		    mp->mtype == M_ERR ? "ex/vi: " : "", (int)mp->len, mp->buf);
478e0b8e63eSJohn Marino 		SLIST_REMOVE_HEAD(gp->msgq, q);
479e0b8e63eSJohn Marino #if defined(DEBUG) || defined(PURIFY)
480e0b8e63eSJohn Marino 		free(mp->buf);
481e0b8e63eSJohn Marino 		free(mp);
482e0b8e63eSJohn Marino #endif
483e0b8e63eSJohn Marino 	}
484e0b8e63eSJohn Marino 
485e0b8e63eSJohn Marino #if defined(DEBUG) || defined(PURIFY)
486e0b8e63eSJohn Marino 	/* Free any temporary space. */
487e0b8e63eSJohn Marino 	free(gp->tmp_bp);
488e0b8e63eSJohn Marino 
489e0b8e63eSJohn Marino #if defined(DEBUG)
490e0b8e63eSJohn Marino 	/* Close debugging file descriptor. */
491e0b8e63eSJohn Marino 	if (gp->tracefp != NULL)
492e0b8e63eSJohn Marino 		(void)fclose(gp->tracefp);
493e0b8e63eSJohn Marino #endif
494e0b8e63eSJohn Marino #endif
495e0b8e63eSJohn Marino }
496e0b8e63eSJohn Marino 
497e0b8e63eSJohn Marino /*
498e0b8e63eSJohn Marino  * v_obsolete --
499e0b8e63eSJohn Marino  *	Convert historic arguments into something getopt(3) will like.
500e0b8e63eSJohn Marino  */
501e0b8e63eSJohn Marino static int
v_obsolete(char * argv[])502*b1ac2ebbSDaniel Fojt v_obsolete(char *argv[])
503e0b8e63eSJohn Marino {
504e0b8e63eSJohn Marino 	size_t len;
505e0b8e63eSJohn Marino 	char *p;
506e0b8e63eSJohn Marino 
507e0b8e63eSJohn Marino 	/*
508e0b8e63eSJohn Marino 	 * Translate old style arguments into something getopt will like.
509e0b8e63eSJohn Marino 	 * Make sure it's not text space memory, because ex modifies the
510e0b8e63eSJohn Marino 	 * strings.
511e0b8e63eSJohn Marino 	 *	Change "+" into "-c$".
512e0b8e63eSJohn Marino 	 *	Change "+<anything else>" into "-c<anything else>".
513e0b8e63eSJohn Marino 	 *	Change "-" into "-s"
514e0b8e63eSJohn Marino 	 *	The c, T, t and w options take arguments so they can't be
515e0b8e63eSJohn Marino 	 *	    special arguments.
516e0b8e63eSJohn Marino 	 *
517e0b8e63eSJohn Marino 	 * Stop if we find "--" as an argument, the user may want to edit
518e0b8e63eSJohn Marino 	 * a file named "+foo".
519e0b8e63eSJohn Marino 	 */
520e0b8e63eSJohn Marino 	while (*++argv && strcmp(argv[0], "--"))
521e0b8e63eSJohn Marino 		if (argv[0][0] == '+') {
522e0b8e63eSJohn Marino 			if (argv[0][1] == '\0') {
523e0b8e63eSJohn Marino 				argv[0] = strdup("-c$");
524e0b8e63eSJohn Marino 				if (argv[0] == NULL)
525e0b8e63eSJohn Marino 					goto nomem;
526e0b8e63eSJohn Marino 			} else  {
527e0b8e63eSJohn Marino 				p = argv[0];
528e0b8e63eSJohn Marino 				len = strlen(argv[0]);
529e0b8e63eSJohn Marino 				argv[0] = malloc(len + 2);
530e0b8e63eSJohn Marino 				if (argv[0] == NULL)
531e0b8e63eSJohn Marino 					goto nomem;
532e0b8e63eSJohn Marino 				argv[0][0] = '-';
533e0b8e63eSJohn Marino 				argv[0][1] = 'c';
534e0b8e63eSJohn Marino 				(void)strlcpy(argv[0] + 2, p + 1, len);
535e0b8e63eSJohn Marino 			}
536e0b8e63eSJohn Marino 		} else if (argv[0][0] == '-')
537e0b8e63eSJohn Marino 			if (argv[0][1] == '\0') {
538e0b8e63eSJohn Marino 				argv[0] = strdup("-s");
539e0b8e63eSJohn Marino 				if (argv[0] == NULL) {
540*b1ac2ebbSDaniel Fojt nomem:					warn(NULL);
541e0b8e63eSJohn Marino 					return (1);
542e0b8e63eSJohn Marino 				}
543e0b8e63eSJohn Marino 			} else
544e0b8e63eSJohn Marino 				if ((argv[0][1] == 'c' || argv[0][1] == 'T' ||
545e0b8e63eSJohn Marino 				    argv[0][1] == 't' || argv[0][1] == 'w') &&
546e0b8e63eSJohn Marino 				    argv[0][2] == '\0')
547e0b8e63eSJohn Marino 					++argv;
548e0b8e63eSJohn Marino 	return (0);
549e0b8e63eSJohn Marino }
550e0b8e63eSJohn Marino 
551e0b8e63eSJohn Marino #ifdef DEBUG
552e0b8e63eSJohn Marino static void
attach(GS * gp)553e0b8e63eSJohn Marino attach(GS *gp)
554e0b8e63eSJohn Marino {
555e0b8e63eSJohn Marino 	int fd;
556e0b8e63eSJohn Marino 	char ch;
557e0b8e63eSJohn Marino 
558e0b8e63eSJohn Marino 	if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) {
559*b1ac2ebbSDaniel Fojt 		warn("%s", _PATH_TTY);
560e0b8e63eSJohn Marino 		return;
561e0b8e63eSJohn Marino 	}
562e0b8e63eSJohn Marino 
563e0b8e63eSJohn Marino 	(void)printf("process %lu waiting, enter <CR> to continue: ",
564e0b8e63eSJohn Marino 	    (u_long)getpid());
565e0b8e63eSJohn Marino 	(void)fflush(stdout);
566e0b8e63eSJohn Marino 
567e0b8e63eSJohn Marino 	do {
568e0b8e63eSJohn Marino 		if (read(fd, &ch, 1) != 1) {
569e0b8e63eSJohn Marino 			(void)close(fd);
570e0b8e63eSJohn Marino 			return;
571e0b8e63eSJohn Marino 		}
572e0b8e63eSJohn Marino 	} while (ch != '\n' && ch != '\r');
573e0b8e63eSJohn Marino 	(void)close(fd);
574e0b8e63eSJohn Marino }
575e0b8e63eSJohn Marino #endif
576