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