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.
13 static const char sccsid[] = "$Id: ex_read.c,v 10.44 2001/06/25 15:19:19 skimo Exp $";
16 #include <sys/types.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
28 #include "../common/common.h"
32 * ex_read -- :read [file]
34 * Read from a file or utility.
37 * Historical vi wouldn't undo a filter read, for no apparent reason.
39 * PUBLIC: int ex_read(SCR *, EXCMD *);
42 ex_read(SCR *sp, EXCMD *cmdp)
44 enum { R_ARG, R_EXPANDARG, R_FILTER } which;
62 * 0 args: read the current pathname.
63 * 1 args: check for "read !arg".
70 arg = cmdp->argv[0]->bp;
71 arglen = cmdp->argv[0]->len;
77 /* Secure means no shell access. */
78 if (O_ISSET(sp, O_SECURE)) {
79 ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F);
90 /* Load a temporary file if no file being edited. */
92 if ((frp = file_add(sp, NULL)) == NULL)
94 if (file_init(sp, frp, NULL, 0))
101 * File name and bang expand the user's argument. If
102 * we don't get an additional argument, it's illegal.
105 if (argv_exp1(sp, cmdp, arg, arglen, 1))
107 if (argc == cmdp->argc) {
108 ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
111 argc = cmdp->argc - 1;
113 /* Set the last bang command. */
115 if (exp->lastbcomm != NULL)
116 free(exp->lastbcomm);
117 if ((exp->lastbcomm =
118 v_wstrdup(sp, cmdp->argv[argc]->bp,
119 cmdp->argv[argc]->len)) == NULL) {
120 msgq(sp, M_SYSERR, NULL);
125 * Vi redisplayed the user's argument if it changed, ex
126 * always displayed a !, plus the user's argument if it
129 if (F_ISSET(sp, SC_VI)) {
130 if (F_ISSET(cmdp, E_MODIFY))
131 (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
133 if (F_ISSET(cmdp, E_MODIFY))
135 "!"WS"\n", cmdp->argv[argc]->bp);
137 (void)ex_puts(sp, "!\n");
142 * Historically, filter reads as the first ex command didn't
143 * wait for the user. If SC_SCR_EXWROTE not already set, set
144 * the don't-wait flag.
146 if (!F_ISSET(sp, SC_SCR_EXWROTE))
147 F_SET(sp, SC_EX_WAIT_NO);
150 * Switch into ex canonical mode. The reason to restore the
151 * original terminal modes for read filters is so that users
152 * can do things like ":r! cat /dev/tty".
155 * We do not output an extra <newline>, so that we don't touch
156 * the screen on a normal read.
158 if (F_ISSET(sp, SC_VI)) {
159 if (gp->scr_screen(sp, SC_EX)) {
160 ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
165 * Historically, the read command doesn't switch to
166 * the alternate X11 xterm screen, if doing a filter
167 * read -- don't set SA_ALTERNATE.
169 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
172 if (ex_filter(sp, cmdp, &cmdp->addr1,
173 NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
176 /* The filter version of read set the autoprint flag. */
177 F_SET(cmdp, E_AUTOPRINT);
180 * If in vi mode, move to the first nonblank. Might have
181 * switched into ex mode, so saved the original SC_VI value.
184 if (F_ISSET(sp, SC_VI)) {
186 (void)nonblank(sp, sp->lno, &sp->cno);
190 name = sp->frp->name;
193 if (argv_exp2(sp, cmdp, arg, arglen))
196 * 0 args: impossible.
197 * 1 args: impossible (I hope).
199 * >2 args: object, too many args.
201 * The 1 args case depends on the argv_sexp() function refusing
202 * to return success without at least one non-blank character.
204 switch (cmdp->argc) {
210 INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len + 1,
214 * Historically, the read and write commands renamed
215 * "unnamed" files, or, if the file had a name, set
216 * the alternate file name.
218 if (F_ISSET(sp->frp, FR_TMPFILE) &&
219 !F_ISSET(sp->frp, FR_EXNAMED)) {
220 if ((p = strdup(name)) != NULL) {
225 * The file has a real name, it's no longer a
226 * temporary, clear the temporary file flags.
228 F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
229 F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);
231 /* Notify the screen. */
232 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
233 name = sp->frp->name;
235 set_alt_name(sp, name);
240 ex_wemsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
249 * Historically, vi did not permit reads from non-regular files, nor
250 * did it distinguish between "read !" and "read!", so there was no
251 * way to "force" it. We permit reading from named pipes too, since
252 * they didn't exist when the original implementation of vi was done
253 * and they seem a reasonable addition.
255 if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
256 msgq_str(sp, M_SYSERR, name, "%s");
259 if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
262 "145|Only regular files and named pipes may be read");
266 /* Try and get a lock. */
267 if (file_lock(sp, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
268 msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
270 rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
273 * In vi, set the cursor to the first line read in, if anything read
274 * in, otherwise, the address. (Historic vi set it to the line after
275 * the address regardless, but since that line may not exist we don't
278 * In ex, set the cursor to the last line read in, if anything read in,
279 * otherwise, the address.
281 if (F_ISSET(sp, SC_VI)) {
282 sp->lno = cmdp->addr1.lno;
286 sp->lno = cmdp->addr1.lno + nlines;
292 * Read lines into the file.
294 * PUBLIC: int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int);
297 ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp, int silent)
303 u_long ccnt; /* XXX: can't print off_t portably. */
313 * Add in the lines from the output. Insertion starts at the line
314 * following the address.
318 p = "147|Reading...";
319 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
320 if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
325 p == NULL ? BUSY_UPDATE : BUSY_ON);
329 FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen);
330 if (db_append(sp, 1, lno, wp, wlen))
335 if (ferror(fp) || fclose(fp))
338 /* Return the number of lines read in. */
343 p = msg_print(sp, name, &nf);
345 "148|%s: %lu lines, %lu characters", p,
348 FREE_SPACE(sp, p, 0);
353 err: msgq_str(sp, M_SYSERR, name, "%s");
359 gp->scr_busy(sp, NULL, BUSY_OFF);