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