/*-1* Copyright (c) 1991, 19932* The Regents of the University of California. All rights reserved.3*4* This code is derived from software contributed to Berkeley by5* Kenneth Almquist.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15* 3. Neither the name of the University nor the names of its contributors16* may be used to endorse or promote products derived from this software17* without specific prior written permission.18*19* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*/3132#include <stdio.h> /* defines BUFSIZ */33#include <fcntl.h>34#include <errno.h>35#include <unistd.h>36#include <stdlib.h>37#include <string.h>3839/*40* This file implements the input routines used by the parser.41*/4243#include "shell.h"44#include "redir.h"45#include "syntax.h"46#include "input.h"47#include "output.h"48#include "options.h"49#include "memalloc.h"50#include "error.h"51#include "alias.h"52#include "parser.h"53#ifndef NO_HISTORY54#include "myhistedit.h"55#endif56#include "trap.h"5758#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */5960struct strpush {61struct strpush *prev; /* preceding string on stack */62const char *prevstring;63int prevnleft;64int prevlleft;65struct alias *ap; /* if push was associated with an alias */66};6768/*69* The parsefile structure pointed to by the global variable parsefile70* contains information about the current file being read.71*/7273struct parsefile {74struct parsefile *prev; /* preceding file on stack */75int linno; /* current line */76int fd; /* file descriptor (or -1 if string) */77int nleft; /* number of chars left in this line */78int lleft; /* number of lines left in this buffer */79const char *nextc; /* next char in buffer */80char *buf; /* input buffer */81struct strpush *strpush; /* for pushing strings at this level */82struct strpush basestrpush; /* so pushing one is fast */83};848586int plinno = 1; /* input line number */87int parsenleft; /* copy of parsefile->nleft */88static int parselleft; /* copy of parsefile->lleft */89const char *parsenextc; /* copy of parsefile->nextc */90static char basebuf[BUFSIZ + 1];/* buffer for top level input file */91static struct parsefile basepf = { /* top level input file */92.nextc = basebuf,93.buf = basebuf94};95static struct parsefile *parsefile = &basepf; /* current input file */96int whichprompt; /* 1 == PS1, 2 == PS2 */9798static void pushfile(void);99static int preadfd(void);100static void popstring(void);101102void103resetinput(void)104{105popallfiles();106parselleft = parsenleft = 0; /* clear input buffer */107}108109110111/*112* Read a character from the script, returning PEOF on end of file.113* Nul characters in the input are silently discarded.114*/115116int117pgetc(void)118{119return pgetc_macro();120}121122123static int124preadfd(void)125{126int nr;127parsenextc = parsefile->buf;128129retry:130#ifndef NO_HISTORY131if (parsefile->fd == 0 && el) {132static const char *rl_cp;133static int el_len;134135if (rl_cp == NULL) {136el_resize(el);137rl_cp = el_gets(el, &el_len);138}139if (rl_cp == NULL)140nr = el_len == 0 ? 0 : -1;141else {142nr = el_len;143if (nr > BUFSIZ)144nr = BUFSIZ;145memcpy(parsefile->buf, rl_cp, nr);146if (nr != el_len) {147el_len -= nr;148rl_cp += nr;149} else150rl_cp = NULL;151}152} else153#endif154nr = read(parsefile->fd, parsefile->buf, BUFSIZ);155156if (nr <= 0) {157if (nr < 0) {158if (errno == EINTR)159goto retry;160if (parsefile->fd == 0 && errno == EWOULDBLOCK) {161int flags = fcntl(0, F_GETFL, 0);162if (flags >= 0 && flags & O_NONBLOCK) {163flags &=~ O_NONBLOCK;164if (fcntl(0, F_SETFL, flags) >= 0) {165out2fmt_flush("sh: turning off NDELAY mode\n");166goto retry;167}168}169}170}171nr = -1;172}173return nr;174}175176/*177* Refill the input buffer and return the next input character:178*179* 1) If a string was pushed back on the input, pop it;180* 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading181* from a string so we can't refill the buffer, return EOF.182* 3) If there is more in this buffer, use it else call read to fill it.183* 4) Process input up to the next newline, deleting nul characters.184*/185186int187preadbuffer(void)188{189char *p, *q, *r, *end;190char savec;191192while (parsefile->strpush) {193/*194* Add a space to the end of an alias to ensure that the195* alias remains in use while parsing its last word.196* This avoids alias recursions.197*/198if (parsenleft == -1 && parsefile->strpush->ap != NULL)199return ' ';200popstring();201if (--parsenleft >= 0)202return (*parsenextc++);203}204if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)205return PEOF;206207again:208if (parselleft <= 0) {209if ((parselleft = preadfd()) == -1) {210parselleft = parsenleft = EOF_NLEFT;211return PEOF;212}213}214215p = parsefile->buf + (parsenextc - parsefile->buf);216end = p + parselleft;217*end = '\0';218q = strchrnul(p, '\n');219if (q != end && *q == '\0') {220/* delete nul characters */221for (r = q; q != end; q++) {222if (*q != '\0')223*r++ = *q;224}225parselleft -= end - r;226if (parselleft == 0)227goto again;228end = p + parselleft;229*end = '\0';230q = strchrnul(p, '\n');231}232if (q == end) {233parsenleft = parselleft;234parselleft = 0;235} else /* *q == '\n' */ {236q++;237parsenleft = q - parsenextc;238parselleft -= parsenleft;239}240parsenleft--;241242savec = *q;243*q = '\0';244245#ifndef NO_HISTORY246if (parsefile->fd == 0 && hist &&247parsenextc[strspn(parsenextc, " \t\n")] != '\0') {248HistEvent he;249INTOFF;250history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,251parsenextc);252INTON;253}254#endif255256if (vflag) {257out2str(parsenextc);258flushout(out2);259}260261*q = savec;262263return *parsenextc++;264}265266/*267* Returns if we are certain we are at EOF. Does not cause any more input268* to be read from the outside world.269*/270271int272preadateof(void)273{274if (parsenleft > 0)275return 0;276if (parsefile->strpush)277return 0;278if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)279return 1;280return 0;281}282283/*284* Undo the last call to pgetc. Only one character may be pushed back.285* PEOF may be pushed back.286*/287288void289pungetc(void)290{291parsenleft++;292parsenextc--;293}294295/*296* Push a string back onto the input at this current parsefile level.297* We handle aliases this way.298*/299void300pushstring(const char *s, int len, struct alias *ap)301{302struct strpush *sp;303304INTOFF;305/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/306if (parsefile->strpush) {307sp = ckmalloc(sizeof (struct strpush));308sp->prev = parsefile->strpush;309parsefile->strpush = sp;310} else311sp = parsefile->strpush = &(parsefile->basestrpush);312sp->prevstring = parsenextc;313sp->prevnleft = parsenleft;314sp->prevlleft = parselleft;315sp->ap = ap;316if (ap)317ap->flag |= ALIASINUSE;318parsenextc = s;319parsenleft = len;320INTON;321}322323static void324popstring(void)325{326struct strpush *sp = parsefile->strpush;327328INTOFF;329if (sp->ap) {330if (parsenextc != sp->ap->val &&331(parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))332forcealias();333sp->ap->flag &= ~ALIASINUSE;334}335parsenextc = sp->prevstring;336parsenleft = sp->prevnleft;337parselleft = sp->prevlleft;338/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/339parsefile->strpush = sp->prev;340if (sp != &(parsefile->basestrpush))341ckfree(sp);342INTON;343}344345/*346* Set the input to take input from a file. If push is set, push the347* old input onto the stack first.348* About verify:349* -1: Obey verifyflag350* 0: Do not verify351* 1: Do verify352*/353354void355setinputfile(const char *fname, int push, int verify)356{357int e;358int fd;359int fd2;360int oflags = O_RDONLY | O_CLOEXEC;361362if (verify == 1 || (verify == -1 && verifyflag))363oflags |= O_VERIFY;364365INTOFF;366if ((fd = open(fname, oflags)) < 0) {367e = errno;368errorwithstatus(e == ENOENT || e == ENOTDIR ? 127 : 126,369"cannot open %s: %s", fname, strerror(e));370}371if (fd < 10) {372fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);373close(fd);374if (fd2 < 0)375error("Out of file descriptors");376fd = fd2;377}378setinputfd(fd, push);379INTON;380}381382383/*384* Like setinputfile, but takes an open file descriptor (which should have385* its FD_CLOEXEC flag already set). Call this with interrupts off.386*/387388void389setinputfd(int fd, int push)390{391if (push) {392pushfile();393parsefile->buf = ckmalloc(BUFSIZ + 1);394}395if (parsefile->fd > 0)396close(parsefile->fd);397parsefile->fd = fd;398if (parsefile->buf == NULL)399parsefile->buf = ckmalloc(BUFSIZ + 1);400parselleft = parsenleft = 0;401plinno = 1;402}403404405/*406* Like setinputfile, but takes input from a string.407*/408409void410setinputstring(const char *string, int push)411{412INTOFF;413if (push)414pushfile();415parsenextc = string;416parselleft = parsenleft = strlen(string);417parsefile->buf = NULL;418plinno = 1;419INTON;420}421422423424/*425* To handle the "." command, a stack of input files is used. Pushfile426* adds a new entry to the stack and popfile restores the previous level.427*/428429static void430pushfile(void)431{432struct parsefile *pf;433434parsefile->nleft = parsenleft;435parsefile->lleft = parselleft;436parsefile->nextc = parsenextc;437parsefile->linno = plinno;438pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));439pf->prev = parsefile;440pf->fd = -1;441pf->strpush = NULL;442pf->basestrpush.prev = NULL;443parsefile = pf;444}445446447void448popfile(void)449{450struct parsefile *pf = parsefile;451452INTOFF;453if (pf->fd >= 0)454close(pf->fd);455if (pf->buf)456ckfree(pf->buf);457while (pf->strpush)458popstring();459parsefile = pf->prev;460ckfree(pf);461parsenleft = parsefile->nleft;462parselleft = parsefile->lleft;463parsenextc = parsefile->nextc;464plinno = parsefile->linno;465INTON;466}467468469/*470* Return current file (to go back to it later using popfilesupto()).471*/472473struct parsefile *474getcurrentfile(void)475{476return parsefile;477}478479480/*481* Pop files until the given file is on top again. Useful for regular482* builtins that read shell commands from files or strings.483* If the given file is not an active file, an error is raised.484*/485486void487popfilesupto(struct parsefile *file)488{489while (parsefile != file && parsefile != &basepf)490popfile();491if (parsefile != file)492error("popfilesupto() misused");493}494495/*496* Return to top level.497*/498499void500popallfiles(void)501{502while (parsefile != &basepf)503popfile();504}505506507508/*509* Close the file(s) that the shell is reading commands from. Called510* after a fork is done.511*/512513void514closescript(void)515{516popallfiles();517if (parsefile->fd > 0) {518close(parsefile->fd);519parsefile->fd = 0;520}521}522523524