split is "sp", not "s"
[nvi.git] / ex / ex_write.c
blob9bc13402322b447bcae1abb83e24e182664cfee6
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: ex_write.c,v 8.19 1993/12/18 11:28:32 bostic Exp $ (Berkeley) $Date: 1993/12/18 11:28:32 $";
10 #endif /* not lint */
12 #include <sys/types.h>
13 #include <sys/stat.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
21 #include "vi.h"
22 #include "excmd.h"
24 enum which {WQ, WRITE, XIT};
26 static int exwr __P((SCR *, EXF *, EXCMDARG *, enum which));
29 * ex_wq -- :wq[!] [>>] [file]
30 * Write to a file.
32 int
33 ex_wq(sp, ep, cmdp)
34 SCR *sp;
35 EXF *ep;
36 EXCMDARG *cmdp;
38 int force;
40 if (exwr(sp, ep, cmdp, WQ))
41 return (1);
43 force = F_ISSET(cmdp, E_FORCE);
44 if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
45 msgq(sp, M_ERR,
46 "More files to edit; use \":n\" to go to the next file");
47 return (1);
50 F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
51 return (0);
55 * ex_write -- :write[!] [>>] [file]
56 * :write [!] [cmd]
57 * Write to a file.
59 int
60 ex_write(sp, ep, cmdp)
61 SCR *sp;
62 EXF *ep;
63 EXCMDARG *cmdp;
65 return (exwr(sp, ep, cmdp, WRITE));
70 * ex_xit -- :x[it]! [file]
72 * Write out any modifications and quit.
74 int
75 ex_xit(sp, ep, cmdp)
76 SCR *sp;
77 EXF *ep;
78 EXCMDARG *cmdp;
80 int force;
82 if (F_ISSET((ep), F_MODIFIED) && exwr(sp, ep, cmdp, XIT))
83 return (1);
85 force = F_ISSET(cmdp, E_FORCE);
86 if (!force && ep->refcnt <= 1 && file_unedited(sp) != NULL) {
87 msgq(sp, M_ERR,
88 "More files to edit; use \":n\" to go to the next file");
89 return (1);
92 F_SET(sp, force ? S_EXIT_FORCE : S_EXIT);
93 return (0);
97 * exwr --
98 * The guts of the ex write commands.
100 static int
101 exwr(sp, ep, cmdp, cmd)
102 SCR *sp;
103 EXF *ep;
104 EXCMDARG *cmdp;
105 enum which cmd;
107 EX_PRIVATE *exp;
108 MARK rm;
109 int flags;
110 char *name, *p;
112 /* All write commands can have an associated '!'. */
113 LF_INIT(FS_POSSIBLE);
114 if (F_ISSET(cmdp, E_FORCE))
115 LF_SET(FS_FORCE);
117 /* Skip any leading whitespace. */
118 if (cmdp->argc != 0)
119 for (p = cmdp->argv[0]->bp; *p && isblank(*p); ++p);
121 /* If no arguments, just write the file back. */
122 if (cmdp->argc == 0 || *p == '\0') {
123 if (F_ISSET(cmdp, E_ADDR2_ALL))
124 LF_SET(FS_ALL);
125 return (file_write(sp, ep,
126 &cmdp->addr1, &cmdp->addr2, NULL, flags));
129 /* If "write !" it's a pipe to a utility. */
130 exp = EXP(sp);
131 if (cmd == WRITE && *p == '!') {
132 for (++p; *p && isblank(*p); ++p);
133 if (*p == '\0') {
134 msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
135 return (1);
137 /* Expand the argument. */
138 if (argv_exp1(sp, ep, cmdp, p, strlen(p), 0))
139 return (1);
140 if (filtercmd(sp, ep, &cmdp->addr1, &cmdp->addr2,
141 &rm, cmdp->argv[1]->bp, FILTER_WRITE))
142 return (1);
143 sp->lno = rm.lno;
144 return (0);
147 /* If "write >>" it's an append to a file. */
148 if (cmd != XIT && p[0] == '>' && p[1] == '>') {
149 LF_SET(FS_APPEND);
151 /* Skip ">>" and whitespace. */
152 for (p += 2; *p && isblank(*p); ++p);
155 /* Build an argv so we get an argument count and file expansion. */
156 if (argv_exp2(sp, ep, cmdp, p, strlen(p), 0))
157 return (1);
159 switch (cmdp->argc) {
160 case 1:
162 * Nothing to expand, write the current file.
163 * XXX
164 * Should never happen, already checked this case.
166 name = NULL;
167 break;
168 case 2:
169 /* One new argument, write it. */
170 name = cmdp->argv[exp->argsoff - 1]->bp;
171 set_alt_name(sp, name);
172 break;
173 default:
174 /* If expanded to more than one argument, object. */
175 msgq(sp, M_ERR, "%s expanded into too many file names",
176 cmdp->argv[0]->bp);
177 msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
178 return (1);
181 if (F_ISSET(cmdp, E_ADDR2_ALL))
182 LF_SET(FS_ALL);
183 return (file_write(sp, ep, &cmdp->addr1, &cmdp->addr2, name, flags));
187 * ex_writefp --
188 * Write a range of lines to a FILE *.
191 ex_writefp(sp, ep, name, fp, fm, tm, nlno, nch)
192 SCR *sp;
193 EXF *ep;
194 char *name;
195 FILE *fp;
196 MARK *fm, *tm;
197 u_long *nlno, *nch;
199 register u_long ccnt, fline, tline;
200 size_t len;
201 char *p;
203 fline = fm->lno;
204 tline = tm->lno;
206 if (nlno != NULL) {
207 *nch = 0;
208 *nlno = 0;
210 ccnt = 0;
213 * The vi filter code has multiple processes running simultaneously,
214 * and one of them calls ex_writefp(). The "unsafe" function calls
215 * in this code are to file_gline() and msgq(). File_gline() is safe,
216 * see the comment in filter.c:filtercmd() for details. We don't call
217 * msgq if the multiple process bit in the EXF is set.
219 * !!!
220 * Historic vi permitted files of 0 length to be written. However,
221 * since the way vi got around dealing with "empty" files was to
222 * always have a line in the file no matter what, it wrote them as
223 * files of a single, empty line. We write empty files.
225 * "Alex, I'll take vi trivia for $1000."
227 if (tline != 0)
228 for (; fline <= tline; ++fline) {
229 if ((p = file_gline(sp, ep, fline, &len)) == NULL)
230 break;
231 if (fwrite(p, 1, len, fp) != len) {
232 msgq(sp, M_SYSERR, name);
233 (void)fclose(fp);
234 return (1);
236 ccnt += len;
237 if (putc('\n', fp) != '\n')
238 break;
239 ++ccnt;
241 if (fclose(fp)) {
242 if (!F_ISSET(ep, F_MULTILOCK))
243 msgq(sp, M_SYSERR, name);
244 return (1);
246 if (nlno != NULL) {
247 *nch = ccnt;
248 *nlno = tm->lno == 0 ? 0 : tm->lno - fm->lno + 1;
250 return (0);