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.
6 *
7 * See the LICENSE file for redistribution information.
8 */
9
10#include "config.h"
11
12#ifndef lint
13static const char sccsid[] = "$Id: ex_read.c,v 10.44 2001/06/25 15:19:19 skimo Exp $";
14#endif /* not lint */
15
16#include <sys/types.h>
17#include <sys/queue.h>
18#include <sys/stat.h>
19
20#include <bitstring.h>
21#include <ctype.h>
22#include <errno.h>
23#include <limits.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "../common/common.h"
29#include "../vi/vi.h"
30
31/*
32 * ex_read --	:read [file]
33 *		:read [!cmd]
34 *	Read from a file or utility.
35 *
36 * !!!
37 * Historical vi wouldn't undo a filter read, for no apparent reason.
38 *
39 * PUBLIC: int ex_read __P((SCR *, EXCMD *));
40 */
41int
42ex_read(SCR *sp, EXCMD *cmdp)
43{
44	enum { R_ARG, R_EXPANDARG, R_FILTER } which;
45	struct stat sb;
46	CHAR_T *arg = NULL;
47	char *name = NULL;
48	size_t nlen;
49	EX_PRIVATE *exp;
50	FILE *fp;
51	FREF *frp;
52	GS *gp;
53	MARK rm;
54	recno_t nlines;
55	size_t arglen = 0;
56	int argc, rval;
57	char *p;
58
59	gp = sp->gp;
60
61	/*
62	 * 0 args: read the current pathname.
63	 * 1 args: check for "read !arg".
64	 */
65	switch (cmdp->argc) {
66	case 0:
67		which = R_ARG;
68		break;
69	case 1:
70		arg = cmdp->argv[0]->bp;
71		arglen = cmdp->argv[0]->len;
72		if (*arg == '!') {
73			++arg;
74			--arglen;
75			which = R_FILTER;
76
77			/* Secure means no shell access. */
78			if (O_ISSET(sp, O_SECURE)) {
79				ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F);
80				return (1);
81			}
82		} else
83			which = R_EXPANDARG;
84		break;
85	default:
86		abort();
87		/* NOTREACHED */
88	}
89
90	/* Load a temporary file if no file being edited. */
91	if (sp->ep == NULL) {
92		if ((frp = file_add(sp, NULL)) == NULL)
93			return (1);
94		if (file_init(sp, frp, NULL, 0))
95			return (1);
96	}
97
98	switch (which) {
99	case R_FILTER:
100		/*
101		 * File name and bang expand the user's argument.  If
102		 * we don't get an additional argument, it's illegal.
103		 */
104		argc = cmdp->argc;
105		if (argv_exp1(sp, cmdp, arg, arglen, 1))
106			return (1);
107		if (argc == cmdp->argc) {
108			ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
109			return (1);
110		}
111		argc = cmdp->argc - 1;
112
113		/* Set the last bang command. */
114		exp = EXP(sp);
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);
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				    "!"WS"\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_wemsg(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			INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len + 1,
211				 name, nlen);
212			/*
213			 * !!!
214			 * Historically, the read and write commands renamed
215			 * "unnamed" files, or, if the file had a name, set
216			 * the alternate file name.
217			 */
218			if (F_ISSET(sp->frp, FR_TMPFILE) &&
219			    !F_ISSET(sp->frp, FR_EXNAMED)) {
220				if ((p = strdup(name)) != 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				name = sp->frp->name;
234			} else {
235				set_alt_name(sp, name);
236				name = sp->alt_name;
237			}
238			break;
239		default:
240			ex_wemsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
241			return (1);
242
243		}
244		break;
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, 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 __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
295 */
296int
297ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp, int silent)
298{
299	EX_PRIVATE *exp;
300	GS *gp;
301	recno_t lcnt, lno;
302	size_t len;
303	u_long ccnt;			/* XXX: can't print off_t portably. */
304	int nf, rval;
305	char *p;
306	size_t wlen;
307	CHAR_T *wp;
308
309	gp = sp->gp;
310	exp = EXP(sp);
311
312	/*
313	 * Add in the lines from the output.  Insertion starts at the line
314	 * following the address.
315	 */
316	ccnt = 0;
317	lcnt = 0;
318	p = "147|Reading...";
319	for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
320		if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
321			if (INTERRUPTED(sp))
322				break;
323			if (!silent) {
324				gp->scr_busy(sp, p,
325				    p == NULL ? BUSY_UPDATE : BUSY_ON);
326				p = NULL;
327			}
328		}
329		FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen);
330		if (db_append(sp, 1, lno, wp, wlen))
331			goto err;
332		ccnt += len;
333	}
334
335	if (ferror(fp) || fclose(fp))
336		goto err;
337
338	/* Return the number of lines read in. */
339	if (nlinesp != NULL)
340		*nlinesp = lcnt;
341
342	if (!silent) {
343		p = msg_print(sp, name, &nf);
344		msgq(sp, M_INFO,
345		    "148|%s: %lu lines, %lu characters", p,
346		    (u_long)lcnt, ccnt);
347		if (nf)
348			FREE_SPACE(sp, p, 0);
349	}
350
351	rval = 0;
352	if (0) {
353err:		msgq_str(sp, M_SYSERR, name, "%s");
354		(void)fclose(fp);
355		rval = 1;
356	}
357
358	if (!silent)
359		gp->scr_busy(sp, NULL, BUSY_OFF);
360	return (rval);
361}
362