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