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