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