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