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