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