File: | src/usr.bin/vi/build/../ex/ex_read.c |
Warning: | line 280, column 7 Branch condition evaluates to a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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(*__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((void *)0); /* 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)((((&(((sp)))->opts[(((O_SECURE)))])->flags) & ( (0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_SECURE )))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_SECURE)))] .o_cur.val)) { | |||
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((void *)0)) { | |||
91 | if ((frp = file_add(sp, NULL((void *)0))) == NULL((void *)0)) | |||
92 | return (1); | |||
93 | if (file_init(sp, frp, NULL((void *)0), 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)((EX_PRIVATE *)((sp)->ex_private)); | |||
114 | free(exp->lastbcomm); | |||
115 | if ((exp->lastbcomm = | |||
116 | strdup(cmdp->argv[argc]->bp)) == NULL((void *)0)) { | |||
117 | msgq(sp, M_SYSERR, NULL((void *)0)); | |||
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)(((sp)->flags) & ((0x00000002)))) { | |||
127 | if (F_ISSET(cmdp, E_MODIFY)(((cmdp)->flags) & ((0x00200000)))) | |||
128 | (void)vs_update(sp, "!", cmdp->argv[argc]->bp); | |||
129 | } else { | |||
130 | if (F_ISSET(cmdp, E_MODIFY)(((cmdp)->flags) & ((0x00200000)))) | |||
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)(((sp)->flags) & ((0x00000010)))) | |||
144 | F_SET(sp, SC_EX_WAIT_NO)(((sp)->flags) |= ((0x00080000))); | |||
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)(((sp)->flags) & ((0x00000002)))) { | |||
156 | if (gp->scr_screen(sp, SC_EX0x00000001)) { | |||
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)(((sp)->flags) |= ((0x00000004 | 0x00000010))); | |||
167 | } | |||
168 | ||||
169 | if (ex_filter(sp, cmdp, &cmdp->addr1, | |||
170 | NULL((void *)0), &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)(((cmdp)->flags) |= ((0x00000040))); | |||
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)(((sp)->flags) & ((0x00000002)))) { | |||
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)(((sp->frp)->flags) & ((0x0080))) && | |||
215 | !F_ISSET(sp->frp, FR_EXNAMED)(((sp->frp)->flags) & ((0x0004)))) { | |||
216 | if ((p = v_strdup(sp, cmdp->argv[1]->bp, | |||
217 | cmdp->argv[1]->len)) != NULL((void *)0)) { | |||
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)(((sp->frp)->flags) &= ~((0x0040 | 0x0080))); | |||
226 | F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED)(((sp->frp)->flags) |= ((0x0008 | 0x0004))); | |||
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((void *)0) || fstat(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), &sb)) { | |||
253 | msgq_str(sp, M_SYSERR, name, "%s"); | |||
254 | return (1); | |||
255 | } | |||
256 | if (!S_ISFIFO(sb.st_mode)((sb.st_mode & 0170000) == 0010000) && !S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)) { | |||
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((void *)0), NULL((void *)0), fileno(fp)(!__isthreaded ? ((fp)->_file) : (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)(((sp)->flags) & ((0x00000002)))) { | |||
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)((EX_PRIVATE *)((sp)->ex_private)); | |||
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_CHECK100 == 0) { | |||
317 | if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get ((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)-> flags) & ((0x0004)))))) | |||
318 | break; | |||
319 | if (!silent) { | |||
320 | gp->scr_busy(sp, p, | |||
321 | p == NULL((void *)0) ? BUSY_UPDATE : BUSY_ON); | |||
322 | p = NULL((void *)0); | |||
323 | } | |||
324 | } | |||
325 | if (db_append(sp, 1, lno, exp->ibp, len)) | |||
326 | goto err; | |||
327 | ccnt += len; | |||
328 | } | |||
329 | ||||
330 | if (ferror(fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror )(fp)) || fclose(fp)) | |||
331 | goto err; | |||
332 | ||||
333 | /* Return the number of lines read in. */ | |||
334 | if (nlinesp != NULL((void *)0)) | |||
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){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp ) (((L__gp)->flags) &= ~((0x0100))); else free(p); }; | |||
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((void *)0), BUSY_OFF); | |||
354 | return (rval); | |||
355 | } |