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