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