1 |
|
|
/* $OpenBSD: ex_args.c,v 1.12 2016/01/06 22:28:52 millert Exp $ */ |
2 |
|
|
|
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 1991, 1993, 1994 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* Copyright (c) 1991, 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/time.h> |
17 |
|
|
|
18 |
|
|
#include <bitstring.h> |
19 |
|
|
#include <errno.h> |
20 |
|
|
#include <limits.h> |
21 |
|
|
#include <stdio.h> |
22 |
|
|
#include <stdlib.h> |
23 |
|
|
#include <string.h> |
24 |
|
|
|
25 |
|
|
#include "../common/common.h" |
26 |
|
|
#include "../vi/vi.h" |
27 |
|
|
|
28 |
|
|
static int ex_N_next(SCR *, EXCMD *); |
29 |
|
|
|
30 |
|
|
/* |
31 |
|
|
* ex_next -- :next [+cmd] [files] |
32 |
|
|
* Edit the next file, optionally setting the list of files. |
33 |
|
|
* |
34 |
|
|
* !!! |
35 |
|
|
* The :next command behaved differently from the :rewind command in |
36 |
|
|
* historic vi. See nvi/docs/autowrite for details, but the basic |
37 |
|
|
* idea was that it ignored the force flag if the autowrite flag was |
38 |
|
|
* set. This implementation handles them all identically. |
39 |
|
|
* |
40 |
|
|
* PUBLIC: int ex_next(SCR *, EXCMD *); |
41 |
|
|
*/ |
42 |
|
|
int |
43 |
|
|
ex_next(SCR *sp, EXCMD *cmdp) |
44 |
|
|
{ |
45 |
|
|
ARGS **argv; |
46 |
|
|
FREF *frp; |
47 |
|
|
int noargs; |
48 |
|
|
char **ap; |
49 |
|
|
|
50 |
|
|
/* Check for file to move to. */ |
51 |
|
|
if (cmdp->argc == 0 && (sp->cargv == NULL || sp->cargv[1] == NULL)) { |
52 |
|
|
msgq(sp, M_ERR, "No more files to edit"); |
53 |
|
|
return (1); |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
if (F_ISSET(cmdp, E_NEWSCREEN)) { |
57 |
|
|
/* By default, edit the next file in the old argument list. */ |
58 |
|
|
if (cmdp->argc == 0) { |
59 |
|
|
if (argv_exp0(sp, |
60 |
|
|
cmdp, sp->cargv[1], strlen(sp->cargv[1]))) |
61 |
|
|
return (1); |
62 |
|
|
return (ex_edit(sp, cmdp)); |
63 |
|
|
} |
64 |
|
|
return (ex_N_next(sp, cmdp)); |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
/* Check modification. */ |
68 |
|
|
if (file_m1(sp, |
69 |
|
|
FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) |
70 |
|
|
return (1); |
71 |
|
|
|
72 |
|
|
/* Any arguments are a replacement file list. */ |
73 |
|
|
if (cmdp->argc) { |
74 |
|
|
/* Free the current list. */ |
75 |
|
|
if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) { |
76 |
|
|
for (ap = sp->argv; *ap != NULL; ++ap) |
77 |
|
|
free(*ap); |
78 |
|
|
free(sp->argv); |
79 |
|
|
} |
80 |
|
|
F_CLR(sp, SC_ARGNOFREE | SC_ARGRECOVER); |
81 |
|
|
sp->cargv = NULL; |
82 |
|
|
|
83 |
|
|
/* Create a new list. */ |
84 |
|
|
CALLOC_RET(sp, |
85 |
|
|
sp->argv, cmdp->argc + 1, sizeof(char *)); |
86 |
|
|
for (ap = sp->argv, |
87 |
|
|
argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) |
88 |
|
|
if ((*ap = |
89 |
|
|
v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL) |
90 |
|
|
return (1); |
91 |
|
|
*ap = NULL; |
92 |
|
|
|
93 |
|
|
/* Switch to the first file. */ |
94 |
|
|
sp->cargv = sp->argv; |
95 |
|
|
if ((frp = file_add(sp, *sp->cargv)) == NULL) |
96 |
|
|
return (1); |
97 |
|
|
noargs = 0; |
98 |
|
|
|
99 |
|
|
/* Display a file count with the welcome message. */ |
100 |
|
|
F_SET(sp, SC_STATUS_CNT); |
101 |
|
|
} else { |
102 |
|
|
if ((frp = file_add(sp, sp->cargv[1])) == NULL) |
103 |
|
|
return (1); |
104 |
|
|
if (F_ISSET(sp, SC_ARGRECOVER)) |
105 |
|
|
F_SET(frp, FR_RECOVER); |
106 |
|
|
noargs = 1; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
if (file_init(sp, frp, NULL, FS_SETALT | |
110 |
|
|
(FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) |
111 |
|
|
return (1); |
112 |
|
|
if (noargs) |
113 |
|
|
++sp->cargv; |
114 |
|
|
|
115 |
|
|
F_SET(sp, SC_FSWITCH); |
116 |
|
|
return (0); |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
/* |
120 |
|
|
* ex_N_next -- |
121 |
|
|
* New screen version of ex_next. |
122 |
|
|
*/ |
123 |
|
|
static int |
124 |
|
|
ex_N_next(SCR *sp, EXCMD *cmdp) |
125 |
|
|
{ |
126 |
|
|
SCR *new; |
127 |
|
|
FREF *frp; |
128 |
|
|
|
129 |
|
|
/* Get a new screen. */ |
130 |
|
|
if (screen_init(sp->gp, sp, &new)) |
131 |
|
|
return (1); |
132 |
|
|
if (vs_split(sp, new, 0)) { |
133 |
|
|
(void)screen_end(new); |
134 |
|
|
return (1); |
135 |
|
|
} |
136 |
|
|
|
137 |
|
|
/* Get a backing file. */ |
138 |
|
|
if ((frp = file_add(new, cmdp->argv[0]->bp)) == NULL || |
139 |
|
|
file_init(new, frp, NULL, |
140 |
|
|
(FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) { |
141 |
|
|
(void)vs_discard(new, NULL); |
142 |
|
|
(void)screen_end(new); |
143 |
|
|
return (1); |
144 |
|
|
} |
145 |
|
|
|
146 |
|
|
/* The arguments are a replacement file list. */ |
147 |
|
|
new->cargv = new->argv = ex_buildargv(sp, cmdp, NULL); |
148 |
|
|
|
149 |
|
|
/* Display a file count with the welcome message. */ |
150 |
|
|
F_SET(new, SC_STATUS_CNT); |
151 |
|
|
|
152 |
|
|
/* Set up the switch. */ |
153 |
|
|
sp->nextdisp = new; |
154 |
|
|
F_SET(sp, SC_SSWITCH); |
155 |
|
|
|
156 |
|
|
return (0); |
157 |
|
|
} |
158 |
|
|
|
159 |
|
|
/* |
160 |
|
|
* ex_prev -- :prev |
161 |
|
|
* Edit the previous file. |
162 |
|
|
* |
163 |
|
|
* PUBLIC: int ex_prev(SCR *, EXCMD *); |
164 |
|
|
*/ |
165 |
|
|
int |
166 |
|
|
ex_prev(SCR *sp, EXCMD *cmdp) |
167 |
|
|
{ |
168 |
|
|
FREF *frp; |
169 |
|
|
|
170 |
|
|
if (sp->cargv == sp->argv) { |
171 |
|
|
msgq(sp, M_ERR, "No previous files to edit"); |
172 |
|
|
return (1); |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
if (F_ISSET(cmdp, E_NEWSCREEN)) { |
176 |
|
|
if (argv_exp0(sp, cmdp, sp->cargv[-1], strlen(sp->cargv[-1]))) |
177 |
|
|
return (1); |
178 |
|
|
return (ex_edit(sp, cmdp)); |
179 |
|
|
} |
180 |
|
|
|
181 |
|
|
if (file_m1(sp, |
182 |
|
|
FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) |
183 |
|
|
return (1); |
184 |
|
|
|
185 |
|
|
if ((frp = file_add(sp, sp->cargv[-1])) == NULL) |
186 |
|
|
return (1); |
187 |
|
|
|
188 |
|
|
if (file_init(sp, frp, NULL, FS_SETALT | |
189 |
|
|
(FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) |
190 |
|
|
return (1); |
191 |
|
|
--sp->cargv; |
192 |
|
|
|
193 |
|
|
F_SET(sp, SC_FSWITCH); |
194 |
|
|
return (0); |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
/* |
198 |
|
|
* ex_rew -- :rew |
199 |
|
|
* Re-edit the list of files. |
200 |
|
|
* |
201 |
|
|
* !!! |
202 |
|
|
* Historic practice was that all files would start editing at the beginning |
203 |
|
|
* of the file. We don't get this right because we may have multiple screens |
204 |
|
|
* and we can't clear the FR_CURSORSET bit for a single screen. I don't see |
205 |
|
|
* anyone noticing, but if they do, we'll have to put information into the SCR |
206 |
|
|
* structure so we can keep track of it. |
207 |
|
|
* |
208 |
|
|
* PUBLIC: int ex_rew(SCR *, EXCMD *); |
209 |
|
|
*/ |
210 |
|
|
int |
211 |
|
|
ex_rew(SCR *sp, EXCMD *cmdp) |
212 |
|
|
{ |
213 |
|
|
FREF *frp; |
214 |
|
|
|
215 |
|
|
/* |
216 |
|
|
* !!! |
217 |
|
|
* Historic practice -- you can rewind to the current file. |
218 |
|
|
*/ |
219 |
|
|
if (sp->argv == NULL) { |
220 |
|
|
msgq(sp, M_ERR, "No previous files to rewind"); |
221 |
|
|
return (1); |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
if (file_m1(sp, |
225 |
|
|
FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) |
226 |
|
|
return (1); |
227 |
|
|
|
228 |
|
|
/* Switch to the first one. */ |
229 |
|
|
sp->cargv = sp->argv; |
230 |
|
|
if ((frp = file_add(sp, *sp->cargv)) == NULL) |
231 |
|
|
return (1); |
232 |
|
|
if (file_init(sp, frp, NULL, FS_SETALT | |
233 |
|
|
(FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) |
234 |
|
|
return (1); |
235 |
|
|
|
236 |
|
|
/* Switch and display a file count with the welcome message. */ |
237 |
|
|
F_SET(sp, SC_FSWITCH | SC_STATUS_CNT); |
238 |
|
|
|
239 |
|
|
return (0); |
240 |
|
|
} |
241 |
|
|
|
242 |
|
|
/* |
243 |
|
|
* ex_args -- :args |
244 |
|
|
* Display the list of files. |
245 |
|
|
* |
246 |
|
|
* PUBLIC: int ex_args(SCR *, EXCMD *); |
247 |
|
|
*/ |
248 |
|
|
int |
249 |
|
|
ex_args(SCR *sp, EXCMD *cmdp) |
250 |
|
|
{ |
251 |
|
|
int cnt, col, len, sep; |
252 |
|
|
char **ap; |
253 |
|
|
|
254 |
|
|
if (sp->argv == NULL) { |
255 |
|
|
(void)msgq(sp, M_ERR, "No file list to display"); |
256 |
|
|
return (0); |
257 |
|
|
} |
258 |
|
|
|
259 |
|
|
col = len = sep = 0; |
260 |
|
|
for (cnt = 1, ap = sp->argv; *ap != NULL; ++ap) { |
261 |
|
|
col += len = strlen(*ap) + sep + (ap == sp->cargv ? 2 : 0); |
262 |
|
|
if (col >= sp->cols - 1) { |
263 |
|
|
col = len; |
264 |
|
|
sep = 0; |
265 |
|
|
(void)ex_puts(sp, "\n"); |
266 |
|
|
} else if (cnt != 1) { |
267 |
|
|
sep = 1; |
268 |
|
|
(void)ex_puts(sp, " "); |
269 |
|
|
} |
270 |
|
|
++cnt; |
271 |
|
|
|
272 |
|
|
(void)ex_printf(sp, "%s%s%s", ap == sp->cargv ? "[" : "", |
273 |
|
|
*ap, ap == sp->cargv ? "]" : ""); |
274 |
|
|
if (INTERRUPTED(sp)) |
275 |
|
|
break; |
276 |
|
|
} |
277 |
|
|
(void)ex_puts(sp, "\n"); |
278 |
|
|
return (0); |
279 |
|
|
} |
280 |
|
|
|
281 |
|
|
/* |
282 |
|
|
* ex_buildargv -- |
283 |
|
|
* Build a new file argument list. |
284 |
|
|
* |
285 |
|
|
* PUBLIC: char **ex_buildargv(SCR *, EXCMD *, char *); |
286 |
|
|
*/ |
287 |
|
|
char ** |
288 |
|
|
ex_buildargv(SCR *sp, EXCMD *cmdp, char *name) |
289 |
|
|
{ |
290 |
|
|
ARGS **argv; |
291 |
|
|
int argc; |
292 |
|
|
char **ap, **s_argv; |
293 |
|
|
|
294 |
|
|
argc = cmdp == NULL ? 1 : cmdp->argc; |
295 |
|
|
CALLOC(sp, s_argv, argc + 1, sizeof(char *)); |
296 |
|
|
if ((ap = s_argv) == NULL) |
297 |
|
|
return (NULL); |
298 |
|
|
|
299 |
|
|
if (cmdp == NULL) { |
300 |
|
|
if ((*ap = v_strdup(sp, name, strlen(name))) == NULL) { |
301 |
|
|
free(s_argv); |
302 |
|
|
return (NULL); |
303 |
|
|
} |
304 |
|
|
++ap; |
305 |
|
|
} else |
306 |
|
|
for (argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) |
307 |
|
|
if ((*ap = |
308 |
|
|
v_strdup(sp, argv[0]->bp, argv[0]->len)) == NULL) { |
309 |
|
|
while (--ap >= s_argv) |
310 |
|
|
free(*ap); |
311 |
|
|
free(s_argv); |
312 |
|
|
return (NULL); |
313 |
|
|
} |
314 |
|
|
*ap = NULL; |
315 |
|
|
return (s_argv); |
316 |
|
|
} |