1/*-
2 * Copyright (c) 1992, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 *	Keith Bostic.  All rights reserved.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#ifndef lint
13static const char sccsid[] = "$Id: ex_edit.c,v 10.15 2011/12/22 23:26:50 zy Exp $";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/time.h>
19
20#include <bitstring.h>
21#include <errno.h>
22#include <limits.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "../common/common.h"
28#include "../vi/vi.h"
29
30static int ex_N_edit(SCR *, EXCMD *, FREF *, int);
31
32/*
33 * ex_edit --	:e[dit][!] [+cmd] [file]
34 *		:ex[!] [+cmd] [file]
35 *		:vi[sual][!] [+cmd] [file]
36 *
37 * Edit a file; if none specified, re-edit the current file.  The third
38 * form of the command can only be executed while in vi mode.  See the
39 * hack in ex.c:ex_cmd().
40 *
41 * !!!
42 * Historic vi didn't permit the '+' command form without specifying
43 * a file name as well.  This seems unreasonable, so we support it
44 * regardless.
45 *
46 * PUBLIC: int ex_edit(SCR *, EXCMD *);
47 */
48int
49ex_edit(SCR *sp, EXCMD *cmdp)
50{
51	FREF *frp;
52	int attach, setalt;
53	char *np;
54	size_t nlen;
55
56	switch (cmdp->argc) {
57	case 0:
58		/*
59		 * If the name has been changed, we edit that file, not the
60		 * original name.  If the user was editing a temporary file
61		 * (or wasn't editing any file), create another one.  The
62		 * reason for not reusing temporary files is that there is
63		 * special exit processing of them, and reuse is tricky.
64		 */
65		frp = sp->frp;
66		if (sp->ep == NULL || F_ISSET(frp, FR_TMPFILE)) {
67			if ((frp = file_add(sp, NULL)) == NULL)
68				return (1);
69			attach = 0;
70		} else
71			attach = 1;
72		setalt = 0;
73		break;
74	case 1:
75		INT2CHAR(sp, cmdp->argv[0]->bp, cmdp->argv[0]->len + 1,
76			 np, nlen);
77		if ((frp = file_add(sp, np)) == NULL)
78			return (1);
79		attach = 0;
80		setalt = 1;
81		set_alt_name(sp, np);
82		break;
83	default:
84		abort();
85	}
86
87	if (F_ISSET(cmdp, E_NEWSCREEN) || cmdp->cmd == &cmds[C_VSPLIT])
88		return (ex_N_edit(sp, cmdp, frp, attach));
89
90	/*
91	 * Check for modifications.
92	 *
93	 * !!!
94	 * Contrary to POSIX 1003.2-1992, autowrite did not affect :edit.
95	 */
96	if (file_m2(sp, FL_ISSET(cmdp->iflags, E_C_FORCE)))
97		return (1);
98
99	/* Switch files. */
100	if (file_init(sp, frp, NULL, (setalt ? FS_SETALT : 0) |
101	    (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0)))
102		return (1);
103
104	F_SET(sp, SC_FSWITCH);
105	return (0);
106}
107
108/*
109 * ex_N_edit --
110 *	New screen version of ex_edit.
111 */
112static int
113ex_N_edit(SCR *sp, EXCMD *cmdp, FREF *frp, int attach)
114{
115	SCR *new;
116
117	/* Get a new screen. */
118	if (screen_init(sp->gp, sp, &new))
119		return (1);
120	if ((cmdp->cmd == &cmds[C_VSPLIT] && vs_vsplit(sp, new)) ||
121	    (cmdp->cmd != &cmds[C_VSPLIT] && vs_split(sp, new, 0))) {
122		(void)screen_end(new);
123		return (1);
124	}
125
126	/* Get a backing file. */
127	if (attach) {
128		/* Copy file state, keep the screen and cursor the same. */
129		new->ep = sp->ep;
130		++new->ep->refcnt;
131
132		new->frp = frp;
133		new->frp->flags = sp->frp->flags;
134
135		new->lno = sp->lno;
136		new->cno = sp->cno;
137
138#if defined(USE_WIDECHAR) && defined(USE_ICONV)
139		/* Synchronize the iconv environments. */
140		o_set(new, O_FILEENCODING, OS_STRDUP,
141		    O_STR(sp, O_FILEENCODING), 0);
142		conv_enc(new, O_FILEENCODING, 0);
143#endif
144	} else if (file_init(new, frp, NULL,
145	    (FL_ISSET(cmdp->iflags, E_C_FORCE) ? FS_FORCE : 0))) {
146		(void)vs_discard(new, NULL);
147		(void)screen_end(new);
148		return (1);
149	}
150
151	/* Create the argument list. */
152	new->cargv = new->argv = ex_buildargv(sp, NULL, frp->name);
153
154	/* Set up the switch. */
155	sp->nextdisp = new;
156	F_SET(sp, SC_SSWITCH);
157
158	return (0);
159}
160