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