input.c revision 199629
11558Srgrimes/*-
21558Srgrimes * Copyright (c) 1991, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * This code is derived from software contributed to Berkeley by
61558Srgrimes * Kenneth Almquist.
71558Srgrimes *
81558Srgrimes * Redistribution and use in source and binary forms, with or without
91558Srgrimes * modification, are permitted provided that the following conditions
101558Srgrimes * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 4. Neither the name of the University nor the names of its contributors
171558Srgrimes *    may be used to endorse or promote products derived from this software
181558Srgrimes *    without specific prior written permission.
191558Srgrimes *
201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301558Srgrimes * SUCH DAMAGE.
311558Srgrimes */
3226737Scharnier
3326737Scharnier#ifndef lint
341558Srgrimes#if 0
351558Srgrimesstatic char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
361558Srgrimes#endif
371558Srgrimes#endif /* not lint */
381558Srgrimes#include <sys/cdefs.h>
391558Srgrimes__FBSDID("$FreeBSD: head/bin/sh/input.c 199629 2009-11-21 14:28:32Z jilles $");
401558Srgrimes
411558Srgrimes#include <stdio.h>	/* defines BUFSIZ */
421558Srgrimes#include <fcntl.h>
431558Srgrimes#include <errno.h>
441558Srgrimes#include <unistd.h>
451558Srgrimes#include <stdlib.h>
461558Srgrimes#include <string.h>
471558Srgrimes
481558Srgrimes/*
491558Srgrimes * This file implements the input routines used by the parser.
501558Srgrimes */
511558Srgrimes
521558Srgrimes#include "shell.h"
531558Srgrimes#include "redir.h"
541558Srgrimes#include "syntax.h"
551558Srgrimes#include "input.h"
561558Srgrimes#include "output.h"
571558Srgrimes#include "options.h"
581558Srgrimes#include "memalloc.h"
591558Srgrimes#include "error.h"
6026737Scharnier#include "alias.h"
611558Srgrimes#include "parser.h"
621558Srgrimes#include "myhistedit.h"
631558Srgrimes#include "trap.h"
641558Srgrimes
651558Srgrimes#define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
661558Srgrimes
671558SrgrimesMKINIT
681558Srgrimesstruct strpush {
691558Srgrimes	struct strpush *prev;	/* preceding string on stack */
701558Srgrimes	char *prevstring;
711558Srgrimes	int prevnleft;
721558Srgrimes	int prevlleft;
731558Srgrimes	struct alias *ap;	/* if push was associated with an alias */
741558Srgrimes};
751558Srgrimes
761558Srgrimes/*
771558Srgrimes * The parsefile structure pointed to by the global variable parsefile
781558Srgrimes * contains information about the current file being read.
791558Srgrimes */
801558Srgrimes
811558SrgrimesMKINIT
821558Srgrimesstruct parsefile {
831558Srgrimes	struct parsefile *prev;	/* preceding file on stack */
841558Srgrimes	int linno;		/* current line */
851558Srgrimes	int fd;			/* file descriptor (or -1 if string) */
866443Sdg	int nleft;		/* number of chars left in this line */
871558Srgrimes	int lleft;		/* number of lines left in this buffer */
881558Srgrimes	char *nextc;		/* next char in buffer */
891558Srgrimes	char *buf;		/* input buffer */
901558Srgrimes	struct strpush *strpush; /* for pushing strings at this level */
911558Srgrimes	struct strpush basestrpush; /* so pushing one is fast */
921558Srgrimes};
931558Srgrimes
941558Srgrimes
951558Srgrimesint plinno = 1;			/* input line number */
961558SrgrimesMKINIT int parsenleft;		/* copy of parsefile->nleft */
971558SrgrimesMKINIT int parselleft;		/* copy of parsefile->lleft */
981558Srgrimeschar *parsenextc;		/* copy of parsefile->nextc */
991558SrgrimesMKINIT struct parsefile basepf;	/* top level input file */
1001558Srgrimeschar basebuf[BUFSIZ];		/* buffer for top level input file */
1011558SrgrimesSTATIC struct parsefile *parsefile = &basepf;	/* current input file */
1021558Srgrimesint init_editline = 0;		/* editline library initialized? */
1031558Srgrimesint whichprompt;		/* 1 == PS1, 2 == PS2 */
1041558Srgrimes
1051558SrgrimesEditLine *el;			/* cookie for editline package */
1061558Srgrimes
1071558SrgrimesSTATIC void pushfile(void);
1081558Srgrimesstatic int preadfd(void);
1091558Srgrimes
11026737Scharnier#ifdef mkinit
11126737ScharnierINCLUDE "input.h"
1121558SrgrimesINCLUDE "error.h"
1131558Srgrimes
1141558SrgrimesINIT {
11524359Simp	extern char basebuf[];
1161558Srgrimes
1171558Srgrimes	basepf.nextc = basepf.buf = basebuf;
1181558Srgrimes}
1191558Srgrimes
1201558SrgrimesRESET {
1211558Srgrimes	popallfiles();
1221558Srgrimes	if (exception != EXSHELLPROC)
1231558Srgrimes		parselleft = parsenleft = 0;	/* clear input buffer */
1241558Srgrimes}
1251558Srgrimes
1261558SrgrimesSHELLPROC {
1271558Srgrimes	popallfiles();
1281558Srgrimes}
1291558Srgrimes#endif
1301558Srgrimes
1311558Srgrimes
1321558Srgrimes/*
1331558Srgrimes * Read a line from the script.
1341558Srgrimes */
1351558Srgrimes
1361558Srgrimeschar *
1371558Srgrimespfgets(char *line, int len)
1381558Srgrimes{
1391558Srgrimes	char *p = line;
1401558Srgrimes	int nleft = len;
1411558Srgrimes	int c;
1421558Srgrimes
14326737Scharnier	while (--nleft > 0) {
1441558Srgrimes		c = pgetc_macro();
1451558Srgrimes		if (c == PEOF) {
1461558Srgrimes			if (p == line)
1471558Srgrimes				return NULL;
1481558Srgrimes			break;
1491558Srgrimes		}
1501558Srgrimes		*p++ = c;
1511558Srgrimes		if (c == '\n')
1521558Srgrimes			break;
1531558Srgrimes	}
1541558Srgrimes	*p = '\0';
1551558Srgrimes	return line;
1561558Srgrimes}
1571558Srgrimes
1581558Srgrimes
1591558Srgrimes
1601558Srgrimes/*
1611558Srgrimes * Read a character from the script, returning PEOF on end of file.
1621558Srgrimes * Nul characters in the input are silently discarded.
1631558Srgrimes */
1641558Srgrimes
1651558Srgrimesint
1661558Srgrimespgetc(void)
1671558Srgrimes{
1681558Srgrimes	return pgetc_macro();
1691558Srgrimes}
1701558Srgrimes
1711558Srgrimes
1721558Srgrimesstatic int
1731558Srgrimespreadfd(void)
1741558Srgrimes{
1751558Srgrimes	int nr;
1761558Srgrimes	parsenextc = parsefile->buf;
1771558Srgrimes
1781558Srgrimes#ifndef NO_HISTORY
1791558Srgrimes	if (el != NULL && gotwinch) {
1801558Srgrimes		gotwinch = 0;
1811558Srgrimes		el_resize(el);
1821558Srgrimes	}
1831558Srgrimes#endif
1841558Srgrimesretry:
1851558Srgrimes#ifndef NO_HISTORY
1861558Srgrimes	if (parsefile->fd == 0 && el) {
1871558Srgrimes		static const char *rl_cp;
1881558Srgrimes		static int el_len;
1891558Srgrimes
1901558Srgrimes		if (rl_cp == NULL)
1911558Srgrimes			rl_cp = el_gets(el, &el_len);
1921558Srgrimes		if (rl_cp == NULL)
1931558Srgrimes			nr = 0;
19426737Scharnier		else {
19526737Scharnier			nr = el_len;
19626737Scharnier			if (nr > BUFSIZ - 1)
19726737Scharnier				nr = BUFSIZ - 1;
1981558Srgrimes			memcpy(parsenextc, rl_cp, nr);
1991558Srgrimes			if (nr != el_len) {
2001558Srgrimes				el_len -= nr;
2011558Srgrimes				rl_cp += nr;
2021558Srgrimes			} else
2031558Srgrimes				rl_cp = NULL;
2041558Srgrimes		}
2051558Srgrimes	} else
2061558Srgrimes#endif
2071558Srgrimes		nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
2081558Srgrimes
2091558Srgrimes	if (nr <= 0) {
2101558Srgrimes                if (nr < 0) {
2111558Srgrimes                        if (errno == EINTR)
2121558Srgrimes                                goto retry;
2131558Srgrimes                        if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
2141558Srgrimes                                int flags = fcntl(0, F_GETFL, 0);
2151558Srgrimes                                if (flags >= 0 && flags & O_NONBLOCK) {
2161558Srgrimes                                        flags &=~ O_NONBLOCK;
2171558Srgrimes                                        if (fcntl(0, F_SETFL, flags) >= 0) {
2181558Srgrimes						out2fmt_flush("sh: turning off NDELAY mode\n");
2191558Srgrimes                                                goto retry;
2201558Srgrimes                                        }
2211558Srgrimes                                }
2221558Srgrimes                        }
2231558Srgrimes                }
2241558Srgrimes                nr = -1;
2251558Srgrimes	}
2261558Srgrimes	return nr;
2271558Srgrimes}
2281558Srgrimes
2291558Srgrimes/*
2301558Srgrimes * Refill the input buffer and return the next input character:
2311558Srgrimes *
2321558Srgrimes * 1) If a string was pushed back on the input, pop it;
2331558Srgrimes * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
2341558Srgrimes *    from a string so we can't refill the buffer, return EOF.
2351558Srgrimes * 3) If there is more in this buffer, use it else call read to fill it.
2361558Srgrimes * 4) Process input up to the next newline, deleting nul characters.
2371558Srgrimes */
2381558Srgrimes
2391558Srgrimesint
2401558Srgrimespreadbuffer(void)
2411558Srgrimes{
2421558Srgrimes	char *p, *q;
2431558Srgrimes	int more;
2441558Srgrimes	int something;
2451558Srgrimes	char savec;
2461558Srgrimes
2471558Srgrimes	if (parsefile->strpush) {
2481558Srgrimes		popstring();
2491558Srgrimes		if (--parsenleft >= 0)
2501558Srgrimes			return (*parsenextc++);
2511558Srgrimes	}
2521558Srgrimes	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
2531558Srgrimes		return PEOF;
2541558Srgrimes	flushout(&output);
2551558Srgrimes	flushout(&errout);
2561558Srgrimes
2571558Srgrimesagain:
2581558Srgrimes	if (parselleft <= 0) {
2591558Srgrimes		if ((parselleft = preadfd()) == -1) {
2601558Srgrimes			parselleft = parsenleft = EOF_NLEFT;
2611558Srgrimes			return PEOF;
2621558Srgrimes		}
2631558Srgrimes	}
2641558Srgrimes
2651558Srgrimes	q = p = parsenextc;
2661558Srgrimes
2671558Srgrimes	/* delete nul characters */
2681558Srgrimes	something = 0;
2691558Srgrimes	for (more = 1; more;) {
2701558Srgrimes		switch (*p) {
2711558Srgrimes		case '\0':
2721558Srgrimes			p++;	/* Skip nul */
2731558Srgrimes			goto check;
2741558Srgrimes
2751558Srgrimes		case '\t':
2761558Srgrimes		case ' ':
2771558Srgrimes			break;
2781558Srgrimes
2791558Srgrimes		case '\n':
2801558Srgrimes			parsenleft = q - parsenextc;
2811558Srgrimes			more = 0; /* Stop processing here */
2821558Srgrimes			break;
2831558Srgrimes
2841558Srgrimes		default:
2851558Srgrimes			something = 1;
2861558Srgrimes			break;
2871558Srgrimes		}
2881558Srgrimes
2891558Srgrimes		*q++ = *p++;
2901558Srgrimescheck:
2911558Srgrimes		if (--parselleft <= 0) {
2921558Srgrimes			parsenleft = q - parsenextc - 1;
2931558Srgrimes			if (parsenleft < 0)
2941558Srgrimes				goto again;
2951558Srgrimes			*q = '\0';
2961558Srgrimes			more = 0;
2971558Srgrimes		}
2981558Srgrimes	}
2991558Srgrimes
3001558Srgrimes	savec = *q;
3011558Srgrimes	*q = '\0';
3021558Srgrimes
3031558Srgrimes#ifndef NO_HISTORY
3041558Srgrimes	if (parsefile->fd == 0 && hist && something) {
3051558Srgrimes		HistEvent he;
3061558Srgrimes		INTOFF;
3071558Srgrimes		history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
3081558Srgrimes		    parsenextc);
3091558Srgrimes		INTON;
3101558Srgrimes	}
3111558Srgrimes#endif
3121558Srgrimes
3131558Srgrimes	if (vflag) {
3141558Srgrimes		out2str(parsenextc);
3151558Srgrimes		flushout(out2);
3161558Srgrimes	}
3174844Sats
3181558Srgrimes	*q = savec;
3191558Srgrimes
3201558Srgrimes	return *parsenextc++;
3211558Srgrimes}
3221558Srgrimes
3231558Srgrimes/*
3241558Srgrimes * Returns if we are certain we are at EOF. Does not cause any more input
3251558Srgrimes * to be read from the outside world.
3261558Srgrimes */
3271558Srgrimes
3281558Srgrimesint
3291558Srgrimespreadateof(void)
3301558Srgrimes{
3311558Srgrimes	if (parsenleft > 0)
3321558Srgrimes		return 0;
3331558Srgrimes	if (parsefile->strpush)
3341558Srgrimes		return 0;
3351558Srgrimes	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
3361558Srgrimes		return 1;
3371558Srgrimes	return 0;
3381558Srgrimes}
3391558Srgrimes
3401558Srgrimes/*
3411558Srgrimes * Undo the last call to pgetc.  Only one character may be pushed back.
3421558Srgrimes * PEOF may be pushed back.
3431558Srgrimes */
3441558Srgrimes
3451558Srgrimesvoid
3461558Srgrimespungetc(void)
3471558Srgrimes{
3481558Srgrimes	parsenleft++;
3491558Srgrimes	parsenextc--;
3501558Srgrimes}
3511558Srgrimes
3521558Srgrimes/*
3531558Srgrimes * Push a string back onto the input at this current parsefile level.
3541558Srgrimes * We handle aliases this way.
3551558Srgrimes */
3561558Srgrimesvoid
3571558Srgrimespushstring(char *s, int len, void *ap)
3581558Srgrimes{
3591558Srgrimes	struct strpush *sp;
3601558Srgrimes
3611558Srgrimes	INTOFF;
3621558Srgrimes/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
3631558Srgrimes	if (parsefile->strpush) {
3641558Srgrimes		sp = ckmalloc(sizeof (struct strpush));
3651558Srgrimes		sp->prev = parsefile->strpush;
3661558Srgrimes		parsefile->strpush = sp;
3671558Srgrimes	} else
3681558Srgrimes		sp = parsefile->strpush = &(parsefile->basestrpush);
3691558Srgrimes	sp->prevstring = parsenextc;
3701558Srgrimes	sp->prevnleft = parsenleft;
3711558Srgrimes	sp->prevlleft = parselleft;
3721558Srgrimes	sp->ap = (struct alias *)ap;
3731558Srgrimes	if (ap)
3741558Srgrimes		((struct alias *)ap)->flag |= ALIASINUSE;
3751558Srgrimes	parsenextc = s;
3761558Srgrimes	parsenleft = len;
3771558Srgrimes	INTON;
3781558Srgrimes}
3791558Srgrimes
3801558Srgrimesvoid
3811558Srgrimespopstring(void)
3821558Srgrimes{
3831558Srgrimes	struct strpush *sp = parsefile->strpush;
3841558Srgrimes
3851558Srgrimes	INTOFF;
3861558Srgrimes	parsenextc = sp->prevstring;
3871558Srgrimes	parsenleft = sp->prevnleft;
3881558Srgrimes	parselleft = sp->prevlleft;
3891558Srgrimes/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
3901558Srgrimes	if (sp->ap)
3911558Srgrimes		sp->ap->flag &= ~ALIASINUSE;
3921558Srgrimes	parsefile->strpush = sp->prev;
3931558Srgrimes	if (sp != &(parsefile->basestrpush))
3941558Srgrimes		ckfree(sp);
3951558Srgrimes	INTON;
3961558Srgrimes}
3971558Srgrimes
3981558Srgrimes/*
3991558Srgrimes * Set the input to take input from a file.  If push is set, push the
4001558Srgrimes * old input onto the stack first.
4011558Srgrimes */
4021558Srgrimes
4031558Srgrimesvoid
4041558Srgrimessetinputfile(char *fname, int push)
40526737Scharnier{
40626737Scharnier	int fd;
4071558Srgrimes	int fd2;
4081558Srgrimes
4091558Srgrimes	INTOFF;
4101558Srgrimes	if ((fd = open(fname, O_RDONLY)) < 0)
4111558Srgrimes		error("Can't open %s: %s", fname, strerror(errno));
4121558Srgrimes	if (fd < 10) {
4131558Srgrimes		fd2 = fcntl(fd, F_DUPFD, 10);
4141558Srgrimes		close(fd);
4151558Srgrimes		if (fd2 < 0)
4161558Srgrimes			error("Out of file descriptors");
4171558Srgrimes		fd = fd2;
4181558Srgrimes	}
4191558Srgrimes	setinputfd(fd, push);
4201558Srgrimes	INTON;
4211558Srgrimes}
4221558Srgrimes
4231558Srgrimes
4241558Srgrimes/*
4251558Srgrimes * Like setinputfile, but takes an open file descriptor.  Call this with
4261558Srgrimes * interrupts off.
4271558Srgrimes */
4281558Srgrimes
4291558Srgrimesvoid
4301558Srgrimessetinputfd(int fd, int push)
4311558Srgrimes{
4321558Srgrimes	(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
4331558Srgrimes	if (push) {
4341558Srgrimes		pushfile();
4351558Srgrimes		parsefile->buf = ckmalloc(BUFSIZ);
4361558Srgrimes	}
4371558Srgrimes	if (parsefile->fd > 0)
4381558Srgrimes		close(parsefile->fd);
4391558Srgrimes	parsefile->fd = fd;
4401558Srgrimes	if (parsefile->buf == NULL)
4411558Srgrimes		parsefile->buf = ckmalloc(BUFSIZ);
4421558Srgrimes	parselleft = parsenleft = 0;
4431558Srgrimes	plinno = 1;
4441558Srgrimes}
4451558Srgrimes
4461558Srgrimes
44726737Scharnier/*
4481558Srgrimes * Like setinputfile, but takes input from a string.
4491558Srgrimes */
4501558Srgrimes
4511558Srgrimesvoid
4521558Srgrimessetinputstring(char *string, int push)
4536443Sdg{
4541558Srgrimes	INTOFF;
4551558Srgrimes	if (push)
456		pushfile();
457	parsenextc = string;
458	parselleft = parsenleft = strlen(string);
459	parsefile->buf = NULL;
460	plinno = 1;
461	INTON;
462}
463
464
465
466/*
467 * To handle the "." command, a stack of input files is used.  Pushfile
468 * adds a new entry to the stack and popfile restores the previous level.
469 */
470
471STATIC void
472pushfile(void)
473{
474	struct parsefile *pf;
475
476	parsefile->nleft = parsenleft;
477	parsefile->lleft = parselleft;
478	parsefile->nextc = parsenextc;
479	parsefile->linno = plinno;
480	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
481	pf->prev = parsefile;
482	pf->fd = -1;
483	pf->strpush = NULL;
484	pf->basestrpush.prev = NULL;
485	parsefile = pf;
486}
487
488
489void
490popfile(void)
491{
492	struct parsefile *pf = parsefile;
493
494	INTOFF;
495	if (pf->fd >= 0)
496		close(pf->fd);
497	if (pf->buf)
498		ckfree(pf->buf);
499	while (pf->strpush)
500		popstring();
501	parsefile = pf->prev;
502	ckfree(pf);
503	parsenleft = parsefile->nleft;
504	parselleft = parsefile->lleft;
505	parsenextc = parsefile->nextc;
506	plinno = parsefile->linno;
507	INTON;
508}
509
510
511/*
512 * Return to top level.
513 */
514
515void
516popallfiles(void)
517{
518	while (parsefile != &basepf)
519		popfile();
520}
521
522
523
524/*
525 * Close the file(s) that the shell is reading commands from.  Called
526 * after a fork is done.
527 */
528
529void
530closescript(void)
531{
532	popallfiles();
533	if (parsefile->fd > 0) {
534		close(parsefile->fd);
535		parsefile->fd = 0;
536	}
537}
538