Import nvi2 version 2.1.3 to vendor branch
[dragonfly.git] / contrib / nvi2 / ex / ex_edit.c
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 }