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