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