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