home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / ash02emx.zip / input.c < prev    next >
C/C++ Source or Header  |  1997-12-25  |  9KB  |  383 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * 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.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. /*static char sccsid[] = "from: @(#)input.c    5.4 (Berkeley) 7/1/91";*/
  39. static char rcsid[] = "input.c,v 1.4 1993/08/01 18:58:15 mycroft Exp";
  40. #endif /* not lint */
  41.  
  42. /*
  43.  * This file implements the input routines used by the parser.
  44.  */
  45.  
  46. #include <stdio.h>    /* defines BUFSIZ */
  47. #include "shell.h"
  48. #include <fcntl.h>
  49. #include <errno.h>
  50. #include "syntax.h"
  51. #include "input.h"
  52. #include "output.h"
  53. #include "memalloc.h"
  54. #include "error.h"
  55.  
  56. #define EOF_NLEFT -99        /* value of parsenleft when EOF pushed back */
  57.  
  58.  
  59. /*
  60.  * The parsefile structure pointed to by the global variable parsefile
  61.  * contains information about the current file being read.
  62.  */
  63.  
  64. MKINIT
  65. struct parsefile {
  66.     int linno;        /* current line */
  67.     int fd;            /* file descriptor (or -1 if string) */
  68.     int nleft;        /* number of chars left in buffer */
  69.     char *nextc;        /* next char in buffer */
  70.     struct parsefile *prev;    /* preceding file on stack */
  71.     char *buf;        /* input buffer */
  72. };
  73.  
  74.  
  75. int plinno = 1;            /* input line number */
  76. MKINIT int parsenleft;        /* copy of parsefile->nleft */
  77. char *parsenextc;        /* copy of parsefile->nextc */
  78. MKINIT struct parsefile basepf;    /* top level input file */
  79. char basebuf[BUFSIZ];        /* buffer for top level input file */
  80. struct parsefile *parsefile = &basepf;    /* current input file */
  81. char *pushedstring;        /* copy of parsenextc when text pushed back */
  82. int pushednleft;        /* copy of parsenleft when text pushed back */
  83.  
  84. #ifdef __STDC__
  85. STATIC void pushfile(void);
  86. #else
  87. STATIC void pushfile();
  88. #endif
  89.  
  90.  
  91.  
  92. #ifdef mkinit
  93. INCLUDE "input.h"
  94. INCLUDE "error.h"
  95.  
  96. INIT {
  97.     extern char basebuf[];
  98.  
  99.     basepf.nextc = basepf.buf = basebuf;
  100. }
  101.  
  102. RESET {
  103.     if (exception != EXSHELLPROC)
  104.         parsenleft = 0;            /* clear input buffer */
  105.     popallfiles();
  106. }
  107.  
  108. SHELLPROC {
  109.     popallfiles();
  110. }
  111. #endif
  112.  
  113.  
  114. /*
  115.  * Read a line from the script.
  116.  */
  117.  
  118. char *
  119. pfgets(line, len)
  120.     char *line;
  121.     {
  122.     register char *p = line;
  123.     int nleft = len;
  124.     int c;
  125.  
  126.     while (--nleft > 0) {
  127.         c = pgetc_macro();
  128.         if (c == PEOF) {
  129.             if (p == line)
  130.                 return NULL;
  131.             break;
  132.         }
  133.         *p++ = c;
  134.         if (c == '\n')
  135.             break;
  136.     }
  137.     *p = '\0';
  138.     return line;
  139. }
  140.  
  141.  
  142.  
  143. /*
  144.  * Read a character from the script, returning PEOF on end of file.
  145.  * Nul characters in the input are silently discarded.
  146.  */
  147.  
  148. int
  149. pgetc() {
  150.     return pgetc_macro();
  151. }
  152.  
  153.  
  154. /*
  155.  * Refill the input buffer and return the next input character:
  156.  *
  157.  * 1) If a string was pushed back on the input, switch back to the regular
  158.  *    buffer.
  159.  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
  160.  *    from a string so we can't refill the buffer, return EOF.
  161.  * 3) Call read to read in the characters.
  162.  * 4) Delete all nul characters from the buffer.
  163.  */
  164.  
  165. int
  166. preadbuffer() {
  167.     register char *p, *q;
  168.     register int i;
  169.  
  170.     if (pushedstring) {
  171.         parsenextc = pushedstring;
  172.         pushedstring = NULL;
  173.         parsenleft = pushednleft;
  174.         if (--parsenleft >= 0)
  175.             return *parsenextc++;
  176.     }
  177.     if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
  178.         return PEOF;
  179.     flushout(&output);
  180.     flushout(&errout);
  181. retry:
  182.     p = parsenextc = parsefile->buf;
  183.     i = read(parsefile->fd, p, BUFSIZ);
  184.     if (i <= 0) {
  185.                 if (i < 0) {
  186.                         if (errno == EINTR)
  187.                                 goto retry;
  188.                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
  189.                                 int flags = fcntl(0, F_GETFL, 0);
  190.                                 if (flags >= 0 && flags & O_NONBLOCK) {
  191.                                         flags &=~ O_NONBLOCK;
  192.                                         if (fcntl(0, F_SETFL, flags) >= 0) {
  193.                         out2str("sh: turning off NDELAY mode\n");
  194.                                                 goto retry;
  195.                                         }
  196.                                 }
  197.                         }
  198.                 }
  199.                 parsenleft = EOF_NLEFT;
  200.                 return PEOF;
  201.     }
  202.     parsenleft = i - 1;
  203.  
  204.     /* delete nul characters */
  205.     for (;;) {
  206.         if (*p++ == '\0')
  207.             break;
  208.         if (--i <= 0)
  209.             return *parsenextc++;        /* no nul characters */
  210.     }
  211.     q = p - 1;
  212.     while (--i > 0) {
  213.         if (*p != '\0')
  214.             *q++ = *p;
  215.         p++;
  216.     }
  217.     if (q == parsefile->buf)
  218.         goto retry;            /* buffer contained nothing but nuls */
  219.     parsenleft = q - parsefile->buf - 1;
  220.     return *parsenextc++;
  221. }
  222.  
  223.  
  224. /*
  225.  * Undo the last call to pgetc.  Only one character may be pushed back.
  226.  * PEOF may be pushed back.
  227.  */
  228.  
  229. void
  230. pungetc() {
  231.     parsenleft++;
  232.     parsenextc--;
  233. }
  234.  
  235.  
  236. /*
  237.  * Push a string back onto the input.  This code doesn't work if the user
  238.  * tries to push back more than one string at once.
  239.  */
  240.  
  241. void
  242. ppushback(string, length)
  243.     char *string;
  244.     {
  245.     pushedstring = parsenextc;
  246.     pushednleft = parsenleft;
  247.     parsenextc = string;
  248.     parsenleft = length;
  249. }
  250.  
  251.  
  252.  
  253. /*
  254.  * Set the input to take input from a file.  If push is set, push the
  255.  * old input onto the stack first.
  256.  */
  257.  
  258. void
  259. setinputfile(fname, push)
  260.     char *fname;
  261.     {
  262.     int fd;
  263.     int fd2;
  264.  
  265.     INTOFF;
  266.     if ((fd = open(fname, O_RDONLY)) < 0)
  267.         error("Can't open %s", fname);
  268.     if (fd < 10) {
  269.         fd2 = copyfd(fd, 10);
  270.         close(fd);
  271.         if (fd2 < 0)
  272.             error("Out of file descriptors");
  273.         fd = fd2;
  274.     }
  275.     setinputfd(fd, push);
  276.     INTON;
  277. }
  278.  
  279.  
  280. /*
  281.  * Like setinputfile, but takes an open file descriptor.  Call this with
  282.  * interrupts off.
  283.  */
  284.  
  285. void
  286. setinputfd(fd, push) {
  287.     if (push) {
  288.         pushfile();
  289.         parsefile->buf = ckmalloc(BUFSIZ);
  290.     }
  291.     if (parsefile->fd > 0)
  292.         close(parsefile->fd);
  293.     parsefile->fd = fd;
  294.     if (parsefile->buf == NULL)
  295.         parsefile->buf = ckmalloc(BUFSIZ);
  296.     parsenleft = 0;
  297.     plinno = 1;
  298. }
  299.  
  300.  
  301. /*
  302.  * Like setinputfile, but takes input from a string.
  303.  */
  304.  
  305. void
  306. setinputstring(string, push)
  307.     char *string;
  308.     {
  309.     INTOFF;
  310.     if (push)
  311.         pushfile();
  312.     parsenextc = string;
  313.     parsenleft = strlen(string);
  314.     parsefile->buf = NULL;
  315.     plinno = 1;
  316.     INTON;
  317. }
  318.  
  319.  
  320.  
  321. /*
  322.  * To handle the "." command, a stack of input files is used.  Pushfile
  323.  * adds a new entry to the stack and popfile restores the previous level.
  324.  */
  325.  
  326. STATIC void
  327. pushfile() {
  328.     struct parsefile *pf;
  329.  
  330.     parsefile->nleft = parsenleft;
  331.     parsefile->nextc = parsenextc;
  332.     parsefile->linno = plinno;
  333.     pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
  334.     pf->prev = parsefile;
  335.     pf->fd = -1;
  336.     parsefile = pf;
  337. }
  338.  
  339.  
  340. void
  341. popfile() {
  342.     struct parsefile *pf = parsefile;
  343.  
  344.     INTOFF;
  345.     if (pf->fd >= 0)
  346.         close(pf->fd);
  347.     if (pf->buf)
  348.         ckfree(pf->buf);
  349.     parsefile = pf->prev;
  350.     ckfree(pf);
  351.     parsenleft = parsefile->nleft;
  352.     parsenextc = parsefile->nextc;
  353.     plinno = parsefile->linno;
  354.     INTON;
  355. }
  356.  
  357.  
  358. /*
  359.  * Return to top level.
  360.  */
  361.  
  362. void
  363. popallfiles() {
  364.     while (parsefile != &basepf)
  365.         popfile();
  366. }
  367.  
  368.  
  369.  
  370. /*
  371.  * Close the file(s) that the shell is reading commands from.  Called
  372.  * after a fork is done.
  373.  */
  374.  
  375. void
  376. closescript() {
  377.     popallfiles();
  378.     if (parsefile->fd > 0) {
  379.         close(parsefile->fd);
  380.         parsefile->fd = 0;
  381.     }
  382. }
  383.