xref: /csrg-svn/bin/sh/input.c (revision 50345)
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*50345Sbostic static char sccsid[] = "@(#)input.c	5.4 (Berkeley) 07/01/91";
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"
2647119Sbostic #include "memalloc.h"
2747119Sbostic #include "error.h"
2847119Sbostic 
2947119Sbostic #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
3047119Sbostic 
3147119Sbostic 
3247119Sbostic /*
3347119Sbostic  * The parsefile structure pointed to by the global variable parsefile
3447119Sbostic  * contains information about the current file being read.
3547119Sbostic  */
3647119Sbostic 
3747119Sbostic MKINIT
3847119Sbostic struct parsefile {
3947119Sbostic 	int linno;		/* current line */
4047119Sbostic 	int fd;			/* file descriptor (or -1 if string) */
4147119Sbostic 	int nleft;		/* number of chars left in buffer */
4247119Sbostic 	char *nextc;		/* next char in buffer */
4347119Sbostic 	struct parsefile *prev;	/* preceding file on stack */
4447119Sbostic 	char *buf;		/* input buffer */
4547119Sbostic };
4647119Sbostic 
4747119Sbostic 
4847119Sbostic int plinno = 1;			/* input line number */
4947119Sbostic MKINIT int parsenleft;		/* copy of parsefile->nleft */
5047119Sbostic char *parsenextc;		/* copy of parsefile->nextc */
5147119Sbostic MKINIT struct parsefile basepf;	/* top level input file */
5247119Sbostic char basebuf[BUFSIZ];		/* buffer for top level input file */
5347119Sbostic struct parsefile *parsefile = &basepf;	/* current input file */
5447119Sbostic char *pushedstring;		/* copy of parsenextc when text pushed back */
5547119Sbostic int pushednleft;		/* copy of parsenleft when text pushed back */
5647119Sbostic 
5747119Sbostic #ifdef __STDC__
5847119Sbostic STATIC void pushfile(void);
5947119Sbostic #else
6047119Sbostic STATIC void pushfile();
6147119Sbostic #endif
6247119Sbostic 
6347119Sbostic 
6447119Sbostic 
6547119Sbostic #ifdef mkinit
6647119Sbostic INCLUDE "input.h"
6747119Sbostic INCLUDE "error.h"
6847119Sbostic 
6947119Sbostic INIT {
7047119Sbostic 	extern char basebuf[];
7147119Sbostic 
7247119Sbostic 	basepf.nextc = basepf.buf = basebuf;
7347119Sbostic }
7447119Sbostic 
7547119Sbostic RESET {
7647119Sbostic 	if (exception != EXSHELLPROC)
7747119Sbostic 		parsenleft = 0;            /* clear input buffer */
7847119Sbostic 	popallfiles();
7947119Sbostic }
8047119Sbostic 
8147119Sbostic SHELLPROC {
8247119Sbostic 	popallfiles();
8347119Sbostic }
8447119Sbostic #endif
8547119Sbostic 
8647119Sbostic 
8747119Sbostic /*
8847119Sbostic  * Read a line from the script.
8947119Sbostic  */
9047119Sbostic 
9147119Sbostic char *
9247119Sbostic pfgets(line, len)
9347119Sbostic 	char *line;
9447119Sbostic 	{
9547119Sbostic 	register char *p = line;
9647119Sbostic 	int nleft = len;
9747119Sbostic 	int c;
9847119Sbostic 
9947119Sbostic 	while (--nleft > 0) {
10047119Sbostic 		c = pgetc_macro();
10147119Sbostic 		if (c == PEOF) {
10247119Sbostic 			if (p == line)
10347119Sbostic 				return NULL;
10447119Sbostic 			break;
10547119Sbostic 		}
10647119Sbostic 		*p++ = c;
10747119Sbostic 		if (c == '\n')
10847119Sbostic 			break;
10947119Sbostic 	}
11047119Sbostic 	*p = '\0';
11147119Sbostic 	return line;
11247119Sbostic }
11347119Sbostic 
11447119Sbostic 
11547119Sbostic 
11647119Sbostic /*
11747119Sbostic  * Read a character from the script, returning PEOF on end of file.
11847119Sbostic  * Nul characters in the input are silently discarded.
11947119Sbostic  */
12047119Sbostic 
12147119Sbostic int
12247119Sbostic pgetc() {
12347119Sbostic 	return pgetc_macro();
12447119Sbostic }
12547119Sbostic 
12647119Sbostic 
12747119Sbostic /*
12847119Sbostic  * Refill the input buffer and return the next input character:
12947119Sbostic  *
13047119Sbostic  * 1) If a string was pushed back on the input, switch back to the regular
13147119Sbostic  *    buffer.
13247119Sbostic  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
13347119Sbostic  *    from a string so we can't refill the buffer, return EOF.
13447119Sbostic  * 3) Call read to read in the characters.
13547119Sbostic  * 4) Delete all nul characters from the buffer.
13647119Sbostic  */
13747119Sbostic 
13847119Sbostic int
13947119Sbostic preadbuffer() {
14047119Sbostic 	register char *p, *q;
14147119Sbostic 	register int i;
14247119Sbostic 
14347119Sbostic 	if (pushedstring) {
14447119Sbostic 		parsenextc = pushedstring;
14547119Sbostic 		pushedstring = NULL;
14647119Sbostic 		parsenleft = pushednleft;
14747119Sbostic 		if (--parsenleft >= 0)
14847119Sbostic 			return *parsenextc++;
14947119Sbostic 	}
15047119Sbostic 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
15147119Sbostic 		return PEOF;
15247119Sbostic 	flushout(&output);
15347119Sbostic 	flushout(&errout);
15447119Sbostic retry:
15547119Sbostic 	p = parsenextc = parsefile->buf;
15647119Sbostic 	i = read(parsefile->fd, p, BUFSIZ);
15747119Sbostic 	if (i <= 0) {
15847294Smarc                 if (i < 0) {
15947294Smarc                         if (errno == EINTR)
16047294Smarc                                 goto retry;
16147294Smarc                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
16247294Smarc                                 int flags = fcntl(0, F_GETFL, 0);
163*50345Sbostic                                 if (flags >= 0 && flags & O_NONBLOCK) {
164*50345Sbostic                                         flags &=~ O_NONBLOCK;
16547294Smarc                                         if (fcntl(0, F_SETFL, flags) >= 0) {
16647980Smarc 						out2str("sh: turning off NDELAY mode\n");
16747294Smarc                                                 goto retry;
16847294Smarc                                         }
16947294Smarc                                 }
17047294Smarc                         }
17147294Smarc                 }
17247294Smarc                 parsenleft = EOF_NLEFT;
17347294Smarc                 return PEOF;
17447119Sbostic 	}
17547119Sbostic 	parsenleft = i - 1;
17647119Sbostic 
17747119Sbostic 	/* delete nul characters */
17847119Sbostic 	for (;;) {
17947119Sbostic 		if (*p++ == '\0')
18047119Sbostic 			break;
18147119Sbostic 		if (--i <= 0)
18247119Sbostic 			return *parsenextc++;		/* no nul characters */
18347119Sbostic 	}
18447119Sbostic 	q = p - 1;
18547119Sbostic 	while (--i > 0) {
18647119Sbostic 		if (*p != '\0')
18747119Sbostic 			*q++ = *p;
18847119Sbostic 		p++;
18947119Sbostic 	}
19047119Sbostic 	if (q == parsefile->buf)
19147119Sbostic 		goto retry;			/* buffer contained nothing but nuls */
19247119Sbostic 	parsenleft = q - parsefile->buf - 1;
19347119Sbostic 	return *parsenextc++;
19447119Sbostic }
19547119Sbostic 
19647119Sbostic 
19747119Sbostic /*
19847119Sbostic  * Undo the last call to pgetc.  Only one character may be pushed back.
19947119Sbostic  * PEOF may be pushed back.
20047119Sbostic  */
20147119Sbostic 
20247119Sbostic void
20347119Sbostic pungetc() {
20447119Sbostic 	parsenleft++;
20547119Sbostic 	parsenextc--;
20647119Sbostic }
20747119Sbostic 
20847119Sbostic 
20947119Sbostic /*
21047119Sbostic  * Push a string back onto the input.  This code doesn't work if the user
21147119Sbostic  * tries to push back more than one string at once.
21247119Sbostic  */
21347119Sbostic 
21447119Sbostic void
21547119Sbostic ppushback(string, length)
21647119Sbostic 	char *string;
21747119Sbostic 	{
21847119Sbostic 	pushedstring = parsenextc;
21947119Sbostic 	pushednleft = parsenleft;
22047119Sbostic 	parsenextc = string;
22147119Sbostic 	parsenleft = length;
22247119Sbostic }
22347119Sbostic 
22447119Sbostic 
22547119Sbostic 
22647119Sbostic /*
22747119Sbostic  * Set the input to take input from a file.  If push is set, push the
22847119Sbostic  * old input onto the stack first.
22947119Sbostic  */
23047119Sbostic 
23147119Sbostic void
23247119Sbostic setinputfile(fname, push)
23347119Sbostic 	char *fname;
23447119Sbostic 	{
23547119Sbostic 	int fd;
23647119Sbostic 	int fd2;
23747119Sbostic 
23847119Sbostic 	INTOFF;
23947119Sbostic 	if ((fd = open(fname, O_RDONLY)) < 0)
24047119Sbostic 		error("Can't open %s", fname);
24147119Sbostic 	if (fd < 10) {
24247119Sbostic 		fd2 = copyfd(fd, 10);
24347119Sbostic 		close(fd);
24447119Sbostic 		if (fd2 < 0)
24547119Sbostic 			error("Out of file descriptors");
24647119Sbostic 		fd = fd2;
24747119Sbostic 	}
24847119Sbostic 	setinputfd(fd, push);
24947119Sbostic 	INTON;
25047119Sbostic }
25147119Sbostic 
25247119Sbostic 
25347119Sbostic /*
25447119Sbostic  * Like setinputfile, but takes an open file descriptor.  Call this with
25547119Sbostic  * interrupts off.
25647119Sbostic  */
25747119Sbostic 
25847119Sbostic void
25947119Sbostic setinputfd(fd, push) {
26047119Sbostic 	if (push) {
26147119Sbostic 		pushfile();
26247119Sbostic 		parsefile->buf = ckmalloc(BUFSIZ);
26347119Sbostic 	}
26447119Sbostic 	if (parsefile->fd > 0)
26547119Sbostic 		close(parsefile->fd);
26647119Sbostic 	parsefile->fd = fd;
26747119Sbostic 	if (parsefile->buf == NULL)
26847119Sbostic 		parsefile->buf = ckmalloc(BUFSIZ);
26947119Sbostic 	parsenleft = 0;
27047119Sbostic 	plinno = 1;
27147119Sbostic }
27247119Sbostic 
27347119Sbostic 
27447119Sbostic /*
27547119Sbostic  * Like setinputfile, but takes input from a string.
27647119Sbostic  */
27747119Sbostic 
27847119Sbostic void
27947119Sbostic setinputstring(string, push)
28047119Sbostic 	char *string;
28147119Sbostic 	{
28247119Sbostic 	INTOFF;
28347119Sbostic 	if (push)
28447119Sbostic 		pushfile();
28547119Sbostic 	parsenextc = string;
28647119Sbostic 	parsenleft = strlen(string);
28747119Sbostic 	parsefile->buf = NULL;
28847119Sbostic 	plinno = 1;
28947119Sbostic 	INTON;
29047119Sbostic }
29147119Sbostic 
29247119Sbostic 
29347119Sbostic 
29447119Sbostic /*
29547119Sbostic  * To handle the "." command, a stack of input files is used.  Pushfile
29647119Sbostic  * adds a new entry to the stack and popfile restores the previous level.
29747119Sbostic  */
29847119Sbostic 
29947119Sbostic STATIC void
30047119Sbostic pushfile() {
30147119Sbostic 	struct parsefile *pf;
30247119Sbostic 
30347119Sbostic 	parsefile->nleft = parsenleft;
30447119Sbostic 	parsefile->nextc = parsenextc;
30547119Sbostic 	parsefile->linno = plinno;
30647119Sbostic 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
30747119Sbostic 	pf->prev = parsefile;
30847119Sbostic 	pf->fd = -1;
30947119Sbostic 	parsefile = pf;
31047119Sbostic }
31147119Sbostic 
31247119Sbostic 
31347119Sbostic void
31447119Sbostic popfile() {
31547119Sbostic 	struct parsefile *pf = parsefile;
31647119Sbostic 
31747119Sbostic 	INTOFF;
31847119Sbostic 	if (pf->fd >= 0)
31947119Sbostic 		close(pf->fd);
32047119Sbostic 	if (pf->buf)
32147119Sbostic 		ckfree(pf->buf);
32247119Sbostic 	parsefile = pf->prev;
32347119Sbostic 	ckfree(pf);
32447119Sbostic 	parsenleft = parsefile->nleft;
32547119Sbostic 	parsenextc = parsefile->nextc;
32647119Sbostic 	plinno = parsefile->linno;
32747119Sbostic 	INTON;
32847119Sbostic }
32947119Sbostic 
33047119Sbostic 
33147119Sbostic /*
33247119Sbostic  * Return to top level.
33347119Sbostic  */
33447119Sbostic 
33547119Sbostic void
33647119Sbostic popallfiles() {
33747119Sbostic 	while (parsefile != &basepf)
33847119Sbostic 		popfile();
33947119Sbostic }
34047119Sbostic 
34147119Sbostic 
34247119Sbostic 
34347119Sbostic /*
34447119Sbostic  * Close the file(s) that the shell is reading commands from.  Called
34547119Sbostic  * after a fork is done.
34647119Sbostic  */
34747119Sbostic 
34847119Sbostic void
34947119Sbostic closescript() {
35047119Sbostic 	popallfiles();
35147119Sbostic 	if (parsefile->fd > 0) {
35247119Sbostic 		close(parsefile->fd);
35347119Sbostic 		parsefile->fd = 0;
35447119Sbostic 	}
35547119Sbostic }
356