386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 1 Jul 1991 07:17:40 +0000 (23:17 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 1 Jul 1991 07:17:40 +0000 (23:17 -0800)
Work on file usr/src/bin/sh/input.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/src/bin/sh/input.c [new file with mode: 0644]

diff --git a/usr/src/bin/sh/input.c b/usr/src/bin/sh/input.c
new file mode 100644 (file)
index 0000000..ebcde97
--- /dev/null
@@ -0,0 +1,381 @@
+/*-
+ * Copyright (c) 1991 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)input.c    5.4 (Berkeley) 7/1/91";
+#endif /* not lint */
+
+/*
+ * This file implements the input routines used by the parser.
+ */
+
+#include <stdio.h>     /* defines BUFSIZ */
+#include "shell.h"
+#include <fcntl.h>
+#include <errno.h>
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+
+#define EOF_NLEFT -99          /* value of parsenleft when EOF pushed back */
+
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+MKINIT
+struct parsefile {
+       int linno;              /* current line */
+       int fd;                 /* file descriptor (or -1 if string) */
+       int nleft;              /* number of chars left in buffer */
+       char *nextc;            /* next char in buffer */
+       struct parsefile *prev; /* preceding file on stack */
+       char *buf;              /* input buffer */
+};
+
+
+int plinno = 1;                        /* input line number */
+MKINIT int parsenleft;         /* copy of parsefile->nleft */
+char *parsenextc;              /* copy of parsefile->nextc */
+MKINIT struct parsefile basepf;        /* top level input file */
+char basebuf[BUFSIZ];          /* buffer for top level input file */
+struct parsefile *parsefile = &basepf; /* current input file */
+char *pushedstring;            /* copy of parsenextc when text pushed back */
+int pushednleft;               /* copy of parsenleft when text pushed back */
+
+#ifdef __STDC__
+STATIC void pushfile(void);
+#else
+STATIC void pushfile();
+#endif
+
+
+
+#ifdef mkinit
+INCLUDE "input.h"
+INCLUDE "error.h"
+
+INIT {
+       extern char basebuf[];
+
+       basepf.nextc = basepf.buf = basebuf;
+}
+
+RESET {
+       if (exception != EXSHELLPROC)
+               parsenleft = 0;            /* clear input buffer */
+       popallfiles();
+}
+
+SHELLPROC {
+       popallfiles();
+}
+#endif
+
+
+/*
+ * Read a line from the script.
+ */
+
+char *
+pfgets(line, len)
+       char *line;
+       {
+       register char *p = line;
+       int nleft = len;
+       int c;
+
+       while (--nleft > 0) {
+               c = pgetc_macro();
+               if (c == PEOF) {
+                       if (p == line)
+                               return NULL;
+                       break;
+               }
+               *p++ = c;
+               if (c == '\n')
+                       break;
+       }
+       *p = '\0';
+       return line;
+}
+
+
+
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+int
+pgetc() {
+       return pgetc_macro();
+}
+
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, switch back to the regular
+ *    buffer.
+ * 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) Call read to read in the characters.
+ * 4) Delete all nul characters from the buffer.
+ */
+
+int
+preadbuffer() {
+       register char *p, *q;
+       register int i;
+
+       if (pushedstring) {
+               parsenextc = pushedstring;
+               pushedstring = NULL;
+               parsenleft = pushednleft;
+               if (--parsenleft >= 0)
+                       return *parsenextc++;
+       }
+       if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+               return PEOF;
+       flushout(&output);
+       flushout(&errout);
+retry:
+       p = parsenextc = parsefile->buf;
+       i = read(parsefile->fd, p, BUFSIZ);
+       if (i <= 0) {
+                if (i < 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;
+                                        }
+                                }
+                        }
+                }
+                parsenleft = EOF_NLEFT;
+                return PEOF;
+       }
+       parsenleft = i - 1;
+
+       /* delete nul characters */
+       for (;;) {
+               if (*p++ == '\0')
+                       break;
+               if (--i <= 0)
+                       return *parsenextc++;           /* no nul characters */
+       }
+       q = p - 1;
+       while (--i > 0) {
+               if (*p != '\0')
+                       *q++ = *p;
+               p++;
+       }
+       if (q == parsefile->buf)
+               goto retry;                     /* buffer contained nothing but nuls */
+       parsenleft = q - parsefile->buf - 1;
+       return *parsenextc++;
+}
+
+
+/*
+ * Undo the last call to pgetc.  Only one character may be pushed back.
+ * PEOF may be pushed back.
+ */
+
+void
+pungetc() {
+       parsenleft++;
+       parsenextc--;
+}
+
+
+/*
+ * Push a string back onto the input.  This code doesn't work if the user
+ * tries to push back more than one string at once.
+ */
+
+void
+ppushback(string, length)
+       char *string;
+       {
+       pushedstring = parsenextc;
+       pushednleft = parsenleft;
+       parsenextc = string;
+       parsenleft = length;
+}
+
+
+
+/*
+ * Set the input to take input from a file.  If push is set, push the
+ * old input onto the stack first.
+ */
+
+void
+setinputfile(fname, push)
+       char *fname;
+       {
+       int fd;
+       int fd2;
+
+       INTOFF;
+       if ((fd = open(fname, O_RDONLY)) < 0)
+               error("Can't open %s", fname);
+       if (fd < 10) {
+               fd2 = copyfd(fd, 10);
+               close(fd);
+               if (fd2 < 0)
+                       error("Out of file descriptors");
+               fd = fd2;
+       }
+       setinputfd(fd, push);
+       INTON;
+}
+
+
+/*
+ * Like setinputfile, but takes an open file descriptor.  Call this with
+ * interrupts off.
+ */
+
+void
+setinputfd(fd, push) {
+       if (push) {
+               pushfile();
+               parsefile->buf = ckmalloc(BUFSIZ);
+       }
+       if (parsefile->fd > 0)
+               close(parsefile->fd);
+       parsefile->fd = fd;
+       if (parsefile->buf == NULL)
+               parsefile->buf = ckmalloc(BUFSIZ);
+       parsenleft = 0;
+       plinno = 1;
+}
+
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+
+void
+setinputstring(string, push)
+       char *string;
+       {
+       INTOFF;
+       if (push)
+               pushfile();
+       parsenextc = string;
+       parsenleft = strlen(string);
+       parsefile->buf = NULL;
+       plinno = 1;
+       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() {
+       struct parsefile *pf;
+
+       parsefile->nleft = parsenleft;
+       parsefile->nextc = parsenextc;
+       parsefile->linno = plinno;
+       pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
+       pf->prev = parsefile;
+       pf->fd = -1;
+       parsefile = pf;
+}
+
+
+void
+popfile() {
+       struct parsefile *pf = parsefile;
+
+       INTOFF;
+       if (pf->fd >= 0)
+               close(pf->fd);
+       if (pf->buf)
+               ckfree(pf->buf);
+       parsefile = pf->prev;
+       ckfree(pf);
+       parsenleft = parsefile->nleft;
+       parsenextc = parsefile->nextc;
+       plinno = parsefile->linno;
+       INTON;
+}
+
+
+/*
+ * Return to top level.
+ */
+
+void
+popallfiles() {
+       while (parsefile != &basepf)
+               popfile();
+}
+
+
+
+/*
+ * Close the file(s) that the shell is reading commands from.  Called
+ * after a fork is done.
+ */
+
+void
+closescript() {
+       popallfiles();
+       if (parsefile->fd > 0) {
+               close(parsefile->fd);
+               parsefile->fd = 0;
+       }
+}