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