xref: /freebsd/contrib/nvi/ex/ex_edit.c (revision 0957b409a90fd597c1e9124cbaf3edd2b488f4ac)
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
13 static 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 
30 static 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  */
48 int
49 ex_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  */
112 static int
113 ex_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