xref: /csrg-svn/bin/sh/input.c (revision 47119)
1*47119Sbostic /*-
2*47119Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*47119Sbostic  * All rights reserved.
4*47119Sbostic  *
5*47119Sbostic  * This code is derived from software contributed to Berkeley by
6*47119Sbostic  * Kenneth Almquist.
7*47119Sbostic  *
8*47119Sbostic  * %sccs.include.redist.c%
9*47119Sbostic  */
10*47119Sbostic 
11*47119Sbostic #ifndef lint
12*47119Sbostic static char sccsid[] = "@(#)input.c	5.1 (Berkeley) 03/07/91";
13*47119Sbostic #endif /* not lint */
14*47119Sbostic 
15*47119Sbostic /*
16*47119Sbostic  * This file implements the input routines used by the parser.
17*47119Sbostic  */
18*47119Sbostic 
19*47119Sbostic #include <stdio.h>	/* defines BUFSIZ */
20*47119Sbostic #include "shell.h"
21*47119Sbostic #include <fcntl.h>
22*47119Sbostic #include <errno.h>
23*47119Sbostic #include "syntax.h"
24*47119Sbostic #include "input.h"
25*47119Sbostic #include "output.h"
26*47119Sbostic #include "memalloc.h"
27*47119Sbostic #include "error.h"
28*47119Sbostic 
29*47119Sbostic #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
30*47119Sbostic 
31*47119Sbostic 
32*47119Sbostic /*
33*47119Sbostic  * The parsefile structure pointed to by the global variable parsefile
34*47119Sbostic  * contains information about the current file being read.
35*47119Sbostic  */
36*47119Sbostic 
37*47119Sbostic MKINIT
38*47119Sbostic struct parsefile {
39*47119Sbostic 	int linno;		/* current line */
40*47119Sbostic 	int fd;			/* file descriptor (or -1 if string) */
41*47119Sbostic 	int nleft;		/* number of chars left in buffer */
42*47119Sbostic 	char *nextc;		/* next char in buffer */
43*47119Sbostic 	struct parsefile *prev;	/* preceding file on stack */
44*47119Sbostic 	char *buf;		/* input buffer */
45*47119Sbostic };
46*47119Sbostic 
47*47119Sbostic 
48*47119Sbostic int plinno = 1;			/* input line number */
49*47119Sbostic MKINIT int parsenleft;		/* copy of parsefile->nleft */
50*47119Sbostic char *parsenextc;		/* copy of parsefile->nextc */
51*47119Sbostic MKINIT struct parsefile basepf;	/* top level input file */
52*47119Sbostic char basebuf[BUFSIZ];		/* buffer for top level input file */
53*47119Sbostic struct parsefile *parsefile = &basepf;	/* current input file */
54*47119Sbostic char *pushedstring;		/* copy of parsenextc when text pushed back */
55*47119Sbostic int pushednleft;		/* copy of parsenleft when text pushed back */
56*47119Sbostic 
57*47119Sbostic #ifdef __STDC__
58*47119Sbostic STATIC void pushfile(void);
59*47119Sbostic #else
60*47119Sbostic STATIC void pushfile();
61*47119Sbostic #endif
62*47119Sbostic 
63*47119Sbostic 
64*47119Sbostic 
65*47119Sbostic #ifdef mkinit
66*47119Sbostic INCLUDE "input.h"
67*47119Sbostic INCLUDE "error.h"
68*47119Sbostic 
69*47119Sbostic INIT {
70*47119Sbostic 	extern char basebuf[];
71*47119Sbostic 
72*47119Sbostic 	basepf.nextc = basepf.buf = basebuf;
73*47119Sbostic }
74*47119Sbostic 
75*47119Sbostic RESET {
76*47119Sbostic 	if (exception != EXSHELLPROC)
77*47119Sbostic 		parsenleft = 0;            /* clear input buffer */
78*47119Sbostic 	popallfiles();
79*47119Sbostic }
80*47119Sbostic 
81*47119Sbostic SHELLPROC {
82*47119Sbostic 	popallfiles();
83*47119Sbostic }
84*47119Sbostic #endif
85*47119Sbostic 
86*47119Sbostic 
87*47119Sbostic /*
88*47119Sbostic  * Read a line from the script.
89*47119Sbostic  */
90*47119Sbostic 
91*47119Sbostic char *
92*47119Sbostic pfgets(line, len)
93*47119Sbostic 	char *line;
94*47119Sbostic 	{
95*47119Sbostic 	register char *p = line;
96*47119Sbostic 	int nleft = len;
97*47119Sbostic 	int c;
98*47119Sbostic 
99*47119Sbostic 	while (--nleft > 0) {
100*47119Sbostic 		c = pgetc_macro();
101*47119Sbostic 		if (c == PEOF) {
102*47119Sbostic 			if (p == line)
103*47119Sbostic 				return NULL;
104*47119Sbostic 			break;
105*47119Sbostic 		}
106*47119Sbostic 		*p++ = c;
107*47119Sbostic 		if (c == '\n')
108*47119Sbostic 			break;
109*47119Sbostic 	}
110*47119Sbostic 	*p = '\0';
111*47119Sbostic 	return line;
112*47119Sbostic }
113*47119Sbostic 
114*47119Sbostic 
115*47119Sbostic 
116*47119Sbostic /*
117*47119Sbostic  * Read a character from the script, returning PEOF on end of file.
118*47119Sbostic  * Nul characters in the input are silently discarded.
119*47119Sbostic  */
120*47119Sbostic 
121*47119Sbostic int
122*47119Sbostic pgetc() {
123*47119Sbostic 	return pgetc_macro();
124*47119Sbostic }
125*47119Sbostic 
126*47119Sbostic 
127*47119Sbostic /*
128*47119Sbostic  * Refill the input buffer and return the next input character:
129*47119Sbostic  *
130*47119Sbostic  * 1) If a string was pushed back on the input, switch back to the regular
131*47119Sbostic  *    buffer.
132*47119Sbostic  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
133*47119Sbostic  *    from a string so we can't refill the buffer, return EOF.
134*47119Sbostic  * 3) Call read to read in the characters.
135*47119Sbostic  * 4) Delete all nul characters from the buffer.
136*47119Sbostic  */
137*47119Sbostic 
138*47119Sbostic int
139*47119Sbostic preadbuffer() {
140*47119Sbostic 	register char *p, *q;
141*47119Sbostic 	register int i;
142*47119Sbostic 
143*47119Sbostic 	if (pushedstring) {
144*47119Sbostic 		parsenextc = pushedstring;
145*47119Sbostic 		pushedstring = NULL;
146*47119Sbostic 		parsenleft = pushednleft;
147*47119Sbostic 		if (--parsenleft >= 0)
148*47119Sbostic 			return *parsenextc++;
149*47119Sbostic 	}
150*47119Sbostic 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
151*47119Sbostic 		return PEOF;
152*47119Sbostic 	flushout(&output);
153*47119Sbostic 	flushout(&errout);
154*47119Sbostic retry:
155*47119Sbostic 	p = parsenextc = parsefile->buf;
156*47119Sbostic 	i = read(parsefile->fd, p, BUFSIZ);
157*47119Sbostic 	if (i <= 0) {
158*47119Sbostic 		if (i < 0 && errno == EINTR)
159*47119Sbostic 			goto retry;
160*47119Sbostic 		parsenleft = EOF_NLEFT;
161*47119Sbostic 		return PEOF;
162*47119Sbostic 	}
163*47119Sbostic 	parsenleft = i - 1;
164*47119Sbostic 
165*47119Sbostic 	/* delete nul characters */
166*47119Sbostic 	for (;;) {
167*47119Sbostic 		if (*p++ == '\0')
168*47119Sbostic 			break;
169*47119Sbostic 		if (--i <= 0)
170*47119Sbostic 			return *parsenextc++;		/* no nul characters */
171*47119Sbostic 	}
172*47119Sbostic 	q = p - 1;
173*47119Sbostic 	while (--i > 0) {
174*47119Sbostic 		if (*p != '\0')
175*47119Sbostic 			*q++ = *p;
176*47119Sbostic 		p++;
177*47119Sbostic 	}
178*47119Sbostic 	if (q == parsefile->buf)
179*47119Sbostic 		goto retry;			/* buffer contained nothing but nuls */
180*47119Sbostic 	parsenleft = q - parsefile->buf - 1;
181*47119Sbostic 	return *parsenextc++;
182*47119Sbostic }
183*47119Sbostic 
184*47119Sbostic 
185*47119Sbostic /*
186*47119Sbostic  * Undo the last call to pgetc.  Only one character may be pushed back.
187*47119Sbostic  * PEOF may be pushed back.
188*47119Sbostic  */
189*47119Sbostic 
190*47119Sbostic void
191*47119Sbostic pungetc() {
192*47119Sbostic 	parsenleft++;
193*47119Sbostic 	parsenextc--;
194*47119Sbostic }
195*47119Sbostic 
196*47119Sbostic 
197*47119Sbostic /*
198*47119Sbostic  * Push a string back onto the input.  This code doesn't work if the user
199*47119Sbostic  * tries to push back more than one string at once.
200*47119Sbostic  */
201*47119Sbostic 
202*47119Sbostic void
203*47119Sbostic ppushback(string, length)
204*47119Sbostic 	char *string;
205*47119Sbostic 	{
206*47119Sbostic 	pushedstring = parsenextc;
207*47119Sbostic 	pushednleft = parsenleft;
208*47119Sbostic 	parsenextc = string;
209*47119Sbostic 	parsenleft = length;
210*47119Sbostic }
211*47119Sbostic 
212*47119Sbostic 
213*47119Sbostic 
214*47119Sbostic /*
215*47119Sbostic  * Set the input to take input from a file.  If push is set, push the
216*47119Sbostic  * old input onto the stack first.
217*47119Sbostic  */
218*47119Sbostic 
219*47119Sbostic void
220*47119Sbostic setinputfile(fname, push)
221*47119Sbostic 	char *fname;
222*47119Sbostic 	{
223*47119Sbostic 	int fd;
224*47119Sbostic 	int fd2;
225*47119Sbostic 
226*47119Sbostic 	INTOFF;
227*47119Sbostic 	if ((fd = open(fname, O_RDONLY)) < 0)
228*47119Sbostic 		error("Can't open %s", fname);
229*47119Sbostic 	if (fd < 10) {
230*47119Sbostic 		fd2 = copyfd(fd, 10);
231*47119Sbostic 		close(fd);
232*47119Sbostic 		if (fd2 < 0)
233*47119Sbostic 			error("Out of file descriptors");
234*47119Sbostic 		fd = fd2;
235*47119Sbostic 	}
236*47119Sbostic 	setinputfd(fd, push);
237*47119Sbostic 	INTON;
238*47119Sbostic }
239*47119Sbostic 
240*47119Sbostic 
241*47119Sbostic /*
242*47119Sbostic  * Like setinputfile, but takes an open file descriptor.  Call this with
243*47119Sbostic  * interrupts off.
244*47119Sbostic  */
245*47119Sbostic 
246*47119Sbostic void
247*47119Sbostic setinputfd(fd, push) {
248*47119Sbostic 	if (push) {
249*47119Sbostic 		pushfile();
250*47119Sbostic 		parsefile->buf = ckmalloc(BUFSIZ);
251*47119Sbostic 	}
252*47119Sbostic 	if (parsefile->fd > 0)
253*47119Sbostic 		close(parsefile->fd);
254*47119Sbostic 	parsefile->fd = fd;
255*47119Sbostic 	if (parsefile->buf == NULL)
256*47119Sbostic 		parsefile->buf = ckmalloc(BUFSIZ);
257*47119Sbostic 	parsenleft = 0;
258*47119Sbostic 	plinno = 1;
259*47119Sbostic }
260*47119Sbostic 
261*47119Sbostic 
262*47119Sbostic /*
263*47119Sbostic  * Like setinputfile, but takes input from a string.
264*47119Sbostic  */
265*47119Sbostic 
266*47119Sbostic void
267*47119Sbostic setinputstring(string, push)
268*47119Sbostic 	char *string;
269*47119Sbostic 	{
270*47119Sbostic 	INTOFF;
271*47119Sbostic 	if (push)
272*47119Sbostic 		pushfile();
273*47119Sbostic 	parsenextc = string;
274*47119Sbostic 	parsenleft = strlen(string);
275*47119Sbostic 	parsefile->buf = NULL;
276*47119Sbostic 	plinno = 1;
277*47119Sbostic 	INTON;
278*47119Sbostic }
279*47119Sbostic 
280*47119Sbostic 
281*47119Sbostic 
282*47119Sbostic /*
283*47119Sbostic  * To handle the "." command, a stack of input files is used.  Pushfile
284*47119Sbostic  * adds a new entry to the stack and popfile restores the previous level.
285*47119Sbostic  */
286*47119Sbostic 
287*47119Sbostic STATIC void
288*47119Sbostic pushfile() {
289*47119Sbostic 	struct parsefile *pf;
290*47119Sbostic 
291*47119Sbostic 	parsefile->nleft = parsenleft;
292*47119Sbostic 	parsefile->nextc = parsenextc;
293*47119Sbostic 	parsefile->linno = plinno;
294*47119Sbostic 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
295*47119Sbostic 	pf->prev = parsefile;
296*47119Sbostic 	pf->fd = -1;
297*47119Sbostic 	parsefile = pf;
298*47119Sbostic }
299*47119Sbostic 
300*47119Sbostic 
301*47119Sbostic void
302*47119Sbostic popfile() {
303*47119Sbostic 	struct parsefile *pf = parsefile;
304*47119Sbostic 
305*47119Sbostic 	INTOFF;
306*47119Sbostic 	if (pf->fd >= 0)
307*47119Sbostic 		close(pf->fd);
308*47119Sbostic 	if (pf->buf)
309*47119Sbostic 		ckfree(pf->buf);
310*47119Sbostic 	parsefile = pf->prev;
311*47119Sbostic 	ckfree(pf);
312*47119Sbostic 	parsenleft = parsefile->nleft;
313*47119Sbostic 	parsenextc = parsefile->nextc;
314*47119Sbostic 	plinno = parsefile->linno;
315*47119Sbostic 	INTON;
316*47119Sbostic }
317*47119Sbostic 
318*47119Sbostic 
319*47119Sbostic /*
320*47119Sbostic  * Return to top level.
321*47119Sbostic  */
322*47119Sbostic 
323*47119Sbostic void
324*47119Sbostic popallfiles() {
325*47119Sbostic 	while (parsefile != &basepf)
326*47119Sbostic 		popfile();
327*47119Sbostic }
328*47119Sbostic 
329*47119Sbostic 
330*47119Sbostic 
331*47119Sbostic /*
332*47119Sbostic  * Close the file(s) that the shell is reading commands from.  Called
333*47119Sbostic  * after a fork is done.
334*47119Sbostic  */
335*47119Sbostic 
336*47119Sbostic void
337*47119Sbostic closescript() {
338*47119Sbostic 	popallfiles();
339*47119Sbostic 	if (parsefile->fd > 0) {
340*47119Sbostic 		close(parsefile->fd);
341*47119Sbostic 		parsefile->fd = 0;
342*47119Sbostic 	}
343*47119Sbostic }
344