GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../ex/ex_read.c Lines: 0 121 0.0 %
Date: 2017-11-07 Branches: 0 109 0.0 %

Line Branch Exec Source
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
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
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
}