xref: /csrg-svn/bin/sh/input.c (revision 54313)
147119Sbostic /*-
247119Sbostic  * Copyright (c) 1991 The Regents of the University of California.
347119Sbostic  * All rights reserved.
447119Sbostic  *
547119Sbostic  * This code is derived from software contributed to Berkeley by
647119Sbostic  * Kenneth Almquist.
747119Sbostic  *
847119Sbostic  * %sccs.include.redist.c%
947119Sbostic  */
1047119Sbostic 
1147119Sbostic #ifndef lint
12*54313Smarc static char sccsid[] = "@(#)input.c	5.5 (Berkeley) 06/23/92";
1347119Sbostic #endif /* not lint */
1447119Sbostic 
1547119Sbostic /*
1647119Sbostic  * This file implements the input routines used by the parser.
1747119Sbostic  */
1847119Sbostic 
1947119Sbostic #include <stdio.h>	/* defines BUFSIZ */
2047119Sbostic #include "shell.h"
2147119Sbostic #include <fcntl.h>
2247119Sbostic #include <errno.h>
2347119Sbostic #include "syntax.h"
2447119Sbostic #include "input.h"
2547119Sbostic #include "output.h"
26*54313Smarc #include "options.h"
2747119Sbostic #include "memalloc.h"
2847119Sbostic #include "error.h"
29*54313Smarc #include "alias.h"
30*54313Smarc #include "parser.h"
31*54313Smarc #include "histedit.h"
3247119Sbostic 
3347119Sbostic #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
3447119Sbostic 
35*54313Smarc MKINIT
36*54313Smarc struct strpush {
37*54313Smarc 	struct strpush *prev;	/* preceding string on stack */
38*54313Smarc 	char *prevstring;
39*54313Smarc 	int prevnleft;
40*54313Smarc 	struct alias *ap;	/* if push was associated with an alias */
41*54313Smarc };
4247119Sbostic 
4347119Sbostic /*
4447119Sbostic  * The parsefile structure pointed to by the global variable parsefile
4547119Sbostic  * contains information about the current file being read.
4647119Sbostic  */
4747119Sbostic 
4847119Sbostic MKINIT
4947119Sbostic struct parsefile {
50*54313Smarc 	struct parsefile *prev;	/* preceding file on stack */
5147119Sbostic 	int linno;		/* current line */
5247119Sbostic 	int fd;			/* file descriptor (or -1 if string) */
5347119Sbostic 	int nleft;		/* number of chars left in buffer */
5447119Sbostic 	char *nextc;		/* next char in buffer */
5547119Sbostic 	char *buf;		/* input buffer */
56*54313Smarc 	struct strpush *strpush; /* for pushing strings at this level */
57*54313Smarc 	struct strpush basestrpush; /* so pushing one is fast */
5847119Sbostic };
5947119Sbostic 
6047119Sbostic 
6147119Sbostic int plinno = 1;			/* input line number */
6247119Sbostic MKINIT int parsenleft;		/* copy of parsefile->nleft */
6347119Sbostic char *parsenextc;		/* copy of parsefile->nextc */
6447119Sbostic MKINIT struct parsefile basepf;	/* top level input file */
6547119Sbostic char basebuf[BUFSIZ];		/* buffer for top level input file */
6647119Sbostic struct parsefile *parsefile = &basepf;	/* current input file */
6747119Sbostic char *pushedstring;		/* copy of parsenextc when text pushed back */
6847119Sbostic int pushednleft;		/* copy of parsenleft when text pushed back */
69*54313Smarc int init_editline = 0;		/* editline library initialized? */
70*54313Smarc int whichprompt;		/* 1 == PS1, 2 == PS2 */
7147119Sbostic 
72*54313Smarc EditLine *el;			/* cookie for editline package */
73*54313Smarc 
7447119Sbostic #ifdef __STDC__
7547119Sbostic STATIC void pushfile(void);
7647119Sbostic #else
7747119Sbostic STATIC void pushfile();
7847119Sbostic #endif
7947119Sbostic 
8047119Sbostic 
8147119Sbostic 
8247119Sbostic #ifdef mkinit
8347119Sbostic INCLUDE "input.h"
8447119Sbostic INCLUDE "error.h"
8547119Sbostic 
8647119Sbostic INIT {
8747119Sbostic 	extern char basebuf[];
8847119Sbostic 
8947119Sbostic 	basepf.nextc = basepf.buf = basebuf;
9047119Sbostic }
9147119Sbostic 
9247119Sbostic RESET {
9347119Sbostic 	if (exception != EXSHELLPROC)
9447119Sbostic 		parsenleft = 0;            /* clear input buffer */
9547119Sbostic 	popallfiles();
9647119Sbostic }
9747119Sbostic 
9847119Sbostic SHELLPROC {
9947119Sbostic 	popallfiles();
10047119Sbostic }
10147119Sbostic #endif
10247119Sbostic 
10347119Sbostic 
10447119Sbostic /*
10547119Sbostic  * Read a line from the script.
10647119Sbostic  */
10747119Sbostic 
10847119Sbostic char *
10947119Sbostic pfgets(line, len)
11047119Sbostic 	char *line;
11147119Sbostic 	{
11247119Sbostic 	register char *p = line;
11347119Sbostic 	int nleft = len;
11447119Sbostic 	int c;
11547119Sbostic 
11647119Sbostic 	while (--nleft > 0) {
11747119Sbostic 		c = pgetc_macro();
11847119Sbostic 		if (c == PEOF) {
11947119Sbostic 			if (p == line)
12047119Sbostic 				return NULL;
12147119Sbostic 			break;
12247119Sbostic 		}
12347119Sbostic 		*p++ = c;
12447119Sbostic 		if (c == '\n')
12547119Sbostic 			break;
12647119Sbostic 	}
12747119Sbostic 	*p = '\0';
12847119Sbostic 	return line;
12947119Sbostic }
13047119Sbostic 
13147119Sbostic 
13247119Sbostic 
13347119Sbostic /*
13447119Sbostic  * Read a character from the script, returning PEOF on end of file.
13547119Sbostic  * Nul characters in the input are silently discarded.
13647119Sbostic  */
13747119Sbostic 
13847119Sbostic int
13947119Sbostic pgetc() {
14047119Sbostic 	return pgetc_macro();
14147119Sbostic }
14247119Sbostic 
14347119Sbostic 
14447119Sbostic /*
14547119Sbostic  * Refill the input buffer and return the next input character:
14647119Sbostic  *
147*54313Smarc  * 1) If a string was pushed back on the input, pop it;
14847119Sbostic  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
14947119Sbostic  *    from a string so we can't refill the buffer, return EOF.
15047119Sbostic  * 3) Call read to read in the characters.
15147119Sbostic  * 4) Delete all nul characters from the buffer.
15247119Sbostic  */
15347119Sbostic 
15447119Sbostic int
15547119Sbostic preadbuffer() {
15647119Sbostic 	register char *p, *q;
15747119Sbostic 	register int i;
158*54313Smarc 	register int something;
159*54313Smarc 	extern EditLine *el;
160*54313Smarc 	extern int is_interactive;
16147119Sbostic 
162*54313Smarc 	if (parsefile->strpush) {
163*54313Smarc 		popstring();
16447119Sbostic 		if (--parsenleft >= 0)
165*54313Smarc 			return (*parsenextc++);
16647119Sbostic 	}
16747119Sbostic 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
16847119Sbostic 		return PEOF;
16947119Sbostic 	flushout(&output);
17047119Sbostic 	flushout(&errout);
17147119Sbostic retry:
17247119Sbostic 	p = parsenextc = parsefile->buf;
173*54313Smarc 	if (parsefile->fd == 0 && el) {
174*54313Smarc 		char *rl_cp;
175*54313Smarc 		int len;
176*54313Smarc 
177*54313Smarc 		rl_cp = el_gets(el, &len);
178*54313Smarc 		if (rl_cp == NULL) {
179*54313Smarc 			i = 0;
180*54313Smarc 			goto eof;
181*54313Smarc 		}
182*54313Smarc 		strcpy(p, rl_cp);  /* XXX - BUFSIZE should redesign so not necessary */
183*54313Smarc 		i = len;
184*54313Smarc 
185*54313Smarc 	} else {
186*54313Smarc regular_read:
187*54313Smarc 		i = read(parsefile->fd, p, BUFSIZ - 1);
188*54313Smarc 	}
189*54313Smarc eof:
19047119Sbostic 	if (i <= 0) {
19147294Smarc                 if (i < 0) {
19247294Smarc                         if (errno == EINTR)
19347294Smarc                                 goto retry;
19447294Smarc                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
19547294Smarc                                 int flags = fcntl(0, F_GETFL, 0);
19650345Sbostic                                 if (flags >= 0 && flags & O_NONBLOCK) {
19750345Sbostic                                         flags &=~ O_NONBLOCK;
19847294Smarc                                         if (fcntl(0, F_SETFL, flags) >= 0) {
19947980Smarc 						out2str("sh: turning off NDELAY mode\n");
20047294Smarc                                                 goto retry;
20147294Smarc                                         }
20247294Smarc                                 }
20347294Smarc                         }
20447294Smarc                 }
20547294Smarc                 parsenleft = EOF_NLEFT;
20647294Smarc                 return PEOF;
20747119Sbostic 	}
208*54313Smarc 	parsenleft = i - 1;	/* we're returning one char in this call */
20947119Sbostic 
21047119Sbostic 	/* delete nul characters */
211*54313Smarc 	something = 0;
21247119Sbostic 	for (;;) {
213*54313Smarc 		if (*p == '\0')
21447119Sbostic 			break;
215*54313Smarc 		if (*p != ' ' && *p != '\t' && *p != '\n')
216*54313Smarc 			something = 1;
217*54313Smarc 		p++;
218*54313Smarc 		if (--i <= 0) {
219*54313Smarc 			*p = '\0';
220*54313Smarc 			goto done;		/* no nul characters */
221*54313Smarc 		}
22247119Sbostic 	}
223*54313Smarc 	/*
224*54313Smarc 	 * remove nuls
225*54313Smarc 	 */
226*54313Smarc 	q = p++;
22747119Sbostic 	while (--i > 0) {
22847119Sbostic 		if (*p != '\0')
22947119Sbostic 			*q++ = *p;
23047119Sbostic 		p++;
23147119Sbostic 	}
232*54313Smarc 	*q = '\0';
23347119Sbostic 	if (q == parsefile->buf)
23447119Sbostic 		goto retry;			/* buffer contained nothing but nuls */
23547119Sbostic 	parsenleft = q - parsefile->buf - 1;
236*54313Smarc 
237*54313Smarc done:
238*54313Smarc 	if (parsefile->fd == 0 && hist && something) {
239*54313Smarc 		INTOFF;
240*54313Smarc 		history(hist, whichprompt == 1 ? H_ENTER : H_ADD,
241*54313Smarc 			   parsefile->buf);
242*54313Smarc 		INTON;
243*54313Smarc 	}
244*54313Smarc 	if (vflag) {
245*54313Smarc 		/*
246*54313Smarc 		 * This isn't right.  Most shells coordinate it with
247*54313Smarc 		 * reading a line at a time.  I honestly don't know if its
248*54313Smarc 		 * worth it.
249*54313Smarc 		 */
250*54313Smarc 		i = parsenleft + 1;
251*54313Smarc 		p = parsefile->buf;
252*54313Smarc 		for (; i--; p++)
253*54313Smarc 			out2c(*p)
254*54313Smarc 		flushout(out2);
255*54313Smarc 	}
25647119Sbostic 	return *parsenextc++;
25747119Sbostic }
25847119Sbostic 
25947119Sbostic /*
26047119Sbostic  * Undo the last call to pgetc.  Only one character may be pushed back.
26147119Sbostic  * PEOF may be pushed back.
26247119Sbostic  */
26347119Sbostic 
26447119Sbostic void
26547119Sbostic pungetc() {
26647119Sbostic 	parsenleft++;
26747119Sbostic 	parsenextc--;
26847119Sbostic }
26947119Sbostic 
27047119Sbostic /*
271*54313Smarc  * Push a string back onto the input at this current parsefile level.
272*54313Smarc  * We handle aliases this way.
27347119Sbostic  */
27447119Sbostic void
275*54313Smarc pushstring(s, len, ap)
276*54313Smarc 	char *s;
277*54313Smarc 	int len;
278*54313Smarc 	void *ap;
27947119Sbostic 	{
280*54313Smarc 	struct strpush *sp;
281*54313Smarc 
282*54313Smarc 	INTOFF;
283*54313Smarc /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
284*54313Smarc 	if (parsefile->strpush) {
285*54313Smarc 		sp = ckmalloc(sizeof (struct strpush));
286*54313Smarc 		sp->prev = parsefile->strpush;
287*54313Smarc 		parsefile->strpush = sp;
288*54313Smarc 	} else
289*54313Smarc 		sp = parsefile->strpush = &(parsefile->basestrpush);
290*54313Smarc 	sp->prevstring = parsenextc;
291*54313Smarc 	sp->prevnleft = parsenleft;
292*54313Smarc 	sp->ap = (struct alias *)ap;
293*54313Smarc 	if (ap)
294*54313Smarc 		((struct alias *)ap)->flag |= ALIASINUSE;
295*54313Smarc 	parsenextc = s;
296*54313Smarc 	parsenleft = len;
297*54313Smarc 	INTON;
29847119Sbostic }
29947119Sbostic 
300*54313Smarc popstring()
301*54313Smarc {
302*54313Smarc 	struct strpush *sp = parsefile->strpush;
30347119Sbostic 
304*54313Smarc 	INTOFF;
305*54313Smarc 	parsenextc = sp->prevstring;
306*54313Smarc 	parsenleft = sp->prevnleft;
307*54313Smarc /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
308*54313Smarc 	if (sp->ap)
309*54313Smarc 		sp->ap->flag &= ~ALIASINUSE;
310*54313Smarc 	parsefile->strpush = sp->prev;
311*54313Smarc 	if (sp != &(parsefile->basestrpush))
312*54313Smarc 		ckfree(sp);
313*54313Smarc 	INTON;
314*54313Smarc }
31547119Sbostic 
31647119Sbostic /*
31747119Sbostic  * Set the input to take input from a file.  If push is set, push the
31847119Sbostic  * old input onto the stack first.
31947119Sbostic  */
32047119Sbostic 
32147119Sbostic void
32247119Sbostic setinputfile(fname, push)
32347119Sbostic 	char *fname;
32447119Sbostic 	{
32547119Sbostic 	int fd;
32647119Sbostic 	int fd2;
32747119Sbostic 
32847119Sbostic 	INTOFF;
32947119Sbostic 	if ((fd = open(fname, O_RDONLY)) < 0)
33047119Sbostic 		error("Can't open %s", fname);
33147119Sbostic 	if (fd < 10) {
33247119Sbostic 		fd2 = copyfd(fd, 10);
33347119Sbostic 		close(fd);
33447119Sbostic 		if (fd2 < 0)
33547119Sbostic 			error("Out of file descriptors");
33647119Sbostic 		fd = fd2;
33747119Sbostic 	}
33847119Sbostic 	setinputfd(fd, push);
33947119Sbostic 	INTON;
34047119Sbostic }
34147119Sbostic 
34247119Sbostic 
34347119Sbostic /*
34447119Sbostic  * Like setinputfile, but takes an open file descriptor.  Call this with
34547119Sbostic  * interrupts off.
34647119Sbostic  */
34747119Sbostic 
34847119Sbostic void
34947119Sbostic setinputfd(fd, push) {
35047119Sbostic 	if (push) {
35147119Sbostic 		pushfile();
35247119Sbostic 		parsefile->buf = ckmalloc(BUFSIZ);
35347119Sbostic 	}
35447119Sbostic 	if (parsefile->fd > 0)
35547119Sbostic 		close(parsefile->fd);
35647119Sbostic 	parsefile->fd = fd;
35747119Sbostic 	if (parsefile->buf == NULL)
35847119Sbostic 		parsefile->buf = ckmalloc(BUFSIZ);
35947119Sbostic 	parsenleft = 0;
36047119Sbostic 	plinno = 1;
36147119Sbostic }
36247119Sbostic 
36347119Sbostic 
36447119Sbostic /*
36547119Sbostic  * Like setinputfile, but takes input from a string.
36647119Sbostic  */
36747119Sbostic 
36847119Sbostic void
36947119Sbostic setinputstring(string, push)
37047119Sbostic 	char *string;
37147119Sbostic 	{
37247119Sbostic 	INTOFF;
37347119Sbostic 	if (push)
37447119Sbostic 		pushfile();
37547119Sbostic 	parsenextc = string;
37647119Sbostic 	parsenleft = strlen(string);
37747119Sbostic 	parsefile->buf = NULL;
37847119Sbostic 	plinno = 1;
37947119Sbostic 	INTON;
38047119Sbostic }
38147119Sbostic 
38247119Sbostic 
38347119Sbostic 
38447119Sbostic /*
38547119Sbostic  * To handle the "." command, a stack of input files is used.  Pushfile
38647119Sbostic  * adds a new entry to the stack and popfile restores the previous level.
38747119Sbostic  */
38847119Sbostic 
38947119Sbostic STATIC void
39047119Sbostic pushfile() {
39147119Sbostic 	struct parsefile *pf;
39247119Sbostic 
39347119Sbostic 	parsefile->nleft = parsenleft;
39447119Sbostic 	parsefile->nextc = parsenextc;
39547119Sbostic 	parsefile->linno = plinno;
39647119Sbostic 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
39747119Sbostic 	pf->prev = parsefile;
39847119Sbostic 	pf->fd = -1;
399*54313Smarc 	pf->strpush = NULL;
400*54313Smarc 	pf->basestrpush.prev = NULL;
40147119Sbostic 	parsefile = pf;
40247119Sbostic }
40347119Sbostic 
40447119Sbostic 
40547119Sbostic void
40647119Sbostic popfile() {
40747119Sbostic 	struct parsefile *pf = parsefile;
40847119Sbostic 
40947119Sbostic 	INTOFF;
41047119Sbostic 	if (pf->fd >= 0)
41147119Sbostic 		close(pf->fd);
41247119Sbostic 	if (pf->buf)
41347119Sbostic 		ckfree(pf->buf);
414*54313Smarc 	while (pf->strpush)
415*54313Smarc 		popstring();
41647119Sbostic 	parsefile = pf->prev;
41747119Sbostic 	ckfree(pf);
41847119Sbostic 	parsenleft = parsefile->nleft;
41947119Sbostic 	parsenextc = parsefile->nextc;
42047119Sbostic 	plinno = parsefile->linno;
42147119Sbostic 	INTON;
42247119Sbostic }
42347119Sbostic 
42447119Sbostic 
42547119Sbostic /*
42647119Sbostic  * Return to top level.
42747119Sbostic  */
42847119Sbostic 
42947119Sbostic void
43047119Sbostic popallfiles() {
43147119Sbostic 	while (parsefile != &basepf)
43247119Sbostic 		popfile();
43347119Sbostic }
43447119Sbostic 
43547119Sbostic 
43647119Sbostic 
43747119Sbostic /*
43847119Sbostic  * Close the file(s) that the shell is reading commands from.  Called
43947119Sbostic  * after a fork is done.
44047119Sbostic  */
44147119Sbostic 
44247119Sbostic void
44347119Sbostic closescript() {
44447119Sbostic 	popallfiles();
44547119Sbostic 	if (parsefile->fd > 0) {
44647119Sbostic 		close(parsefile->fd);
44747119Sbostic 		parsefile->fd = 0;
44847119Sbostic 	}
44947119Sbostic }
450