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