diff options
Diffstat (limited to 'bin/sh/input.c')
-rw-r--r-- | bin/sh/input.c | 695 |
1 files changed, 0 insertions, 695 deletions
diff --git a/bin/sh/input.c b/bin/sh/input.c deleted file mode 100644 index dc686f5..0000000 --- a/bin/sh/input.c +++ /dev/null @@ -1,695 +0,0 @@ -/* $NetBSD: input.c,v 1.69 2019/01/16 07:14:17 kre Exp $ */ - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; -#else -__RCSID("$NetBSD: input.c,v 1.69 2019/01/16 07:14:17 kre Exp $"); -#endif -#endif /* not lint */ - -#include <stdio.h> /* defines BUFSIZ */ -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> - -/* - * This file implements the input routines used by the parser. - */ - -#include "shell.h" -#include "redir.h" -#include "syntax.h" -#include "input.h" -#include "output.h" -#include "options.h" -#include "memalloc.h" -#include "error.h" -#include "alias.h" -#include "parser.h" -#include "myhistedit.h" -#include "show.h" - -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ - -MKINIT -struct strpush { - struct strpush *prev; /* preceding string on stack */ - const char *prevstring; - int prevnleft; - int prevlleft; - struct alias *ap; /* if push was associated with an alias */ -}; - -/* - * The parsefile structure pointed to by the global variable parsefile - * contains information about the current file being read. - */ - -MKINIT -struct parsefile { - struct parsefile *prev; /* preceding file on stack */ - int linno; /* current line */ - int fd; /* file descriptor (or -1 if string) */ - int nleft; /* number of chars left in this line */ - int lleft; /* number of chars left in this buffer */ - const char *nextc; /* next char in buffer */ - char *buf; /* input buffer */ - struct strpush *strpush; /* for pushing strings at this level */ - struct strpush basestrpush; /* so pushing one is fast */ -}; - - -int plinno = 1; /* input line number */ -int parsenleft; /* copy of parsefile->nleft */ -MKINIT int parselleft; /* copy of parsefile->lleft */ -const char *parsenextc; /* copy of parsefile->nextc */ -MKINIT struct parsefile basepf; /* top level input file */ -MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */ -struct parsefile *parsefile = &basepf; /* current input file */ -int init_editline = 0; /* editline library initialized? */ -int whichprompt; /* 1 == PS1, 2 == PS2 */ - -STATIC void pushfile(void); -static int preadfd(void); - -#ifdef mkinit -INCLUDE <stdio.h> -INCLUDE "input.h" -INCLUDE "error.h" - -INIT { - basepf.nextc = basepf.buf = basebuf; -} - -RESET { - if (exception != EXSHELLPROC) - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); -} - -SHELLPROC { - popallfiles(); -} -#endif - - -#if 0 /* this is unused */ -/* - * Read a line from the script. - */ - -char * -pfgets(char *line, int len) -{ - char *p = line; - int nleft = len; - int c; - - while (--nleft > 0) { - c = pgetc_macro(); - if (c == PFAKE) /* consecutive PFAKEs is impossible */ - c = pgetc_macro(); - if (c == PEOF) { - if (p == line) - return NULL; - break; - } - *p++ = c; - if (c == '\n') { - plinno++; - break; - } - } - *p = '\0'; - return line; -} -#endif - - -/* - * Read a character from the script, returning PEOF on end of file. - * Nul characters in the input are silently discarded. - */ - -int -pgetc(void) -{ - int c; - - c = pgetc_macro(); - if (c == PFAKE) - c = pgetc_macro(); - return c; -} - - -static int -preadfd(void) -{ - int nr; - char *buf = parsefile->buf; - parsenextc = buf; - - retry: -#ifndef SMALL - if (parsefile->fd == 0 && el) { - static const char *rl_cp; - static int el_len; - - if (rl_cp == NULL) - rl_cp = el_gets(el, &el_len); - if (rl_cp == NULL) - nr = el_len == 0 ? 0 : -1; - else { - nr = el_len; - if (nr > BUFSIZ - 8) - nr = BUFSIZ - 8; - memcpy(buf, rl_cp, nr); - if (nr != el_len) { - el_len -= nr; - rl_cp += nr; - } else - rl_cp = 0; - } - - } else -#endif - nr = read(parsefile->fd, buf, BUFSIZ - 8); - - - if (nr <= 0) { - if (nr < 0) { - if (errno == EINTR) - goto retry; - if (parsefile->fd == 0 && errno == EWOULDBLOCK) { - int flags = fcntl(0, F_GETFL, 0); - - if (flags >= 0 && flags & O_NONBLOCK) { - flags &=~ O_NONBLOCK; - if (fcntl(0, F_SETFL, flags) >= 0) { - out2str("sh: turning off NDELAY mode\n"); - goto retry; - } - } - } - } - nr = -1; - } - return nr; -} - -/* - * Refill the input buffer and return the next input character: - * - * 1) If a string was pushed back on the input, pop it; - * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading - * from a string so we can't refill the buffer, return EOF. - * 3) If there is more stuff in this buffer, use it else call read to fill it. - * 4) Process input up to the next newline, deleting nul characters. - */ - -int -preadbuffer(void) -{ - char *p, *q; - int more; -#ifndef SMALL - int something; -#endif - char savec; - - while (parsefile->strpush) { - if (parsenleft == -1 && parsefile->strpush->ap != NULL) - return PFAKE; - popstring(); - if (--parsenleft >= 0) - return (*parsenextc++); - } - if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) - return PEOF; - flushout(&output); - flushout(&errout); - - again: - if (parselleft <= 0) { - if ((parselleft = preadfd()) == -1) { - parselleft = parsenleft = EOF_NLEFT; - return PEOF; - } - } - - /* p = (not const char *)parsenextc; */ - p = parsefile->buf + (parsenextc - parsefile->buf); - q = p; - - /* delete nul characters */ -#ifndef SMALL - something = 0; -#endif - for (more = 1; more;) { - switch (*p) { - case '\0': - p++; /* Skip nul */ - goto check; - - case '\t': - case ' ': - break; - - case '\n': - parsenleft = q - parsenextc; - more = 0; /* Stop processing here */ - break; - - default: -#ifndef SMALL - something = 1; -#endif - break; - } - - *q++ = *p++; - check: - if (--parselleft <= 0) { - parsenleft = q - parsenextc - 1; - if (parsenleft < 0) - goto again; - *q = '\0'; - more = 0; - } - } - - savec = *q; - *q = '\0'; - -#ifndef SMALL - if (parsefile->fd == 0 && hist && (something || whichprompt == 2)) { - HistEvent he; - - INTOFF; - history(hist, &he, whichprompt != 2 ? H_ENTER : H_APPEND, - parsenextc); - INTON; - } -#endif - - if (vflag) { - out2str(parsenextc); - flushout(out2); - } - - *q = savec; - - return *parsenextc++; -} - -/* - * Test whether we have reached EOF on input stream. - * Return true only if certain (without attempting a read). - * - * Note the similarity to the opening section of preadbuffer() - */ -int -at_eof(void) -{ - struct strpush *sp = parsefile->strpush; - - if (parsenleft > 0) /* more chars are in the buffer */ - return 0; - - while (sp != NULL) { - /* - * If any pushed string has any remaining data, - * then we are not at EOF (simulating popstring()) - */ - if (sp->prevnleft > 0) - return 0; - sp = sp->prev; - } - - /* - * If we reached real EOF and pushed it back, - * or if we are just processing a string (not reading a file) - * then there is no more. Note that if a file pushes a - * string, the file's ->buf remains present. - */ - if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) - return 1; - - /* - * In other cases, there might be more - */ - return 0; -} - -/* - * Undo the last call to pgetc. Only one character may be pushed back. - * PEOF may be pushed back. - */ - -void -pungetc(void) -{ - parsenleft++; - parsenextc--; -} - -/* - * Push a string back onto the input at this current parsefile level. - * We handle aliases this way. - */ -void -pushstring(const char *s, int len, struct alias *ap) -{ - struct strpush *sp; - - VTRACE(DBG_INPUT, - ("pushstring(\"%.*s\", %d)%s%s%s had: nl=%d ll=%d \"%.*s\"\n", - len, s, len, ap ? " for alias:'" : "", - ap ? ap->name : "", ap ? "'" : "", - parsenleft, parselleft, parsenleft, parsenextc)); - - INTOFF; - if (parsefile->strpush) { - sp = ckmalloc(sizeof (struct strpush)); - sp->prev = parsefile->strpush; - parsefile->strpush = sp; - } else - sp = parsefile->strpush = &(parsefile->basestrpush); - - sp->prevstring = parsenextc; - sp->prevnleft = parsenleft; - sp->prevlleft = parselleft; - sp->ap = ap; - if (ap) - ap->flag |= ALIASINUSE; - parsenextc = s; - parsenleft = len; - INTON; -} - -void -popstring(void) -{ - struct strpush *sp = parsefile->strpush; - - INTOFF; - if (sp->ap) { - int alen; - - if ((alen = strlen(sp->ap->val)) > 0 && - (sp->ap->val[alen - 1] == ' ' || - sp->ap->val[alen - 1] == '\t')) - checkkwd |= CHKALIAS; - sp->ap->flag &= ~ALIASINUSE; - } - parsenextc = sp->prevstring; - parsenleft = sp->prevnleft; - parselleft = sp->prevlleft; - - VTRACE(DBG_INPUT, ("popstring()%s%s%s nl=%d ll=%d \"%.*s\"\n", - sp->ap ? " from alias:'" : "", sp->ap ? sp->ap->name : "", - sp->ap ? "'" : "", parsenleft, parselleft, parsenleft, parsenextc)); - - parsefile->strpush = sp->prev; - if (sp != &(parsefile->basestrpush)) - ckfree(sp); - INTON; -} - -/* - * Set the input to take input from a file. If push is set, push the - * old input onto the stack first. - */ - -void -setinputfile(const char *fname, int push) -{ - unsigned char magic[4]; - int fd; - int fd2; - struct stat sb; - - CTRACE(DBG_INPUT,("setinputfile(\"%s\", %spush)\n",fname,push?"":"no")); - - INTOFF; - if ((fd = open(fname, O_RDONLY)) < 0) - error("Can't open %s", fname); - - /* Since the message "Syntax error: "(" unexpected" is not very - * helpful, we check if the file starts with the ELF magic to - * avoid that message. The first lseek tries to make sure that - * we can later rewind the file. - */ - if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode) && - lseek(fd, 0, SEEK_SET) == 0) { - if (read(fd, magic, 4) == 4) { - if (memcmp(magic, "\177ELF", 4) == 0) { - (void)close(fd); - error("Cannot execute ELF binary %s", fname); - } - } - if (lseek(fd, 0, SEEK_SET) != 0) { - (void)close(fd); - error("Cannot rewind the file %s", fname); - } - } - - fd2 = to_upper_fd(fd); /* closes fd, returns higher equiv */ - if (fd2 == fd) { - (void) close(fd); - error("Out of file descriptors"); - } - - setinputfd(fd2, push); - INTON; -} - -/* - * When a shell fd needs to be altered (when the user wants to use - * the same fd - rare, but happens - we need to locate the ref to - * the fd, and update it. This happens via a callback. - * This is the callback func for fd's used for shell input - */ -static void -input_fd_swap(int from, int to) -{ - struct parsefile *pf; - - pf = parsefile; - while (pf != NULL) { /* don't need to stop at basepf */ - if (pf->fd == from) - pf->fd = to; - pf = pf->prev; - } -} - -/* - * Like setinputfile, but takes an open file descriptor. Call this with - * interrupts off. - */ - -void -setinputfd(int fd, int push) -{ - VTRACE(DBG_INPUT, ("setinputfd(%d, %spush)\n", fd, push?"":"no")); - - register_sh_fd(fd, input_fd_swap); - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); - if (push) - pushfile(); - if (parsefile->fd > 0) - sh_close(parsefile->fd); - parsefile->fd = fd; - if (parsefile->buf == NULL) - parsefile->buf = ckmalloc(BUFSIZ); - parselleft = parsenleft = 0; - plinno = 1; - - CTRACE(DBG_INPUT, ("setinputfd(%d, %spush) done; plinno=1\n", fd, - push ? "" : "no")); -} - - -/* - * Like setinputfile, but takes input from a string. - */ - -void -setinputstring(char *string, int push, int line1) -{ - - INTOFF; - if (push) /* XXX: always, as it happens */ - pushfile(); - parsenextc = string; - parselleft = parsenleft = strlen(string); - plinno = line1; - - CTRACE(DBG_INPUT, - ("setinputstring(\"%.20s%s\" (%d), %spush, @ %d)\n", string, - (parsenleft > 20 ? "..." : ""), parsenleft, push?"":"no", line1)); - INTON; -} - - - -/* - * To handle the "." command, a stack of input files is used. Pushfile - * adds a new entry to the stack and popfile restores the previous level. - */ - -STATIC void -pushfile(void) -{ - struct parsefile *pf; - - VTRACE(DBG_INPUT, - ("pushfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno=%d\n", - parsefile->fd, parsefile->buf, parsenleft, parselleft, - parsenleft, parsenextc, plinno)); - - parsefile->nleft = parsenleft; - parsefile->lleft = parselleft; - parsefile->nextc = parsenextc; - parsefile->linno = plinno; - pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); - pf->prev = parsefile; - pf->fd = -1; - pf->strpush = NULL; - pf->basestrpush.prev = NULL; - pf->buf = NULL; - parsefile = pf; -} - - -void -popfile(void) -{ - struct parsefile *pf = parsefile; - - INTOFF; - if (pf->fd >= 0) - sh_close(pf->fd); - if (pf->buf) - ckfree(pf->buf); - while (pf->strpush) - popstring(); - parsefile = pf->prev; - ckfree(pf); - parsenleft = parsefile->nleft; - parselleft = parsefile->lleft; - parsenextc = parsefile->nextc; - - VTRACE(DBG_INPUT, - ("popfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno:%d->%d\n", - parsefile->fd, parsefile->buf, parsenleft, parselleft, - parsenleft, parsenextc, plinno, parsefile->linno)); - - plinno = parsefile->linno; - INTON; -} - -/* - * Return current file (to go back to it later using popfilesupto()). - */ - -struct parsefile * -getcurrentfile(void) -{ - return parsefile; -} - - -/* - * Pop files until the given file is on top again. Useful for regular - * builtins that read shell commands from files or strings. - * If the given file is not an active file, an error is raised. - */ - -void -popfilesupto(struct parsefile *file) -{ - while (parsefile != file && parsefile != &basepf) - popfile(); - if (parsefile != file) - error("popfilesupto() misused"); -} - - -/* - * Return to top level. - */ - -void -popallfiles(void) -{ - while (parsefile != &basepf) - popfile(); -} - - - -/* - * Close the file(s) that the shell is reading commands from. Called - * after a fork is done. - * - * Takes one arg, vfork, which tells it to not modify its global vars - * as it is still running in the parent. - * - * This code is (probably) unnecessary as the 'close on exec' flag is - * set and should be enough. In the vfork case it is definitely wrong - * to close the fds as another fork() may be done later to feed data - * from a 'here' document into a pipe and we don't want to close the - * pipe! - */ - -void -closescript(int vforked) -{ - if (vforked) - return; - popallfiles(); - if (parsefile->fd > 0) { - sh_close(parsefile->fd); - parsefile->fd = 0; - } -} |