input.c revision 250267
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 250267 2013-05-05 10:51:40Z 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 */
95MKINIT 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
111#ifdef mkinit
112INCLUDE "input.h"
113INCLUDE "error.h"
114
115RESET {
116	popallfiles();
117	parselleft = parsenleft = 0;	/* clear input buffer */
118}
119#endif
120
121
122/*
123 * Read a line from the script.
124 */
125
126char *
127pfgets(char *line, int len)
128{
129	char *p = line;
130	int nleft = len;
131	int c;
132
133	while (--nleft > 0) {
134		c = pgetc_macro();
135		if (c == PEOF) {
136			if (p == line)
137				return NULL;
138			break;
139		}
140		*p++ = c;
141		if (c == '\n')
142			break;
143	}
144	*p = '\0';
145	return line;
146}
147
148
149
150/*
151 * Read a character from the script, returning PEOF on end of file.
152 * Nul characters in the input are silently discarded.
153 */
154
155int
156pgetc(void)
157{
158	return pgetc_macro();
159}
160
161
162static int
163preadfd(void)
164{
165	int nr;
166	parsenextc = parsefile->buf;
167
168#ifndef NO_HISTORY
169	if (el != NULL && gotwinch) {
170		gotwinch = 0;
171		el_resize(el);
172	}
173#endif
174retry:
175#ifndef NO_HISTORY
176	if (parsefile->fd == 0 && el) {
177		static const char *rl_cp;
178		static int el_len;
179
180		if (rl_cp == NULL)
181			rl_cp = el_gets(el, &el_len);
182		if (rl_cp == NULL)
183			nr = el_len == 0 ? 0 : -1;
184		else {
185			nr = el_len;
186			if (nr > BUFSIZ)
187				nr = BUFSIZ;
188			memcpy(parsefile->buf, rl_cp, nr);
189			if (nr != el_len) {
190				el_len -= nr;
191				rl_cp += nr;
192			} else
193				rl_cp = NULL;
194		}
195	} else
196#endif
197		nr = read(parsefile->fd, parsefile->buf, BUFSIZ);
198
199	if (nr <= 0) {
200                if (nr < 0) {
201                        if (errno == EINTR)
202                                goto retry;
203                        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
204                                int flags = fcntl(0, F_GETFL, 0);
205                                if (flags >= 0 && flags & O_NONBLOCK) {
206                                        flags &=~ O_NONBLOCK;
207                                        if (fcntl(0, F_SETFL, flags) >= 0) {
208						out2fmt_flush("sh: turning off NDELAY mode\n");
209                                                goto retry;
210                                        }
211                                }
212                        }
213                }
214                nr = -1;
215	}
216	return nr;
217}
218
219/*
220 * Refill the input buffer and return the next input character:
221 *
222 * 1) If a string was pushed back on the input, pop it;
223 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
224 *    from a string so we can't refill the buffer, return EOF.
225 * 3) If there is more in this buffer, use it else call read to fill it.
226 * 4) Process input up to the next newline, deleting nul characters.
227 */
228
229int
230preadbuffer(void)
231{
232	char *p, *q;
233	int more;
234	int something;
235	char savec;
236
237	if (parsefile->strpush) {
238		popstring();
239		if (--parsenleft >= 0)
240			return (*parsenextc++);
241	}
242	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
243		return PEOF;
244	flushout(&output);
245	flushout(&errout);
246
247again:
248	if (parselleft <= 0) {
249		if ((parselleft = preadfd()) == -1) {
250			parselleft = parsenleft = EOF_NLEFT;
251			return PEOF;
252		}
253	}
254
255	q = p = parsefile->buf + (parsenextc - parsefile->buf);
256
257	/* delete nul characters */
258	something = 0;
259	for (more = 1; more;) {
260		switch (*p) {
261		case '\0':
262			p++;	/* Skip nul */
263			goto check;
264
265		case '\t':
266		case ' ':
267			break;
268
269		case '\n':
270			parsenleft = q - parsenextc;
271			more = 0; /* Stop processing here */
272			break;
273
274		default:
275			something = 1;
276			break;
277		}
278
279		*q++ = *p++;
280check:
281		if (--parselleft <= 0) {
282			parsenleft = q - parsenextc - 1;
283			if (parsenleft < 0)
284				goto again;
285			*q = '\0';
286			more = 0;
287		}
288	}
289
290	savec = *q;
291	*q = '\0';
292
293#ifndef NO_HISTORY
294	if (parsefile->fd == 0 && hist && something) {
295		HistEvent he;
296		INTOFF;
297		history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
298		    parsenextc);
299		INTON;
300	}
301#endif
302
303	if (vflag) {
304		out2str(parsenextc);
305		flushout(out2);
306	}
307
308	*q = savec;
309
310	return *parsenextc++;
311}
312
313/*
314 * Returns if we are certain we are at EOF. Does not cause any more input
315 * to be read from the outside world.
316 */
317
318int
319preadateof(void)
320{
321	if (parsenleft > 0)
322		return 0;
323	if (parsefile->strpush)
324		return 0;
325	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
326		return 1;
327	return 0;
328}
329
330/*
331 * Undo the last call to pgetc.  Only one character may be pushed back.
332 * PEOF may be pushed back.
333 */
334
335void
336pungetc(void)
337{
338	parsenleft++;
339	parsenextc--;
340}
341
342/*
343 * Push a string back onto the input at this current parsefile level.
344 * We handle aliases this way.
345 */
346void
347pushstring(char *s, int len, struct alias *ap)
348{
349	struct strpush *sp;
350
351	INTOFF;
352/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
353	if (parsefile->strpush) {
354		sp = ckmalloc(sizeof (struct strpush));
355		sp->prev = parsefile->strpush;
356		parsefile->strpush = sp;
357	} else
358		sp = parsefile->strpush = &(parsefile->basestrpush);
359	sp->prevstring = parsenextc;
360	sp->prevnleft = parsenleft;
361	sp->prevlleft = parselleft;
362	sp->ap = ap;
363	if (ap)
364		ap->flag |= ALIASINUSE;
365	parsenextc = s;
366	parsenleft = len;
367	INTON;
368}
369
370static void
371popstring(void)
372{
373	struct strpush *sp = parsefile->strpush;
374
375	INTOFF;
376	parsenextc = sp->prevstring;
377	parsenleft = sp->prevnleft;
378	parselleft = sp->prevlleft;
379/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
380	if (sp->ap)
381		sp->ap->flag &= ~ALIASINUSE;
382	parsefile->strpush = sp->prev;
383	if (sp != &(parsefile->basestrpush))
384		ckfree(sp);
385	INTON;
386}
387
388/*
389 * Set the input to take input from a file.  If push is set, push the
390 * old input onto the stack first.
391 */
392
393void
394setinputfile(const char *fname, int push)
395{
396	int fd;
397	int fd2;
398
399	INTOFF;
400	if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0)
401		error("cannot open %s: %s", fname, strerror(errno));
402	if (fd < 10) {
403		fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);
404		close(fd);
405		if (fd2 < 0)
406			error("Out of file descriptors");
407		fd = fd2;
408	}
409	setinputfd(fd, push);
410	INTON;
411}
412
413
414/*
415 * Like setinputfile, but takes an open file descriptor (which should have
416 * its FD_CLOEXEC flag already set).  Call this with interrupts off.
417 */
418
419void
420setinputfd(int fd, int push)
421{
422	if (push) {
423		pushfile();
424		parsefile->buf = ckmalloc(BUFSIZ + 1);
425	}
426	if (parsefile->fd > 0)
427		close(parsefile->fd);
428	parsefile->fd = fd;
429	if (parsefile->buf == NULL)
430		parsefile->buf = ckmalloc(BUFSIZ + 1);
431	parselleft = parsenleft = 0;
432	plinno = 1;
433}
434
435
436/*
437 * Like setinputfile, but takes input from a string.
438 */
439
440void
441setinputstring(const char *string, int push)
442{
443	INTOFF;
444	if (push)
445		pushfile();
446	parsenextc = string;
447	parselleft = parsenleft = strlen(string);
448	parsefile->buf = NULL;
449	plinno = 1;
450	INTON;
451}
452
453
454
455/*
456 * To handle the "." command, a stack of input files is used.  Pushfile
457 * adds a new entry to the stack and popfile restores the previous level.
458 */
459
460static void
461pushfile(void)
462{
463	struct parsefile *pf;
464
465	parsefile->nleft = parsenleft;
466	parsefile->lleft = parselleft;
467	parsefile->nextc = parsenextc;
468	parsefile->linno = plinno;
469	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
470	pf->prev = parsefile;
471	pf->fd = -1;
472	pf->strpush = NULL;
473	pf->basestrpush.prev = NULL;
474	parsefile = pf;
475}
476
477
478void
479popfile(void)
480{
481	struct parsefile *pf = parsefile;
482
483	INTOFF;
484	if (pf->fd >= 0)
485		close(pf->fd);
486	if (pf->buf)
487		ckfree(pf->buf);
488	while (pf->strpush)
489		popstring();
490	parsefile = pf->prev;
491	ckfree(pf);
492	parsenleft = parsefile->nleft;
493	parselleft = parsefile->lleft;
494	parsenextc = parsefile->nextc;
495	plinno = parsefile->linno;
496	INTON;
497}
498
499
500/*
501 * Return current file (to go back to it later using popfilesupto()).
502 */
503
504struct parsefile *
505getcurrentfile(void)
506{
507	return parsefile;
508}
509
510
511/*
512 * Pop files until the given file is on top again. Useful for regular
513 * builtins that read shell commands from files or strings.
514 * If the given file is not an active file, an error is raised.
515 */
516
517void
518popfilesupto(struct parsefile *file)
519{
520	while (parsefile != file && parsefile != &basepf)
521		popfile();
522	if (parsefile != file)
523		error("popfilesupto() misused");
524}
525
526/*
527 * Return to top level.
528 */
529
530void
531popallfiles(void)
532{
533	while (parsefile != &basepf)
534		popfile();
535}
536
537
538
539/*
540 * Close the file(s) that the shell is reading commands from.  Called
541 * after a fork is done.
542 */
543
544void
545closescript(void)
546{
547	popallfiles();
548	if (parsefile->fd > 0) {
549		close(parsefile->fd);
550		parsefile->fd = 0;
551	}
552}
553