input.c revision 262951
1249259Sdim/*-
2249259Sdim * Copyright (c) 1991, 1993
3249259Sdim *	The Regents of the University of California.  All rights reserved.
4249259Sdim *
5249259Sdim * This code is derived from software contributed to Berkeley by
6249259Sdim * Kenneth Almquist.
7249259Sdim *
8249259Sdim * Redistribution and use in source and binary forms, with or without
9249259Sdim * modification, are permitted provided that the following conditions
10249259Sdim * are met:
11249259Sdim * 1. Redistributions of source code must retain the above copyright
12249259Sdim *    notice, this list of conditions and the following disclaimer.
13249259Sdim * 2. Redistributions in binary form must reproduce the above copyright
14249259Sdim *    notice, this list of conditions and the following disclaimer in the
15249259Sdim *    documentation and/or other materials provided with the distribution.
16249259Sdim * 4. Neither the name of the University nor the names of its contributors
17249259Sdim *    may be used to endorse or promote products derived from this software
18249259Sdim *    without specific prior written permission.
19249259Sdim *
20249259Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21249259Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22249259Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23249259Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24249259Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25249259Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26249259Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27249259Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28249259Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29249259Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30249259Sdim * SUCH DAMAGE.
31249259Sdim */
32249259Sdim
33249259Sdim#ifndef lint
34249259Sdim#if 0
35249259Sdimstatic char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
36249259Sdim#endif
37249259Sdim#endif /* not lint */
38249259Sdim#include <sys/cdefs.h>
39249259Sdim__FBSDID("$FreeBSD: stable/10/bin/sh/input.c 262951 2014-03-09 17:04:31Z jmmv $");
40249259Sdim
41249259Sdim#include <stdio.h>	/* defines BUFSIZ */
42249259Sdim#include <fcntl.h>
43249259Sdim#include <errno.h>
44249259Sdim#include <unistd.h>
45249259Sdim#include <stdlib.h>
46249259Sdim#include <string.h>
47249259Sdim
48249259Sdim/*
49249259Sdim * This file implements the input routines used by the parser.
50249259Sdim */
51249259Sdim
52249259Sdim#include "shell.h"
53249259Sdim#include "redir.h"
54249259Sdim#include "syntax.h"
55249259Sdim#include "input.h"
56249259Sdim#include "output.h"
57249259Sdim#include "options.h"
58249259Sdim#include "memalloc.h"
59249259Sdim#include "error.h"
60249259Sdim#include "alias.h"
61249259Sdim#include "parser.h"
62249259Sdim#include "myhistedit.h"
63249259Sdim#include "trap.h"
64249259Sdim
65249259Sdim#define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
66249259Sdim
67249259Sdimstruct strpush {
68249259Sdim	struct strpush *prev;	/* preceding string on stack */
69249259Sdim	const char *prevstring;
70249259Sdim	int prevnleft;
71249259Sdim	int prevlleft;
72249259Sdim	struct alias *ap;	/* if push was associated with an alias */
73249259Sdim};
74249259Sdim
75249259Sdim/*
76249259Sdim * The parsefile structure pointed to by the global variable parsefile
77249259Sdim * contains information about the current file being read.
78249259Sdim */
79249259Sdim
80249259Sdimstruct parsefile {
81249259Sdim	struct parsefile *prev;	/* preceding file on stack */
82249259Sdim	int linno;		/* current line */
83249259Sdim	int fd;			/* file descriptor (or -1 if string) */
84249259Sdim	int nleft;		/* number of chars left in this line */
85249259Sdim	int lleft;		/* number of lines left in this buffer */
86249259Sdim	const char *nextc;	/* next char in buffer */
87249259Sdim	char *buf;		/* input buffer */
88249259Sdim	struct strpush *strpush; /* for pushing strings at this level */
89249259Sdim	struct strpush basestrpush; /* so pushing one is fast */
90249259Sdim};
91249259Sdim
92249259Sdim
93249259Sdimint plinno = 1;			/* input line number */
94249259Sdimint parsenleft;			/* copy of parsefile->nleft */
95249259Sdimstatic int parselleft;		/* copy of parsefile->lleft */
96249259Sdimconst char *parsenextc;		/* copy of parsefile->nextc */
97249259Sdimstatic char basebuf[BUFSIZ + 1];/* buffer for top level input file */
98249259Sdimstatic struct parsefile basepf = {	/* top level input file */
99249259Sdim	.nextc = basebuf,
100249259Sdim	.buf = basebuf
101249259Sdim};
102249259Sdimstatic struct parsefile *parsefile = &basepf;	/* current input file */
103249259Sdimint whichprompt;		/* 1 == PS1, 2 == PS2 */
104249259Sdim
105249259SdimEditLine *el;			/* cookie for editline package */
106249259Sdim
107249259Sdimstatic void pushfile(void);
108249259Sdimstatic int preadfd(void);
109249259Sdimstatic void popstring(void);
110249259Sdim
111249259Sdimvoid
112249259Sdimresetinput(void)
113249259Sdim{
114249259Sdim	popallfiles();
115249259Sdim	parselleft = parsenleft = 0;	/* clear input buffer */
116249259Sdim}
117249259Sdim
118249259Sdim
119249259Sdim/*
120249259Sdim * Read a line from the script.
121249259Sdim */
122249259Sdim
123249259Sdimchar *
124249259Sdimpfgets(char *line, int len)
125249259Sdim{
126249259Sdim	char *p = line;
127249259Sdim	int nleft = len;
128249259Sdim	int c;
129249259Sdim
130249259Sdim	while (--nleft > 0) {
131249259Sdim		c = pgetc_macro();
132249259Sdim		if (c == PEOF) {
133249259Sdim			if (p == line)
134249259Sdim				return NULL;
135249259Sdim			break;
136249259Sdim		}
137249259Sdim		*p++ = c;
138249259Sdim		if (c == '\n')
139249259Sdim			break;
140249259Sdim	}
141249259Sdim	*p = '\0';
142249259Sdim	return line;
143249259Sdim}
144249259Sdim
145249259Sdim
146249259Sdim
147249259Sdim/*
148249259Sdim * Read a character from the script, returning PEOF on end of file.
149249259Sdim * Nul characters in the input are silently discarded.
150249259Sdim */
151249259Sdim
152249259Sdimint
153249259Sdimpgetc(void)
154249259Sdim{
155249259Sdim	return pgetc_macro();
156249259Sdim}
157249259Sdim
158249259Sdim
159249259Sdimstatic int
160249259Sdimpreadfd(void)
161249259Sdim{
162249259Sdim	int nr;
163249259Sdim	parsenextc = parsefile->buf;
164249259Sdim
165249259Sdimretry:
166249259Sdim#ifndef NO_HISTORY
167249259Sdim	if (parsefile->fd == 0 && el) {
168249259Sdim		static const char *rl_cp;
169249259Sdim		static int el_len;
170249259Sdim
171249259Sdim		if (rl_cp == NULL) {
172249259Sdim			el_resize(el);
173249259Sdim			rl_cp = el_gets(el, &el_len);
174249259Sdim		}
175249259Sdim		if (rl_cp == NULL)
176249259Sdim			nr = el_len == 0 ? 0 : -1;
177249259Sdim		else {
178249259Sdim			nr = el_len;
179249259Sdim			if (nr > BUFSIZ)
180249259Sdim				nr = BUFSIZ;
181249259Sdim			memcpy(parsefile->buf, rl_cp, nr);
182249259Sdim			if (nr != el_len) {
183249259Sdim				el_len -= nr;
184249259Sdim				rl_cp += nr;
185249259Sdim			} else
186249259Sdim				rl_cp = NULL;
187249259Sdim		}
188249259Sdim	} else
189249259Sdim#endif
190249259Sdim		nr = read(parsefile->fd, parsefile->buf, BUFSIZ);
191249259Sdim
192249259Sdim	if (nr <= 0) {
193249259Sdim                if (nr < 0) {
194249259Sdim                        if (errno == EINTR)
195249259Sdim                                goto retry;
196249259Sdim                        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
197249259Sdim                                int flags = fcntl(0, F_GETFL, 0);
198249259Sdim                                if (flags >= 0 && flags & O_NONBLOCK) {
199249259Sdim                                        flags &=~ O_NONBLOCK;
200249259Sdim                                        if (fcntl(0, F_SETFL, flags) >= 0) {
201249259Sdim						out2fmt_flush("sh: turning off NDELAY mode\n");
202249259Sdim                                                goto retry;
203249259Sdim                                        }
204249259Sdim                                }
205249259Sdim                        }
206249259Sdim                }
207249259Sdim                nr = -1;
208249259Sdim	}
209249259Sdim	return nr;
210249259Sdim}
211249259Sdim
212249259Sdim/*
213249259Sdim * Refill the input buffer and return the next input character:
214249259Sdim *
215249259Sdim * 1) If a string was pushed back on the input, pop it;
216249259Sdim * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
217249259Sdim *    from a string so we can't refill the buffer, return EOF.
218249259Sdim * 3) If there is more in this buffer, use it else call read to fill it.
219249259Sdim * 4) Process input up to the next newline, deleting nul characters.
220249259Sdim */
221249259Sdim
222249259Sdimint
223249259Sdimpreadbuffer(void)
224249259Sdim{
225249259Sdim	char *p, *q;
226249259Sdim	int more;
227249259Sdim	char savec;
228249259Sdim
229249259Sdim	while (parsefile->strpush) {
230249259Sdim		/*
231249259Sdim		 * Add a space to the end of an alias to ensure that the
232249259Sdim		 * alias remains in use while parsing its last word.
233249259Sdim		 * This avoids alias recursions.
234249259Sdim		 */
235249259Sdim		if (parsenleft == -1 && parsefile->strpush->ap != NULL)
236249259Sdim			return ' ';
237249259Sdim		popstring();
238249259Sdim		if (--parsenleft >= 0)
239249259Sdim			return (*parsenextc++);
240249259Sdim	}
241249259Sdim	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
242249259Sdim		return PEOF;
243249259Sdim	flushout(&output);
244249259Sdim	flushout(&errout);
245249259Sdim
246249259Sdimagain:
247249259Sdim	if (parselleft <= 0) {
248249259Sdim		if ((parselleft = preadfd()) == -1) {
249249259Sdim			parselleft = parsenleft = EOF_NLEFT;
250249259Sdim			return PEOF;
251249259Sdim		}
252249259Sdim	}
253249259Sdim
254249259Sdim	q = p = parsefile->buf + (parsenextc - parsefile->buf);
255249259Sdim
256249259Sdim	/* delete nul characters */
257249259Sdim	for (more = 1; more;) {
258249259Sdim		switch (*p) {
259249259Sdim		case '\0':
260249259Sdim			p++;	/* Skip nul */
261249259Sdim			goto check;
262249259Sdim
263249259Sdim		case '\n':
264249259Sdim			parsenleft = q - parsenextc;
265249259Sdim			more = 0; /* Stop processing here */
266249259Sdim			break;
267249259Sdim
268249259Sdim		default:
269249259Sdim			break;
270249259Sdim		}
271249259Sdim
272249259Sdim		*q++ = *p++;
273249259Sdimcheck:
274249259Sdim		if (--parselleft <= 0) {
275249259Sdim			parsenleft = q - parsenextc - 1;
276249259Sdim			if (parsenleft < 0)
277249259Sdim				goto again;
278249259Sdim			*q = '\0';
279249259Sdim			more = 0;
280249259Sdim		}
281249259Sdim	}
282249259Sdim
283249259Sdim	savec = *q;
284249259Sdim	*q = '\0';
285249259Sdim
286249259Sdim#ifndef NO_HISTORY
287249259Sdim	if (parsefile->fd == 0 && hist &&
288249259Sdim	    parsenextc[strspn(parsenextc, " \t\n")] != '\0') {
289249259Sdim		HistEvent he;
290249259Sdim		INTOFF;
291249259Sdim		history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
292249259Sdim		    parsenextc);
293249259Sdim		INTON;
294249259Sdim	}
295249259Sdim#endif
296249259Sdim
297249259Sdim	if (vflag) {
298249259Sdim		out2str(parsenextc);
299249259Sdim		flushout(out2);
300249259Sdim	}
301249259Sdim
302249259Sdim	*q = savec;
303249259Sdim
304249259Sdim	return *parsenextc++;
305249259Sdim}
306249259Sdim
307249259Sdim/*
308249259Sdim * Returns if we are certain we are at EOF. Does not cause any more input
309249259Sdim * to be read from the outside world.
310249259Sdim */
311249259Sdim
312249259Sdimint
313249259Sdimpreadateof(void)
314249259Sdim{
315249259Sdim	if (parsenleft > 0)
316249259Sdim		return 0;
317249259Sdim	if (parsefile->strpush)
318249259Sdim		return 0;
319249259Sdim	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
320249259Sdim		return 1;
321249259Sdim	return 0;
322249259Sdim}
323249259Sdim
324249259Sdim/*
325249259Sdim * Undo the last call to pgetc.  Only one character may be pushed back.
326249259Sdim * PEOF may be pushed back.
327249259Sdim */
328249259Sdim
329249259Sdimvoid
330249259Sdimpungetc(void)
331249259Sdim{
332249259Sdim	parsenleft++;
333249259Sdim	parsenextc--;
334249259Sdim}
335249259Sdim
336249259Sdim/*
337249259Sdim * Push a string back onto the input at this current parsefile level.
338249259Sdim * We handle aliases this way.
339249259Sdim */
340249259Sdimvoid
341249259Sdimpushstring(char *s, int len, struct alias *ap)
342249259Sdim{
343249259Sdim	struct strpush *sp;
344249259Sdim
345249259Sdim	INTOFF;
346249259Sdim/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
347249259Sdim	if (parsefile->strpush) {
348249259Sdim		sp = ckmalloc(sizeof (struct strpush));
349249259Sdim		sp->prev = parsefile->strpush;
350249259Sdim		parsefile->strpush = sp;
351249259Sdim	} else
352249259Sdim		sp = parsefile->strpush = &(parsefile->basestrpush);
353249259Sdim	sp->prevstring = parsenextc;
354249259Sdim	sp->prevnleft = parsenleft;
355249259Sdim	sp->prevlleft = parselleft;
356249259Sdim	sp->ap = ap;
357249259Sdim	if (ap)
358249259Sdim		ap->flag |= ALIASINUSE;
359249259Sdim	parsenextc = s;
360249259Sdim	parsenleft = len;
361249259Sdim	INTON;
362249259Sdim}
363249259Sdim
364249259Sdimstatic void
365249259Sdimpopstring(void)
366249259Sdim{
367249259Sdim	struct strpush *sp = parsefile->strpush;
368249259Sdim
369249259Sdim	INTOFF;
370249259Sdim	if (sp->ap) {
371249259Sdim		if (parsenextc != sp->ap->val &&
372249259Sdim		    (parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))
373249259Sdim			forcealias();
374249259Sdim		sp->ap->flag &= ~ALIASINUSE;
375249259Sdim	}
376249259Sdim	parsenextc = sp->prevstring;
377249259Sdim	parsenleft = sp->prevnleft;
378249259Sdim	parselleft = sp->prevlleft;
379249259Sdim/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
380249259Sdim	parsefile->strpush = sp->prev;
381249259Sdim	if (sp != &(parsefile->basestrpush))
382249259Sdim		ckfree(sp);
383249259Sdim	INTON;
384249259Sdim}
385249259Sdim
386249259Sdim/*
387249259Sdim * Set the input to take input from a file.  If push is set, push the
388249259Sdim * old input onto the stack first.
389249259Sdim */
390249259Sdim
391249259Sdimvoid
392249259Sdimsetinputfile(const char *fname, int push)
393249259Sdim{
394249259Sdim	int fd;
395249259Sdim	int fd2;
396249259Sdim
397249259Sdim	INTOFF;
398249259Sdim	if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0)
399249259Sdim		error("cannot open %s: %s", fname, strerror(errno));
400249259Sdim	if (fd < 10) {
401249259Sdim		fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);
402249259Sdim		close(fd);
403249259Sdim		if (fd2 < 0)
404249259Sdim			error("Out of file descriptors");
405249259Sdim		fd = fd2;
406249259Sdim	}
407249259Sdim	setinputfd(fd, push);
408249259Sdim	INTON;
409249259Sdim}
410249259Sdim
411249259Sdim
412249259Sdim/*
413249259Sdim * Like setinputfile, but takes an open file descriptor (which should have
414249259Sdim * its FD_CLOEXEC flag already set).  Call this with interrupts off.
415249259Sdim */
416249259Sdim
417249259Sdimvoid
418249259Sdimsetinputfd(int fd, int push)
419249259Sdim{
420249259Sdim	if (push) {
421249259Sdim		pushfile();
422249259Sdim		parsefile->buf = ckmalloc(BUFSIZ + 1);
423249259Sdim	}
424249259Sdim	if (parsefile->fd > 0)
425249259Sdim		close(parsefile->fd);
426249259Sdim	parsefile->fd = fd;
427249259Sdim	if (parsefile->buf == NULL)
428249259Sdim		parsefile->buf = ckmalloc(BUFSIZ + 1);
429249259Sdim	parselleft = parsenleft = 0;
430249259Sdim	plinno = 1;
431249259Sdim}
432249259Sdim
433249259Sdim
434249259Sdim/*
435249259Sdim * Like setinputfile, but takes input from a string.
436249259Sdim */
437249259Sdim
438249259Sdimvoid
439249259Sdimsetinputstring(const char *string, int push)
440249259Sdim{
441249259Sdim	INTOFF;
442249259Sdim	if (push)
443249259Sdim		pushfile();
444249259Sdim	parsenextc = string;
445249259Sdim	parselleft = parsenleft = strlen(string);
446249259Sdim	parsefile->buf = NULL;
447249259Sdim	plinno = 1;
448249259Sdim	INTON;
449249259Sdim}
450249259Sdim
451249259Sdim
452249259Sdim
453249259Sdim/*
454249259Sdim * To handle the "." command, a stack of input files is used.  Pushfile
455249259Sdim * adds a new entry to the stack and popfile restores the previous level.
456249259Sdim */
457249259Sdim
458249259Sdimstatic void
459249259Sdimpushfile(void)
460249259Sdim{
461249259Sdim	struct parsefile *pf;
462249259Sdim
463249259Sdim	parsefile->nleft = parsenleft;
464249259Sdim	parsefile->lleft = parselleft;
465249259Sdim	parsefile->nextc = parsenextc;
466249259Sdim	parsefile->linno = plinno;
467249259Sdim	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
468249259Sdim	pf->prev = parsefile;
469249259Sdim	pf->fd = -1;
470249259Sdim	pf->strpush = NULL;
471249259Sdim	pf->basestrpush.prev = NULL;
472249259Sdim	parsefile = pf;
473249259Sdim}
474249259Sdim
475249259Sdim
476249259Sdimvoid
477249259Sdimpopfile(void)
478249259Sdim{
479249259Sdim	struct parsefile *pf = parsefile;
480249259Sdim
481249259Sdim	INTOFF;
482249259Sdim	if (pf->fd >= 0)
483249259Sdim		close(pf->fd);
484249259Sdim	if (pf->buf)
485249259Sdim		ckfree(pf->buf);
486249259Sdim	while (pf->strpush)
487249259Sdim		popstring();
488249259Sdim	parsefile = pf->prev;
489249259Sdim	ckfree(pf);
490249259Sdim	parsenleft = parsefile->nleft;
491249259Sdim	parselleft = parsefile->lleft;
492249259Sdim	parsenextc = parsefile->nextc;
493249259Sdim	plinno = parsefile->linno;
494249259Sdim	INTON;
495249259Sdim}
496249259Sdim
497249259Sdim
498249259Sdim/*
499249259Sdim * Return current file (to go back to it later using popfilesupto()).
500249259Sdim */
501249259Sdim
502249259Sdimstruct parsefile *
503249259Sdimgetcurrentfile(void)
504249259Sdim{
505249259Sdim	return parsefile;
506249259Sdim}
507249259Sdim
508249259Sdim
509249259Sdim/*
510249259Sdim * Pop files until the given file is on top again. Useful for regular
511249259Sdim * builtins that read shell commands from files or strings.
512249259Sdim * If the given file is not an active file, an error is raised.
513249259Sdim */
514249259Sdim
515249259Sdimvoid
516249259Sdimpopfilesupto(struct parsefile *file)
517249259Sdim{
518249259Sdim	while (parsefile != file && parsefile != &basepf)
519249259Sdim		popfile();
520249259Sdim	if (parsefile != file)
521249259Sdim		error("popfilesupto() misused");
522249259Sdim}
523249259Sdim
524249259Sdim/*
525249259Sdim * Return to top level.
526249259Sdim */
527249259Sdim
528249259Sdimvoid
529249259Sdimpopallfiles(void)
530249259Sdim{
531249259Sdim	while (parsefile != &basepf)
532249259Sdim		popfile();
533249259Sdim}
534249259Sdim
535249259Sdim
536249259Sdim
537249259Sdim/*
538249259Sdim * Close the file(s) that the shell is reading commands from.  Called
539249259Sdim * after a fork is done.
540249259Sdim */
541249259Sdim
542249259Sdimvoid
543249259Sdimclosescript(void)
544249259Sdim{
545249259Sdim	popallfiles();
546249259Sdim	if (parsefile->fd > 0) {
547249259Sdim		close(parsefile->fd);
548249259Sdim		parsefile->fd = 0;
549249259Sdim	}
550249259Sdim}
551249259Sdim