Deleted Added
full compact
input.c (245676) input.c (248980)
1/*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
36#endif
37#endif /* not lint */
38#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
36#endif
37#endif /* not lint */
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: head/bin/sh/input.c 245676 2013-01-19 22:12:08Z jilles $");
39__FBSDID("$FreeBSD: head/bin/sh/input.c 248980 2013-04-01 17:18:22Z jilles $");
40
41#include <stdio.h> /* defines BUFSIZ */
42#include <fcntl.h>
43#include <errno.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include <string.h>
47
48/*
49 * This file implements the input routines used by the parser.
50 */
51
52#include "shell.h"
53#include "redir.h"
54#include "syntax.h"
55#include "input.h"
56#include "output.h"
57#include "options.h"
58#include "memalloc.h"
59#include "error.h"
60#include "alias.h"
61#include "parser.h"
62#include "myhistedit.h"
63#include "trap.h"
64
65#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
66
67struct strpush {
68 struct strpush *prev; /* preceding string on stack */
40
41#include <stdio.h> /* defines BUFSIZ */
42#include <fcntl.h>
43#include <errno.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include <string.h>
47
48/*
49 * This file implements the input routines used by the parser.
50 */
51
52#include "shell.h"
53#include "redir.h"
54#include "syntax.h"
55#include "input.h"
56#include "output.h"
57#include "options.h"
58#include "memalloc.h"
59#include "error.h"
60#include "alias.h"
61#include "parser.h"
62#include "myhistedit.h"
63#include "trap.h"
64
65#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
66
67struct strpush {
68 struct strpush *prev; /* preceding string on stack */
69 char *prevstring;
69 const char *prevstring;
70 int prevnleft;
71 int prevlleft;
72 struct alias *ap; /* if push was associated with an alias */
73};
74
75/*
76 * The parsefile structure pointed to by the global variable parsefile
77 * contains information about the current file being read.
78 */
79
80struct parsefile {
81 struct parsefile *prev; /* preceding file on stack */
82 int linno; /* current line */
83 int fd; /* file descriptor (or -1 if string) */
84 int nleft; /* number of chars left in this line */
85 int lleft; /* number of lines left in this buffer */
70 int prevnleft;
71 int prevlleft;
72 struct alias *ap; /* if push was associated with an alias */
73};
74
75/*
76 * The parsefile structure pointed to by the global variable parsefile
77 * contains information about the current file being read.
78 */
79
80struct parsefile {
81 struct parsefile *prev; /* preceding file on stack */
82 int linno; /* current line */
83 int fd; /* file descriptor (or -1 if string) */
84 int nleft; /* number of chars left in this line */
85 int lleft; /* number of lines left in this buffer */
86 char *nextc; /* next char in buffer */
86 const char *nextc; /* next char in buffer */
87 char *buf; /* input buffer */
88 struct strpush *strpush; /* for pushing strings at this level */
89 struct strpush basestrpush; /* so pushing one is fast */
90};
91
92
93int plinno = 1; /* input line number */
94int parsenleft; /* copy of parsefile->nleft */
95MKINIT int parselleft; /* copy of parsefile->lleft */
87 char *buf; /* input buffer */
88 struct strpush *strpush; /* for pushing strings at this level */
89 struct strpush basestrpush; /* so pushing one is fast */
90};
91
92
93int plinno = 1; /* input line number */
94int parsenleft; /* copy of parsefile->nleft */
95MKINIT int parselleft; /* copy of parsefile->lleft */
96char *parsenextc; /* copy of parsefile->nextc */
96const char *parsenextc; /* copy of parsefile->nextc */
97static char basebuf[BUFSIZ + 1];/* buffer for top level input file */
98static struct parsefile basepf = { /* top level input file */
99 .nextc = basebuf,
100 .buf = basebuf
101};
102static struct parsefile *parsefile = &basepf; /* current input file */
103int whichprompt; /* 1 == PS1, 2 == PS2 */
104
105EditLine *el; /* cookie for editline package */
106
107static void pushfile(void);
108static int preadfd(void);
109static void popstring(void);
110
111#ifdef mkinit
112INCLUDE "input.h"
113INCLUDE "error.h"
114
115RESET {
116 popallfiles();
117 parselleft = parsenleft = 0; /* clear input buffer */
118}
119#endif
120
121
122/*
123 * Read a line from the script.
124 */
125
126char *
127pfgets(char *line, int len)
128{
129 char *p = line;
130 int nleft = len;
131 int c;
132
133 while (--nleft > 0) {
134 c = pgetc_macro();
135 if (c == PEOF) {
136 if (p == line)
137 return NULL;
138 break;
139 }
140 *p++ = c;
141 if (c == '\n')
142 break;
143 }
144 *p = '\0';
145 return line;
146}
147
148
149
150/*
151 * Read a character from the script, returning PEOF on end of file.
152 * Nul characters in the input are silently discarded.
153 */
154
155int
156pgetc(void)
157{
158 return pgetc_macro();
159}
160
161
162static int
163preadfd(void)
164{
165 int nr;
166 parsenextc = parsefile->buf;
167
168#ifndef NO_HISTORY
169 if (el != NULL && gotwinch) {
170 gotwinch = 0;
171 el_resize(el);
172 }
173#endif
174retry:
175#ifndef NO_HISTORY
176 if (parsefile->fd == 0 && el) {
177 static const char *rl_cp;
178 static int el_len;
179
180 if (rl_cp == NULL)
181 rl_cp = el_gets(el, &el_len);
182 if (rl_cp == NULL)
183 nr = el_len == 0 ? 0 : -1;
184 else {
185 nr = el_len;
186 if (nr > BUFSIZ)
187 nr = BUFSIZ;
97static char basebuf[BUFSIZ + 1];/* buffer for top level input file */
98static struct parsefile basepf = { /* top level input file */
99 .nextc = basebuf,
100 .buf = basebuf
101};
102static struct parsefile *parsefile = &basepf; /* current input file */
103int whichprompt; /* 1 == PS1, 2 == PS2 */
104
105EditLine *el; /* cookie for editline package */
106
107static void pushfile(void);
108static int preadfd(void);
109static void popstring(void);
110
111#ifdef mkinit
112INCLUDE "input.h"
113INCLUDE "error.h"
114
115RESET {
116 popallfiles();
117 parselleft = parsenleft = 0; /* clear input buffer */
118}
119#endif
120
121
122/*
123 * Read a line from the script.
124 */
125
126char *
127pfgets(char *line, int len)
128{
129 char *p = line;
130 int nleft = len;
131 int c;
132
133 while (--nleft > 0) {
134 c = pgetc_macro();
135 if (c == PEOF) {
136 if (p == line)
137 return NULL;
138 break;
139 }
140 *p++ = c;
141 if (c == '\n')
142 break;
143 }
144 *p = '\0';
145 return line;
146}
147
148
149
150/*
151 * Read a character from the script, returning PEOF on end of file.
152 * Nul characters in the input are silently discarded.
153 */
154
155int
156pgetc(void)
157{
158 return pgetc_macro();
159}
160
161
162static int
163preadfd(void)
164{
165 int nr;
166 parsenextc = parsefile->buf;
167
168#ifndef NO_HISTORY
169 if (el != NULL && gotwinch) {
170 gotwinch = 0;
171 el_resize(el);
172 }
173#endif
174retry:
175#ifndef NO_HISTORY
176 if (parsefile->fd == 0 && el) {
177 static const char *rl_cp;
178 static int el_len;
179
180 if (rl_cp == NULL)
181 rl_cp = el_gets(el, &el_len);
182 if (rl_cp == NULL)
183 nr = el_len == 0 ? 0 : -1;
184 else {
185 nr = el_len;
186 if (nr > BUFSIZ)
187 nr = BUFSIZ;
188 memcpy(parsenextc, rl_cp, nr);
188 memcpy(parsefile->buf, rl_cp, nr);
189 if (nr != el_len) {
190 el_len -= nr;
191 rl_cp += nr;
192 } else
193 rl_cp = NULL;
194 }
195 } else
196#endif
189 if (nr != el_len) {
190 el_len -= nr;
191 rl_cp += nr;
192 } else
193 rl_cp = NULL;
194 }
195 } else
196#endif
197 nr = read(parsefile->fd, parsenextc, BUFSIZ);
197 nr = read(parsefile->fd, parsefile->buf, BUFSIZ);
198
199 if (nr <= 0) {
200 if (nr < 0) {
201 if (errno == EINTR)
202 goto retry;
203 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
204 int flags = fcntl(0, F_GETFL, 0);
205 if (flags >= 0 && flags & O_NONBLOCK) {
206 flags &=~ O_NONBLOCK;
207 if (fcntl(0, F_SETFL, flags) >= 0) {
208 out2fmt_flush("sh: turning off NDELAY mode\n");
209 goto retry;
210 }
211 }
212 }
213 }
214 nr = -1;
215 }
216 return nr;
217}
218
219/*
220 * Refill the input buffer and return the next input character:
221 *
222 * 1) If a string was pushed back on the input, pop it;
223 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
224 * from a string so we can't refill the buffer, return EOF.
225 * 3) If there is more in this buffer, use it else call read to fill it.
226 * 4) Process input up to the next newline, deleting nul characters.
227 */
228
229int
230preadbuffer(void)
231{
232 char *p, *q;
233 int more;
234 int something;
235 char savec;
236
237 if (parsefile->strpush) {
238 popstring();
239 if (--parsenleft >= 0)
240 return (*parsenextc++);
241 }
242 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
243 return PEOF;
244 flushout(&output);
245 flushout(&errout);
246
247again:
248 if (parselleft <= 0) {
249 if ((parselleft = preadfd()) == -1) {
250 parselleft = parsenleft = EOF_NLEFT;
251 return PEOF;
252 }
253 }
254
198
199 if (nr <= 0) {
200 if (nr < 0) {
201 if (errno == EINTR)
202 goto retry;
203 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
204 int flags = fcntl(0, F_GETFL, 0);
205 if (flags >= 0 && flags & O_NONBLOCK) {
206 flags &=~ O_NONBLOCK;
207 if (fcntl(0, F_SETFL, flags) >= 0) {
208 out2fmt_flush("sh: turning off NDELAY mode\n");
209 goto retry;
210 }
211 }
212 }
213 }
214 nr = -1;
215 }
216 return nr;
217}
218
219/*
220 * Refill the input buffer and return the next input character:
221 *
222 * 1) If a string was pushed back on the input, pop it;
223 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
224 * from a string so we can't refill the buffer, return EOF.
225 * 3) If there is more in this buffer, use it else call read to fill it.
226 * 4) Process input up to the next newline, deleting nul characters.
227 */
228
229int
230preadbuffer(void)
231{
232 char *p, *q;
233 int more;
234 int something;
235 char savec;
236
237 if (parsefile->strpush) {
238 popstring();
239 if (--parsenleft >= 0)
240 return (*parsenextc++);
241 }
242 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
243 return PEOF;
244 flushout(&output);
245 flushout(&errout);
246
247again:
248 if (parselleft <= 0) {
249 if ((parselleft = preadfd()) == -1) {
250 parselleft = parsenleft = EOF_NLEFT;
251 return PEOF;
252 }
253 }
254
255 q = p = parsenextc;
255 q = p = parsefile->buf + (parsenextc - parsefile->buf);
256
257 /* delete nul characters */
258 something = 0;
259 for (more = 1; more;) {
260 switch (*p) {
261 case '\0':
262 p++; /* Skip nul */
263 goto check;
264
265 case '\t':
266 case ' ':
267 break;
268
269 case '\n':
270 parsenleft = q - parsenextc;
271 more = 0; /* Stop processing here */
272 break;
273
274 default:
275 something = 1;
276 break;
277 }
278
279 *q++ = *p++;
280check:
281 if (--parselleft <= 0) {
282 parsenleft = q - parsenextc - 1;
283 if (parsenleft < 0)
284 goto again;
285 *q = '\0';
286 more = 0;
287 }
288 }
289
290 savec = *q;
291 *q = '\0';
292
293#ifndef NO_HISTORY
294 if (parsefile->fd == 0 && hist && something) {
295 HistEvent he;
296 INTOFF;
297 history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
298 parsenextc);
299 INTON;
300 }
301#endif
302
303 if (vflag) {
304 out2str(parsenextc);
305 flushout(out2);
306 }
307
308 *q = savec;
309
310 return *parsenextc++;
311}
312
313/*
314 * Returns if we are certain we are at EOF. Does not cause any more input
315 * to be read from the outside world.
316 */
317
318int
319preadateof(void)
320{
321 if (parsenleft > 0)
322 return 0;
323 if (parsefile->strpush)
324 return 0;
325 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
326 return 1;
327 return 0;
328}
329
330/*
331 * Undo the last call to pgetc. Only one character may be pushed back.
332 * PEOF may be pushed back.
333 */
334
335void
336pungetc(void)
337{
338 parsenleft++;
339 parsenextc--;
340}
341
342/*
343 * Push a string back onto the input at this current parsefile level.
344 * We handle aliases this way.
345 */
346void
347pushstring(char *s, int len, struct alias *ap)
348{
349 struct strpush *sp;
350
351 INTOFF;
352/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
353 if (parsefile->strpush) {
354 sp = ckmalloc(sizeof (struct strpush));
355 sp->prev = parsefile->strpush;
356 parsefile->strpush = sp;
357 } else
358 sp = parsefile->strpush = &(parsefile->basestrpush);
359 sp->prevstring = parsenextc;
360 sp->prevnleft = parsenleft;
361 sp->prevlleft = parselleft;
362 sp->ap = ap;
363 if (ap)
364 ap->flag |= ALIASINUSE;
365 parsenextc = s;
366 parsenleft = len;
367 INTON;
368}
369
370static void
371popstring(void)
372{
373 struct strpush *sp = parsefile->strpush;
374
375 INTOFF;
376 parsenextc = sp->prevstring;
377 parsenleft = sp->prevnleft;
378 parselleft = sp->prevlleft;
379/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
380 if (sp->ap)
381 sp->ap->flag &= ~ALIASINUSE;
382 parsefile->strpush = sp->prev;
383 if (sp != &(parsefile->basestrpush))
384 ckfree(sp);
385 INTON;
386}
387
388/*
389 * Set the input to take input from a file. If push is set, push the
390 * old input onto the stack first.
391 */
392
393void
394setinputfile(const char *fname, int push)
395{
396 int fd;
397 int fd2;
398
399 INTOFF;
400 if ((fd = open(fname, O_RDONLY)) < 0)
401 error("cannot open %s: %s", fname, strerror(errno));
402 if (fd < 10) {
403 fd2 = fcntl(fd, F_DUPFD, 10);
404 close(fd);
405 if (fd2 < 0)
406 error("Out of file descriptors");
407 fd = fd2;
408 }
409 setinputfd(fd, push);
410 INTON;
411}
412
413
414/*
415 * Like setinputfile, but takes an open file descriptor. Call this with
416 * interrupts off.
417 */
418
419void
420setinputfd(int fd, int push)
421{
422 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
423 if (push) {
424 pushfile();
425 parsefile->buf = ckmalloc(BUFSIZ + 1);
426 }
427 if (parsefile->fd > 0)
428 close(parsefile->fd);
429 parsefile->fd = fd;
430 if (parsefile->buf == NULL)
431 parsefile->buf = ckmalloc(BUFSIZ + 1);
432 parselleft = parsenleft = 0;
433 plinno = 1;
434}
435
436
437/*
438 * Like setinputfile, but takes input from a string.
439 */
440
441void
256
257 /* delete nul characters */
258 something = 0;
259 for (more = 1; more;) {
260 switch (*p) {
261 case '\0':
262 p++; /* Skip nul */
263 goto check;
264
265 case '\t':
266 case ' ':
267 break;
268
269 case '\n':
270 parsenleft = q - parsenextc;
271 more = 0; /* Stop processing here */
272 break;
273
274 default:
275 something = 1;
276 break;
277 }
278
279 *q++ = *p++;
280check:
281 if (--parselleft <= 0) {
282 parsenleft = q - parsenextc - 1;
283 if (parsenleft < 0)
284 goto again;
285 *q = '\0';
286 more = 0;
287 }
288 }
289
290 savec = *q;
291 *q = '\0';
292
293#ifndef NO_HISTORY
294 if (parsefile->fd == 0 && hist && something) {
295 HistEvent he;
296 INTOFF;
297 history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
298 parsenextc);
299 INTON;
300 }
301#endif
302
303 if (vflag) {
304 out2str(parsenextc);
305 flushout(out2);
306 }
307
308 *q = savec;
309
310 return *parsenextc++;
311}
312
313/*
314 * Returns if we are certain we are at EOF. Does not cause any more input
315 * to be read from the outside world.
316 */
317
318int
319preadateof(void)
320{
321 if (parsenleft > 0)
322 return 0;
323 if (parsefile->strpush)
324 return 0;
325 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
326 return 1;
327 return 0;
328}
329
330/*
331 * Undo the last call to pgetc. Only one character may be pushed back.
332 * PEOF may be pushed back.
333 */
334
335void
336pungetc(void)
337{
338 parsenleft++;
339 parsenextc--;
340}
341
342/*
343 * Push a string back onto the input at this current parsefile level.
344 * We handle aliases this way.
345 */
346void
347pushstring(char *s, int len, struct alias *ap)
348{
349 struct strpush *sp;
350
351 INTOFF;
352/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
353 if (parsefile->strpush) {
354 sp = ckmalloc(sizeof (struct strpush));
355 sp->prev = parsefile->strpush;
356 parsefile->strpush = sp;
357 } else
358 sp = parsefile->strpush = &(parsefile->basestrpush);
359 sp->prevstring = parsenextc;
360 sp->prevnleft = parsenleft;
361 sp->prevlleft = parselleft;
362 sp->ap = ap;
363 if (ap)
364 ap->flag |= ALIASINUSE;
365 parsenextc = s;
366 parsenleft = len;
367 INTON;
368}
369
370static void
371popstring(void)
372{
373 struct strpush *sp = parsefile->strpush;
374
375 INTOFF;
376 parsenextc = sp->prevstring;
377 parsenleft = sp->prevnleft;
378 parselleft = sp->prevlleft;
379/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
380 if (sp->ap)
381 sp->ap->flag &= ~ALIASINUSE;
382 parsefile->strpush = sp->prev;
383 if (sp != &(parsefile->basestrpush))
384 ckfree(sp);
385 INTON;
386}
387
388/*
389 * Set the input to take input from a file. If push is set, push the
390 * old input onto the stack first.
391 */
392
393void
394setinputfile(const char *fname, int push)
395{
396 int fd;
397 int fd2;
398
399 INTOFF;
400 if ((fd = open(fname, O_RDONLY)) < 0)
401 error("cannot open %s: %s", fname, strerror(errno));
402 if (fd < 10) {
403 fd2 = fcntl(fd, F_DUPFD, 10);
404 close(fd);
405 if (fd2 < 0)
406 error("Out of file descriptors");
407 fd = fd2;
408 }
409 setinputfd(fd, push);
410 INTON;
411}
412
413
414/*
415 * Like setinputfile, but takes an open file descriptor. Call this with
416 * interrupts off.
417 */
418
419void
420setinputfd(int fd, int push)
421{
422 (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
423 if (push) {
424 pushfile();
425 parsefile->buf = ckmalloc(BUFSIZ + 1);
426 }
427 if (parsefile->fd > 0)
428 close(parsefile->fd);
429 parsefile->fd = fd;
430 if (parsefile->buf == NULL)
431 parsefile->buf = ckmalloc(BUFSIZ + 1);
432 parselleft = parsenleft = 0;
433 plinno = 1;
434}
435
436
437/*
438 * Like setinputfile, but takes input from a string.
439 */
440
441void
442setinputstring(char *string, int push)
442setinputstring(const char *string, int push)
443{
444 INTOFF;
445 if (push)
446 pushfile();
447 parsenextc = string;
448 parselleft = parsenleft = strlen(string);
449 parsefile->buf = NULL;
450 plinno = 1;
451 INTON;
452}
453
454
455
456/*
457 * To handle the "." command, a stack of input files is used. Pushfile
458 * adds a new entry to the stack and popfile restores the previous level.
459 */
460
461static void
462pushfile(void)
463{
464 struct parsefile *pf;
465
466 parsefile->nleft = parsenleft;
467 parsefile->lleft = parselleft;
468 parsefile->nextc = parsenextc;
469 parsefile->linno = plinno;
470 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
471 pf->prev = parsefile;
472 pf->fd = -1;
473 pf->strpush = NULL;
474 pf->basestrpush.prev = NULL;
475 parsefile = pf;
476}
477
478
479void
480popfile(void)
481{
482 struct parsefile *pf = parsefile;
483
484 INTOFF;
485 if (pf->fd >= 0)
486 close(pf->fd);
487 if (pf->buf)
488 ckfree(pf->buf);
489 while (pf->strpush)
490 popstring();
491 parsefile = pf->prev;
492 ckfree(pf);
493 parsenleft = parsefile->nleft;
494 parselleft = parsefile->lleft;
495 parsenextc = parsefile->nextc;
496 plinno = parsefile->linno;
497 INTON;
498}
499
500
501/*
502 * Return current file (to go back to it later using popfilesupto()).
503 */
504
505struct parsefile *
506getcurrentfile(void)
507{
508 return parsefile;
509}
510
511
512/*
513 * Pop files until the given file is on top again. Useful for regular
514 * builtins that read shell commands from files or strings.
515 * If the given file is not an active file, an error is raised.
516 */
517
518void
519popfilesupto(struct parsefile *file)
520{
521 while (parsefile != file && parsefile != &basepf)
522 popfile();
523 if (parsefile != file)
524 error("popfilesupto() misused");
525}
526
527/*
528 * Return to top level.
529 */
530
531void
532popallfiles(void)
533{
534 while (parsefile != &basepf)
535 popfile();
536}
537
538
539
540/*
541 * Close the file(s) that the shell is reading commands from. Called
542 * after a fork is done.
543 */
544
545void
546closescript(void)
547{
548 popallfiles();
549 if (parsefile->fd > 0) {
550 close(parsefile->fd);
551 parsefile->fd = 0;
552 }
553}
443{
444 INTOFF;
445 if (push)
446 pushfile();
447 parsenextc = string;
448 parselleft = parsenleft = strlen(string);
449 parsefile->buf = NULL;
450 plinno = 1;
451 INTON;
452}
453
454
455
456/*
457 * To handle the "." command, a stack of input files is used. Pushfile
458 * adds a new entry to the stack and popfile restores the previous level.
459 */
460
461static void
462pushfile(void)
463{
464 struct parsefile *pf;
465
466 parsefile->nleft = parsenleft;
467 parsefile->lleft = parselleft;
468 parsefile->nextc = parsenextc;
469 parsefile->linno = plinno;
470 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
471 pf->prev = parsefile;
472 pf->fd = -1;
473 pf->strpush = NULL;
474 pf->basestrpush.prev = NULL;
475 parsefile = pf;
476}
477
478
479void
480popfile(void)
481{
482 struct parsefile *pf = parsefile;
483
484 INTOFF;
485 if (pf->fd >= 0)
486 close(pf->fd);
487 if (pf->buf)
488 ckfree(pf->buf);
489 while (pf->strpush)
490 popstring();
491 parsefile = pf->prev;
492 ckfree(pf);
493 parsenleft = parsefile->nleft;
494 parselleft = parsefile->lleft;
495 parsenextc = parsefile->nextc;
496 plinno = parsefile->linno;
497 INTON;
498}
499
500
501/*
502 * Return current file (to go back to it later using popfilesupto()).
503 */
504
505struct parsefile *
506getcurrentfile(void)
507{
508 return parsefile;
509}
510
511
512/*
513 * Pop files until the given file is on top again. Useful for regular
514 * builtins that read shell commands from files or strings.
515 * If the given file is not an active file, an error is raised.
516 */
517
518void
519popfilesupto(struct parsefile *file)
520{
521 while (parsefile != file && parsefile != &basepf)
522 popfile();
523 if (parsefile != file)
524 error("popfilesupto() misused");
525}
526
527/*
528 * Return to top level.
529 */
530
531void
532popallfiles(void)
533{
534 while (parsefile != &basepf)
535 popfile();
536}
537
538
539
540/*
541 * Close the file(s) that the shell is reading commands from. Called
542 * after a fork is done.
543 */
544
545void
546closescript(void)
547{
548 popallfiles();
549 if (parsefile->fd > 0) {
550 close(parsefile->fd);
551 parsefile->fd = 0;
552 }
553}