1 /* $OpenBSD: ex_read.c,v 1.9 2009/10/27 23:59:47 deraadt Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
8 *
9 * See the LICENSE file for redistribution information.
10 */
11
12 #include "config.h"
13
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <sys/stat.h>
17 #include <sys/time.h>
18
19 #include <bitstring.h>
20 #include <ctype.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 /*
31 * ex_read -- :read [file]
32 * :read [!cmd]
33 * Read from a file or utility.
34 *
35 * !!!
36 * Historical vi wouldn't undo a filter read, for no apparent reason.
37 *
38 * PUBLIC: int ex_read(SCR *, EXCMD *);
39 */
40 int
ex_read(sp,cmdp)41 ex_read(sp, cmdp)
42 SCR *sp;
43 EXCMD *cmdp;
44 {
45 enum { R_ARG, R_EXPANDARG, R_FILTER } which;
46 struct stat sb;
47 CHAR_T *arg, *name;
48 EX_PRIVATE *exp;
49 FILE *fp;
50 FREF *frp;
51 GS *gp;
52 MARK rm;
53 recno_t nlines;
54 size_t arglen;
55 int argc, rval;
56 char *p;
57
58 gp = sp->gp;
59
60 /*
61 * 0 args: read the current pathname.
62 * 1 args: check for "read !arg".
63 */
64 switch (cmdp->argc) {
65 case 0:
66 which = R_ARG;
67 arg = NULL; /* unused */
68 arglen = 0; /* unused */
69 break;
70 case 1:
71 arg = cmdp->argv[0]->bp;
72 arglen = cmdp->argv[0]->len;
73 if (*arg == '!') {
74 ++arg;
75 --arglen;
76 which = R_FILTER;
77
78 /* Secure means no shell access. */
79 if (O_ISSET(sp, O_SECURE)) {
80 ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
81 return (1);
82 }
83 } else
84 which = R_EXPANDARG;
85 break;
86 default:
87 abort();
88 /* NOTREACHED */
89 }
90
91 /* Load a temporary file if no file being edited. */
92 if (sp->ep == NULL) {
93 if ((frp = file_add(sp, NULL)) == NULL)
94 return (1);
95 if (file_init(sp, frp, NULL, 0))
96 return (1);
97 }
98
99 switch (which) {
100 case R_FILTER:
101 /*
102 * File name and bang expand the user's argument. If
103 * we don't get an additional argument, it's illegal.
104 */
105 argc = cmdp->argc;
106 if (argv_exp1(sp, cmdp, arg, arglen, 1))
107 return (1);
108 if (argc == cmdp->argc) {
109 ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
110 return (1);
111 }
112 argc = cmdp->argc - 1;
113
114 /* Set the last bang command. */
115 exp = EXP(sp);
116 if (exp->lastbcomm != NULL)
117 free(exp->lastbcomm);
118 if ((exp->lastbcomm =
119 strdup(cmdp->argv[argc]->bp)) == NULL) {
120 msgq(sp, M_SYSERR, NULL);
121 return (1);
122 }
123
124 /*
125 * Vi redisplayed the user's argument if it changed, ex
126 * always displayed a !, plus the user's argument if it
127 * changed.
128 */
129 if (F_ISSET(sp, SC_VI)) {
130 if (F_ISSET(cmdp, E_MODIFY))
131 (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
132 } else {
133 if (F_ISSET(cmdp, E_MODIFY))
134 (void)ex_printf(sp,
135 "!%s\n", cmdp->argv[argc]->bp);
136 else
137 (void)ex_puts(sp, "!\n");
138 (void)ex_fflush(sp);
139 }
140
141 /*
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.
145 */
146 if (!F_ISSET(sp, SC_SCR_EXWROTE))
147 F_SET(sp, SC_EX_WAIT_NO);
148
149 /*
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".
153 *
154 * !!!
155 * We do not output an extra <newline>, so that we don't touch
156 * the screen on a normal read.
157 */
158 if (F_ISSET(sp, SC_VI)) {
159 if (gp->scr_screen(sp, SC_EX)) {
160 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
161 return (1);
162 }
163 /*
164 * !!!
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.
168 */
169 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
170 }
171
172 if (ex_filter(sp, cmdp, &cmdp->addr1,
173 NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
174 return (1);
175
176 /* The filter version of read set the autoprint flag. */
177 F_SET(cmdp, E_AUTOPRINT);
178
179 /*
180 * If in vi mode, move to the first nonblank. Might have
181 * switched into ex mode, so saved the original SC_VI value.
182 */
183 sp->lno = rm.lno;
184 if (F_ISSET(sp, SC_VI)) {
185 sp->cno = 0;
186 (void)nonblank(sp, sp->lno, &sp->cno);
187 }
188 return (0);
189 case R_ARG:
190 name = sp->frp->name;
191 break;
192 case R_EXPANDARG:
193 if (argv_exp2(sp, cmdp, arg, arglen))
194 return (1);
195 /*
196 * 0 args: impossible.
197 * 1 args: impossible (I hope).
198 * 2 args: read it.
199 * >2 args: object, too many args.
200 *
201 * The 1 args case depends on the argv_sexp() function refusing
202 * to return success without at least one non-blank character.
203 */
204 switch (cmdp->argc) {
205 case 0:
206 case 1:
207 abort();
208 /* NOTREACHED */
209 case 2:
210 name = cmdp->argv[1]->bp;
211 /*
212 * !!!
213 * Historically, the read and write commands renamed
214 * "unnamed" files, or, if the file had a name, set
215 * the alternate file name.
216 */
217 if (F_ISSET(sp->frp, FR_TMPFILE) &&
218 !F_ISSET(sp->frp, FR_EXNAMED)) {
219 if ((p = v_strdup(sp, cmdp->argv[1]->bp,
220 cmdp->argv[1]->len)) != NULL) {
221 free(sp->frp->name);
222 sp->frp->name = p;
223 }
224 /*
225 * The file has a real name, it's no longer a
226 * temporary, clear the temporary file flags.
227 */
228 F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
229 F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);
230
231 /* Notify the screen. */
232 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
233 } else
234 set_alt_name(sp, name);
235 break;
236 default:
237 ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
238 return (1);
239
240 }
241 break;
242 default:
243 abort();
244 /* NOTREACHED */
245 }
246
247 /*
248 * !!!
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.
254 */
255 if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
256 msgq_str(sp, M_SYSERR, name, "%s");
257 return (1);
258 }
259 if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
260 (void)fclose(fp);
261 msgq(sp, M_ERR,
262 "145|Only regular files and named pipes may be read");
263 return (1);
264 }
265
266 /* Try and get a lock. */
267 if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
268 msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
269
270 rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
271
272 /*
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
276 * bother.)
277 *
278 * In ex, set the cursor to the last line read in, if anything read in,
279 * otherwise, the address.
280 */
281 if (F_ISSET(sp, SC_VI)) {
282 sp->lno = cmdp->addr1.lno;
283 if (nlines)
284 ++sp->lno;
285 } else
286 sp->lno = cmdp->addr1.lno + nlines;
287 return (rval);
288 }
289
290 /*
291 * ex_readfp --
292 * Read lines into the file.
293 *
294 * PUBLIC: int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int);
295 */
296 int
ex_readfp(sp,name,fp,fm,nlinesp,silent)297 ex_readfp(sp, name, fp, fm, nlinesp, silent)
298 SCR *sp;
299 char *name;
300 FILE *fp;
301 MARK *fm;
302 recno_t *nlinesp;
303 int silent;
304 {
305 EX_PRIVATE *exp;
306 GS *gp;
307 recno_t lcnt, lno;
308 size_t len;
309 u_long ccnt; /* XXX: can't print off_t portably. */
310 int nf, rval;
311 char *p;
312
313 gp = sp->gp;
314 exp = EXP(sp);
315
316 /*
317 * Add in the lines from the output. Insertion starts at the line
318 * following the address.
319 */
320 ccnt = 0;
321 lcnt = 0;
322 p = "147|Reading...";
323 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
324 if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
325 if (INTERRUPTED(sp))
326 break;
327 if (!silent) {
328 gp->scr_busy(sp, p,
329 p == NULL ? BUSY_UPDATE : BUSY_ON);
330 p = NULL;
331 }
332 }
333 if (db_append(sp, 1, lno, exp->ibp, len))
334 goto err;
335 ccnt += len;
336 }
337
338 if (ferror(fp) || fclose(fp))
339 goto err;
340
341 /* Return the number of lines read in. */
342 if (nlinesp != NULL)
343 *nlinesp = lcnt;
344
345 if (!silent) {
346 p = msg_print(sp, name, &nf);
347 msgq(sp, M_INFO,
348 "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
349 if (nf)
350 FREE_SPACE(sp, p, 0);
351 }
352
353 rval = 0;
354 if (0) {
355 err: msgq_str(sp, M_SYSERR, name, "%s");
356 (void)fclose(fp);
357 rval = 1;
358 }
359
360 if (!silent)
361 gp->scr_busy(sp, NULL, BUSY_OFF);
362 return (rval);
363 }
364