better alternative for previous patch
[nvi.git] / ex / ex_read.c
blob41080d854989311815424e0c99e165a30700fc26
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: ex_read.c,v 10.42 2000/11/26 20:10:19 skimo Exp $ (Berkeley) $Date: 2000/11/26 20:10:19 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
21 #include <bitstring.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include "../common/common.h"
30 #include "../vi/vi.h"
33 * ex_read -- :read [file]
34 * :read [!cmd]
35 * Read from a file or utility.
37 * !!!
38 * Historical vi wouldn't undo a filter read, for no apparent reason.
40 * PUBLIC: int ex_read __P((SCR *, EXCMD *));
42 int
43 ex_read(sp, cmdp)
44 SCR *sp;
45 EXCMD *cmdp;
47 enum { R_ARG, R_EXPANDARG, R_FILTER } which;
48 struct stat sb;
49 CHAR_T *arg;
50 char *name;
51 size_t nlen;
52 EX_PRIVATE *exp;
53 FILE *fp;
54 FREF *frp;
55 GS *gp;
56 MARK rm;
57 db_recno_t nlines;
58 size_t arglen;
59 int argc, rval;
60 char *p;
61 char *np;
63 gp = sp->gp;
66 * 0 args: read the current pathname.
67 * 1 args: check for "read !arg".
69 switch (cmdp->argc) {
70 case 0:
71 which = R_ARG;
72 break;
73 case 1:
74 arg = cmdp->argv[0]->bp;
75 arglen = cmdp->argv[0]->len;
76 if (*arg == '!') {
77 ++arg;
78 --arglen;
79 which = R_FILTER;
81 /* Secure means no shell access. */
82 if (O_ISSET(sp, O_SECURE)) {
83 ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
84 return (1);
86 } else
87 which = R_EXPANDARG;
88 break;
89 default:
90 abort();
91 /* NOTREACHED */
94 /* Load a temporary file if no file being edited. */
95 if (sp->ep == NULL) {
96 if ((frp = file_add(sp, NULL)) == NULL)
97 return (1);
98 if (file_init(sp, frp, NULL, 0))
99 return (1);
102 switch (which) {
103 case R_FILTER:
105 * File name and bang expand the user's argument. If
106 * we don't get an additional argument, it's illegal.
108 argc = cmdp->argc;
109 if (argv_exp1(sp, cmdp, arg, arglen, 1))
110 return (1);
111 if (argc == cmdp->argc) {
112 ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
113 return (1);
115 argc = cmdp->argc - 1;
117 /* Set the last bang command. */
118 exp = EXP(sp);
119 if (exp->lastbcomm != NULL)
120 free(exp->lastbcomm);
121 if ((exp->lastbcomm =
122 v_wstrdup(sp, cmdp->argv[argc]->bp,
123 cmdp->argv[argc]->len)) == NULL) {
124 msgq(sp, M_SYSERR, NULL);
125 return (1);
129 * Vi redisplayed the user's argument if it changed, ex
130 * always displayed a !, plus the user's argument if it
131 * changed.
133 if (F_ISSET(sp, SC_VI)) {
134 if (F_ISSET(cmdp, E_MODIFY))
135 (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
136 } else {
137 if (F_ISSET(cmdp, E_MODIFY))
138 (void)ex_printf(sp,
139 "!%s\n", cmdp->argv[argc]->bp);
140 else
141 (void)ex_puts(sp, "!\n");
142 (void)ex_fflush(sp);
146 * Historically, filter reads as the first ex command didn't
147 * wait for the user. If SC_SCR_EXWROTE not already set, set
148 * the don't-wait flag.
150 if (!F_ISSET(sp, SC_SCR_EXWROTE))
151 F_SET(sp, SC_EX_WAIT_NO);
154 * Switch into ex canonical mode. The reason to restore the
155 * original terminal modes for read filters is so that users
156 * can do things like ":r! cat /dev/tty".
158 * !!!
159 * We do not output an extra <newline>, so that we don't touch
160 * the screen on a normal read.
162 if (F_ISSET(sp, SC_VI)) {
163 if (gp->scr_screen(sp, SC_EX)) {
164 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
165 return (1);
168 * !!!
169 * Historically, the read command doesn't switch to
170 * the alternate X11 xterm screen, if doing a filter
171 * read -- don't set SA_ALTERNATE.
173 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
176 if (ex_filter(sp, cmdp, &cmdp->addr1,
177 NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
178 return (1);
180 /* The filter version of read set the autoprint flag. */
181 F_SET(cmdp, E_AUTOPRINT);
184 * If in vi mode, move to the first nonblank. Might have
185 * switched into ex mode, so saved the original SC_VI value.
187 sp->lno = rm.lno;
188 if (F_ISSET(sp, SC_VI)) {
189 sp->cno = 0;
190 (void)nonblank(sp, sp->lno, &sp->cno);
192 return (0);
193 case R_ARG:
194 name = sp->frp->name;
195 break;
196 case R_EXPANDARG:
197 if (argv_exp2(sp, cmdp, arg, arglen))
198 return (1);
200 * 0 args: impossible.
201 * 1 args: impossible (I hope).
202 * 2 args: read it.
203 * >2 args: object, too many args.
205 * The 1 args case depends on the argv_sexp() function refusing
206 * to return success without at least one non-blank character.
208 switch (cmdp->argc) {
209 case 0:
210 case 1:
211 abort();
212 /* NOTREACHED */
213 case 2:
214 INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len + 1,
215 name, nlen);
217 * !!!
218 * Historically, the read and write commands renamed
219 * "unnamed" files, or, if the file had a name, set
220 * the alternate file name.
222 if (F_ISSET(sp->frp, FR_TMPFILE) &&
223 !F_ISSET(sp->frp, FR_EXNAMED)) {
224 if ((p = strdup(name)) != NULL) {
225 free(sp->frp->name);
226 sp->frp->name = p;
229 * The file has a real name, it's no longer a
230 * temporary, clear the temporary file flags.
232 F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
233 F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);
235 /* Notify the screen. */
236 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
237 name = sp->frp->name;
238 } else {
239 set_alt_name(sp, name);
240 name = sp->alt_name;
242 break;
243 default:
244 INT2CHAR(sp, cmdp->argv[0]->bp,
245 cmdp->argv[0]->len + 1, np, nlen);
246 ex_emsg(sp, np, EXM_FILECOUNT);
247 return (1);
250 break;
254 * !!!
255 * Historically, vi did not permit reads from non-regular files, nor
256 * did it distinguish between "read !" and "read!", so there was no
257 * way to "force" it. We permit reading from named pipes too, since
258 * they didn't exist when the original implementation of vi was done
259 * and they seem a reasonable addition.
261 if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
262 msgq_str(sp, M_SYSERR, name, "%s");
263 return (1);
265 if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
266 (void)fclose(fp);
267 msgq(sp, M_ERR,
268 "145|Only regular files and named pipes may be read");
269 return (1);
272 /* Try and get a lock. */
273 if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
274 msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
276 rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
279 * In vi, set the cursor to the first line read in, if anything read
280 * in, otherwise, the address. (Historic vi set it to the line after
281 * the address regardless, but since that line may not exist we don't
282 * bother.)
284 * In ex, set the cursor to the last line read in, if anything read in,
285 * otherwise, the address.
287 if (F_ISSET(sp, SC_VI)) {
288 sp->lno = cmdp->addr1.lno;
289 if (nlines)
290 ++sp->lno;
291 } else
292 sp->lno = cmdp->addr1.lno + nlines;
293 return (rval);
297 * ex_readfp --
298 * Read lines into the file.
300 * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, db_recno_t *, int));
303 ex_readfp(sp, name, fp, fm, nlinesp, silent)
304 SCR *sp;
305 char *name;
306 FILE *fp;
307 MARK *fm;
308 db_recno_t *nlinesp;
309 int silent;
311 EX_PRIVATE *exp;
312 GS *gp;
313 db_recno_t lcnt, lno;
314 size_t len;
315 u_long ccnt; /* XXX: can't print off_t portably. */
316 int nf, rval;
317 char *p;
319 gp = sp->gp;
320 exp = EXP(sp);
323 * Add in the lines from the output. Insertion starts at the line
324 * following the address.
326 ccnt = 0;
327 lcnt = 0;
328 p = "147|Reading...";
329 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
330 if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
331 if (INTERRUPTED(sp))
332 break;
333 if (!silent) {
334 gp->scr_busy(sp, p,
335 p == NULL ? BUSY_UPDATE : BUSY_ON);
336 p = NULL;
339 if (db_append(sp, 1, lno, exp->ibp, len))
340 goto err;
341 ccnt += len;
344 if (ferror(fp) || fclose(fp))
345 goto err;
347 /* Return the number of lines read in. */
348 if (nlinesp != NULL)
349 *nlinesp = lcnt;
351 if (!silent) {
352 p = msg_print(sp, name, &nf);
353 msgq(sp, M_INFO,
354 "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
355 if (nf)
356 FREE_SPACE(sp, p, 0);
359 rval = 0;
360 if (0) {
361 err: msgq_str(sp, M_SYSERR, name, "%s");
362 (void)fclose(fp);
363 rval = 1;
366 if (!silent)
367 gp->scr_busy(sp, NULL, BUSY_OFF);
368 return (rval);