119304Speter/*- 219304Speter * Copyright (c) 1991, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1991, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: ex_args.c,v 10.19 2011/12/16 16:18:10 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <errno.h> 2219304Speter#include <limits.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter 2719304Speter#include "../common/common.h" 2819304Speter#include "../vi/vi.h" 2919304Speter 30281373Sbaptstatic int ex_N_next(SCR *, EXCMD *); 3119304Speter 3219304Speter/* 3319304Speter * ex_next -- :next [+cmd] [files] 3419304Speter * Edit the next file, optionally setting the list of files. 3519304Speter * 3619304Speter * !!! 3719304Speter * The :next command behaved differently from the :rewind command in 3819304Speter * historic vi. See nvi/docs/autowrite for details, but the basic 3919304Speter * idea was that it ignored the force flag if the autowrite flag was 4019304Speter * set. This implementation handles them all identically. 4119304Speter * 42281373Sbapt * PUBLIC: int ex_next(SCR *, EXCMD *); 4319304Speter */ 4419304Speterint 45254225Speterex_next(SCR *sp, EXCMD *cmdp) 4619304Speter{ 4719304Speter ARGS **argv; 4819304Speter FREF *frp; 4919304Speter int noargs; 5019304Speter char **ap; 51254225Speter CHAR_T *wp; 52254225Speter size_t wlen; 53254225Speter char *np; 54254225Speter size_t nlen; 5519304Speter 5619304Speter /* Check for file to move to. */ 5719304Speter if (cmdp->argc == 0 && (sp->cargv == NULL || sp->cargv[1] == NULL)) { 5819304Speter msgq(sp, M_ERR, "111|No more files to edit"); 5919304Speter return (1); 6019304Speter } 6119304Speter 6219304Speter if (F_ISSET(cmdp, E_NEWSCREEN)) { 6319304Speter /* By default, edit the next file in the old argument list. */ 6419304Speter if (cmdp->argc == 0) { 65254225Speter CHAR2INT(sp, sp->cargv[1], strlen(sp->cargv[1]) + 1, 66254225Speter wp, wlen); 67254225Speter if (argv_exp0(sp, cmdp, wp, wlen - 1)) 6819304Speter return (1); 6919304Speter return (ex_edit(sp, cmdp)); 7019304Speter } 7119304Speter return (ex_N_next(sp, cmdp)); 7219304Speter } 7319304Speter 7419304Speter /* Check modification. */ 7519304Speter if (file_m1(sp, 7619304Speter FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) 7719304Speter return (1); 7819304Speter 7919304Speter /* Any arguments are a replacement file list. */ 8019304Speter if (cmdp->argc) { 8119304Speter /* Free the current list. */ 8219304Speter if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) { 8319304Speter for (ap = sp->argv; *ap != NULL; ++ap) 8419304Speter free(*ap); 8519304Speter free(sp->argv); 8619304Speter } 8719304Speter F_CLR(sp, SC_ARGNOFREE | SC_ARGRECOVER); 8819304Speter sp->cargv = NULL; 8919304Speter 9019304Speter /* Create a new list. */ 9119304Speter CALLOC_RET(sp, 9219304Speter sp->argv, char **, cmdp->argc + 1, sizeof(char *)); 9319304Speter for (ap = sp->argv, 94254225Speter argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) { 95254225Speter INT2CHAR(sp, argv[0]->bp, argv[0]->len, np, nlen); 96254225Speter if ((*ap = v_strdup(sp, np, nlen)) == NULL) 9719304Speter return (1); 98254225Speter } 9919304Speter *ap = NULL; 10019304Speter 10119304Speter /* Switch to the first file. */ 10219304Speter sp->cargv = sp->argv; 10319304Speter if ((frp = file_add(sp, *sp->cargv)) == NULL) 10419304Speter return (1); 10519304Speter noargs = 0; 10619304Speter 10719304Speter /* Display a file count with the welcome message. */ 10819304Speter F_SET(sp, SC_STATUS_CNT); 10919304Speter } else { 11019304Speter if ((frp = file_add(sp, sp->cargv[1])) == NULL) 11119304Speter return (1); 11219304Speter if (F_ISSET(sp, SC_ARGRECOVER)) 11319304Speter F_SET(frp, FR_RECOVER); 11419304Speter noargs = 1; 11519304Speter } 11619304Speter 11719304Speter if (file_init(sp, frp, NULL, FS_SETALT | 11819304Speter (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) 11919304Speter return (1); 12019304Speter if (noargs) 12119304Speter ++sp->cargv; 12219304Speter 12319304Speter F_SET(sp, SC_FSWITCH); 12419304Speter return (0); 12519304Speter} 12619304Speter 12719304Speter/* 12819304Speter * ex_N_next -- 12919304Speter * New screen version of ex_next. 13019304Speter */ 13119304Speterstatic int 132254225Speterex_N_next(SCR *sp, EXCMD *cmdp) 13319304Speter{ 13419304Speter SCR *new; 13519304Speter FREF *frp; 136254225Speter char *np; 137254225Speter size_t nlen; 13819304Speter 13919304Speter /* Get a new screen. */ 14019304Speter if (screen_init(sp->gp, sp, &new)) 14119304Speter return (1); 14219304Speter if (vs_split(sp, new, 0)) { 14319304Speter (void)screen_end(new); 14419304Speter return (1); 14519304Speter } 14619304Speter 14719304Speter /* Get a backing file. */ 148254225Speter INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1, np, nlen); 149254225Speter if ((frp = file_add(new, np)) == NULL || 15019304Speter file_init(new, frp, NULL, 15119304Speter (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) { 15219304Speter (void)vs_discard(new, NULL); 15319304Speter (void)screen_end(new); 15419304Speter return (1); 15519304Speter } 15619304Speter 15719304Speter /* The arguments are a replacement file list. */ 15819304Speter new->cargv = new->argv = ex_buildargv(sp, cmdp, NULL); 15919304Speter 16019304Speter /* Display a file count with the welcome message. */ 16119304Speter F_SET(new, SC_STATUS_CNT); 16219304Speter 16319304Speter /* Set up the switch. */ 16419304Speter sp->nextdisp = new; 16519304Speter F_SET(sp, SC_SSWITCH); 16619304Speter 16719304Speter return (0); 16819304Speter} 16919304Speter 17019304Speter/* 17119304Speter * ex_prev -- :prev 17219304Speter * Edit the previous file. 17319304Speter * 174281373Sbapt * PUBLIC: int ex_prev(SCR *, EXCMD *); 17519304Speter */ 17619304Speterint 177254225Speterex_prev(SCR *sp, EXCMD *cmdp) 17819304Speter{ 17919304Speter FREF *frp; 180254225Speter size_t wlen; 181254225Speter CHAR_T *wp; 18219304Speter 18319304Speter if (sp->cargv == sp->argv) { 18419304Speter msgq(sp, M_ERR, "112|No previous files to edit"); 18519304Speter return (1); 18619304Speter } 18719304Speter 18819304Speter if (F_ISSET(cmdp, E_NEWSCREEN)) { 189254225Speter CHAR2INT(sp, sp->cargv[-1], strlen(sp->cargv[-1]) + 1, 190254225Speter wp, wlen); 191254225Speter if (argv_exp0(sp, cmdp, wp, wlen - 1)) 19219304Speter return (1); 19319304Speter return (ex_edit(sp, cmdp)); 19419304Speter } 19519304Speter 19619304Speter if (file_m1(sp, 19719304Speter FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) 19819304Speter return (1); 19919304Speter 20019304Speter if ((frp = file_add(sp, sp->cargv[-1])) == NULL) 20119304Speter return (1); 20219304Speter 20319304Speter if (file_init(sp, frp, NULL, FS_SETALT | 20419304Speter (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) 20519304Speter return (1); 20619304Speter --sp->cargv; 20719304Speter 20819304Speter F_SET(sp, SC_FSWITCH); 20919304Speter return (0); 21019304Speter} 21119304Speter 21219304Speter/* 21319304Speter * ex_rew -- :rew 21419304Speter * Re-edit the list of files. 21519304Speter * 21619304Speter * !!! 21719304Speter * Historic practice was that all files would start editing at the beginning 21819304Speter * of the file. We don't get this right because we may have multiple screens 21919304Speter * and we can't clear the FR_CURSORSET bit for a single screen. I don't see 22019304Speter * anyone noticing, but if they do, we'll have to put information into the SCR 22119304Speter * structure so we can keep track of it. 22219304Speter * 223281373Sbapt * PUBLIC: int ex_rew(SCR *, EXCMD *); 22419304Speter */ 22519304Speterint 226254225Speterex_rew(SCR *sp, EXCMD *cmdp) 22719304Speter{ 22819304Speter FREF *frp; 22919304Speter 23019304Speter /* 23119304Speter * !!! 23219304Speter * Historic practice -- you can rewind to the current file. 23319304Speter */ 23419304Speter if (sp->argv == NULL) { 23519304Speter msgq(sp, M_ERR, "113|No previous files to rewind"); 23619304Speter return (1); 23719304Speter } 23819304Speter 23919304Speter if (file_m1(sp, 24019304Speter FL_ISSET(cmdp->iflags, E_C_FORCE), FS_ALL | FS_POSSIBLE)) 24119304Speter return (1); 24219304Speter 24319304Speter /* Switch to the first one. */ 24419304Speter sp->cargv = sp->argv; 24519304Speter if ((frp = file_add(sp, *sp->cargv)) == NULL) 24619304Speter return (1); 24719304Speter if (file_init(sp, frp, NULL, FS_SETALT | 24819304Speter (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) 24919304Speter return (1); 25019304Speter 25119304Speter /* Switch and display a file count with the welcome message. */ 25219304Speter F_SET(sp, SC_FSWITCH | SC_STATUS_CNT); 25319304Speter 25419304Speter return (0); 25519304Speter} 25619304Speter 25719304Speter/* 25819304Speter * ex_args -- :args 25919304Speter * Display the list of files. 26019304Speter * 261281373Sbapt * PUBLIC: int ex_args(SCR *, EXCMD *); 26219304Speter */ 26319304Speterint 264254225Speterex_args(SCR *sp, EXCMD *cmdp) 26519304Speter{ 26619304Speter GS *gp; 26719304Speter int cnt, col, len, sep; 26819304Speter char **ap; 26919304Speter 27019304Speter if (sp->argv == NULL) { 27119304Speter (void)msgq(sp, M_ERR, "114|No file list to display"); 27219304Speter return (0); 27319304Speter } 27419304Speter 27519304Speter gp = sp->gp; 27619304Speter col = len = sep = 0; 27719304Speter for (cnt = 1, ap = sp->argv; *ap != NULL; ++ap) { 27819304Speter col += len = strlen(*ap) + sep + (ap == sp->cargv ? 2 : 0); 27919304Speter if (col >= sp->cols - 1) { 28019304Speter col = len; 28119304Speter sep = 0; 28219304Speter (void)ex_puts(sp, "\n"); 28319304Speter } else if (cnt != 1) { 28419304Speter sep = 1; 28519304Speter (void)ex_puts(sp, " "); 28619304Speter } 28719304Speter ++cnt; 28819304Speter 28919304Speter (void)ex_printf(sp, "%s%s%s", ap == sp->cargv ? "[" : "", 29019304Speter *ap, ap == sp->cargv ? "]" : ""); 29119304Speter if (INTERRUPTED(sp)) 29219304Speter break; 29319304Speter } 29419304Speter (void)ex_puts(sp, "\n"); 29519304Speter return (0); 29619304Speter} 29719304Speter 29819304Speter/* 29919304Speter * ex_buildargv -- 30019304Speter * Build a new file argument list. 30119304Speter * 302281373Sbapt * PUBLIC: char **ex_buildargv(SCR *, EXCMD *, char *); 30319304Speter */ 30419304Speterchar ** 305254225Speterex_buildargv(SCR *sp, EXCMD *cmdp, char *name) 30619304Speter{ 30719304Speter ARGS **argv; 30819304Speter int argc; 30919304Speter char **ap, **s_argv; 310254225Speter char *np; 311254225Speter size_t nlen; 31219304Speter 31319304Speter argc = cmdp == NULL ? 1 : cmdp->argc; 31419304Speter CALLOC(sp, s_argv, char **, argc + 1, sizeof(char *)); 31519304Speter if ((ap = s_argv) == NULL) 31619304Speter return (NULL); 31719304Speter 31819304Speter if (cmdp == NULL) { 31919304Speter if ((*ap = v_strdup(sp, name, strlen(name))) == NULL) 32019304Speter return (NULL); 32119304Speter ++ap; 32219304Speter } else 323254225Speter for (argv = cmdp->argv; argv[0]->len != 0; ++ap, ++argv) { 324254225Speter INT2CHAR(sp, argv[0]->bp, argv[0]->len, np, nlen); 325254225Speter if ((*ap = v_strdup(sp, np, nlen)) == NULL) 32619304Speter return (NULL); 327254225Speter } 32819304Speter *ap = NULL; 32919304Speter return (s_argv); 33019304Speter} 331