Subversion Repositories HelenOS

Rev

Rev 2714 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*  $NetBSD: input.c,v 1.34 2000/05/22 10:18:47 elric Exp $ */
  2.  
  3. /*-
  4.  * Copyright (c) 1991, 1993
  5.  *  The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * Kenneth Almquist.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions
  12.  * are met:
  13.  * 1. Redistributions of source code must retain the above copyright
  14.  *    notice, this list of conditions and the following disclaimer.
  15.  * 2. Redistributions in binary form must reproduce the above copyright
  16.  *    notice, this list of conditions and the following disclaimer in the
  17.  *    documentation and/or other materials provided with the distribution.
  18.  * 3. All advertising materials mentioning features or use of this software
  19.  *    must display the following acknowledgement:
  20.  *  This product includes software developed by the University of
  21.  *  California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38.  
  39. #include <sys/cdefs.h>
  40. #ifndef lint
  41. #if 0
  42. static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
  43. #else
  44. __RCSID("$NetBSD: input.c,v 1.34 2000/05/22 10:18:47 elric Exp $");
  45. #endif
  46. #endif /* not lint */
  47.  
  48. #include <stdio.h>  /* defines BUFSIZ */
  49. #include <fcntl.h>
  50. #include <errno.h>
  51. #include <unistd.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54.  
  55. /*
  56.  * This file implements the input routines used by the parser.
  57.  */
  58.  
  59. #include "shell.h"
  60. #include "redir.h"
  61. #include "syntax.h"
  62. #include "input.h"
  63. #include "output.h"
  64. #include "options.h"
  65. #include "memalloc.h"
  66. #include "error.h"
  67. #include "alias.h"
  68. #include "parser.h"
  69. #ifndef SMALL
  70. #include "myhistedit.h"
  71. #endif
  72.  
  73. #ifdef HETIO
  74. #include "hetio.h"
  75. #endif
  76.  
  77. #define EOF_NLEFT -99       /* value of parsenleft when EOF pushed back */
  78.  
  79. MKINIT
  80. struct strpush {
  81.     struct strpush *prev;   /* preceding string on stack */
  82.     char *prevstring;
  83.     int prevnleft;
  84.     int prevlleft;
  85.     struct alias *ap;   /* if push was associated with an alias */
  86. };
  87.  
  88. /*
  89.  * The parsefile structure pointed to by the global variable parsefile
  90.  * contains information about the current file being read.
  91.  */
  92.  
  93. MKINIT
  94. struct parsefile {
  95.     struct parsefile *prev; /* preceding file on stack */
  96.     int linno;      /* current line */
  97.     int fd;         /* file descriptor (or -1 if string) */
  98.     int nleft;      /* number of chars left in this line */
  99.     int lleft;      /* number of chars left in this buffer */
  100.     char *nextc;        /* next char in buffer */
  101.     char *buf;      /* input buffer */
  102.     struct strpush *strpush; /* for pushing strings at this level */
  103.     struct strpush basestrpush; /* so pushing one is fast */
  104. };
  105.  
  106.  
  107. int plinno = 1;         /* input line number */
  108. MKINIT int parsenleft;      /* copy of parsefile->nleft */
  109. MKINIT int parselleft;      /* copy of parsefile->lleft */
  110. char *parsenextc;       /* copy of parsefile->nextc */
  111. MKINIT struct parsefile basepf; /* top level input file */
  112. char basebuf[BUFSIZ];       /* buffer for top level input file */
  113. struct parsefile *parsefile = &basepf;  /* current input file */
  114. int init_editline = 0;      /* editline library initialized? */
  115. int whichprompt;        /* 1 == PS1, 2 == PS2 */
  116.  
  117. #ifndef SMALL
  118. EditLine *el;           /* cookie for editline package */
  119. #endif
  120.  
  121. STATIC void pushfile (void);
  122. static int preadfd (void);
  123.  
  124. #ifdef mkinit
  125. INCLUDE "input.h"
  126. INCLUDE "error.h"
  127.  
  128. INIT {
  129.     extern char basebuf[];
  130.  
  131.     basepf.nextc = basepf.buf = basebuf;
  132. }
  133.  
  134. RESET {
  135.     if (exception != EXSHELLPROC)
  136.         parselleft = parsenleft = 0;    /* clear input buffer */
  137.     popallfiles();
  138. }
  139.  
  140. SHELLPROC {
  141.     popallfiles();
  142. }
  143. #endif
  144.  
  145.  
  146. /*
  147.  * Read a line from the script.
  148.  */
  149.  
  150. char *
  151. pfgets(line, len)
  152.     char *line;
  153.     int len;
  154. {
  155.     char *p = line;
  156.     int nleft = len;
  157.     int c;
  158.  
  159.     while (--nleft > 0) {
  160.         c = pgetc_macro();
  161.         if (c == PEOF) {
  162.             if (p == line)
  163.                 return NULL;
  164.             break;
  165.         }
  166.         *p++ = c;
  167.         if (c == '\n')
  168.             break;
  169.     }
  170.     *p = '\0';
  171.     return line;
  172. }
  173.  
  174.  
  175.  
  176. /*
  177.  * Read a character from the script, returning PEOF on end of file.
  178.  * Nul characters in the input are silently discarded.
  179.  */
  180.  
  181. int
  182. pgetc()
  183. {
  184.     return pgetc_macro();
  185. }
  186.  
  187.  
  188. static int
  189. preadfd()
  190. {
  191.     int nr;
  192.     char *buf =  parsefile->buf;
  193.     parsenextc = buf;
  194.  
  195. retry:
  196. #ifndef SMALL
  197.     if (parsefile->fd == 0 && el) {
  198.         const char *rl_cp;
  199.  
  200.         rl_cp = el_gets(el, &nr);
  201.         if (rl_cp == NULL)
  202.             nr = 0;
  203.         else {
  204.             /* XXX - BUFSIZE should redesign so not necessary */
  205.             (void) strcpy(buf, rl_cp);
  206.         }
  207.     } else
  208. #endif
  209.  
  210. #ifdef HETIO
  211.         nr = hetio_read_input(parsefile->fd);
  212.         if (nr == -255)
  213. #endif
  214.         nr = read(parsefile->fd, buf, BUFSIZ - 1);
  215.  
  216.  
  217.     if (nr <= 0) {
  218.                 if (nr < 0) {
  219.                         if (errno == EINTR)
  220.                                 goto retry;
  221.                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
  222.                                 int flags = fcntl(0, F_GETFL, 0);
  223.                                 if (flags >= 0 && flags & O_NONBLOCK) {
  224.                                         flags &=~ O_NONBLOCK;
  225.                                         if (fcntl(0, F_SETFL, flags) >= 0) {
  226.                         out2str("sh: turning off NDELAY mode\n");
  227.                                                 goto retry;
  228.                                         }
  229.                                 }
  230.                         }
  231.                 }
  232.                 nr = -1;
  233.     }
  234.     return nr;
  235. }
  236.  
  237. /*
  238.  * Refill the input buffer and return the next input character:
  239.  *
  240.  * 1) If a string was pushed back on the input, pop it;
  241.  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
  242.  *    from a string so we can't refill the buffer, return EOF.
  243.  * 3) If the is more stuff in this buffer, use it else call read to fill it.
  244.  * 4) Process input up to the next newline, deleting nul characters.
  245.  */
  246.  
  247. int
  248. preadbuffer()
  249. {
  250.     char *p, *q;
  251.     int more;
  252.     int something;
  253.     char savec;
  254.  
  255.     if (parsefile->strpush) {
  256.         popstring();
  257.         if (--parsenleft >= 0)
  258.             return (*parsenextc++);
  259.     }
  260.     if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
  261.         return PEOF;
  262.     flushout(&output);
  263.     flushout(&errout);
  264.  
  265. again:
  266.     if (parselleft <= 0) {
  267.         if ((parselleft = preadfd()) == -1) {
  268.             parselleft = parsenleft = EOF_NLEFT;
  269.             return PEOF;
  270.         }
  271.     }
  272.  
  273.     q = p = parsenextc;
  274.  
  275.     /* delete nul characters */
  276.     something = 0;
  277.     for (more = 1; more;) {
  278.         switch (*p) {
  279.         case '\0':
  280.             p++;    /* Skip nul */
  281.             goto check;
  282.  
  283.         case '\t':
  284.         case ' ':
  285.             break;
  286.  
  287.         case '\n':
  288.             parsenleft = q - parsenextc;
  289.             more = 0; /* Stop processing here */
  290.             break;
  291.  
  292.         default:
  293.             something = 1;
  294.             break;
  295.         }
  296.  
  297.         *q++ = *p++;
  298. check:
  299.         if (--parselleft <= 0) {
  300.             parsenleft = q - parsenextc - 1;
  301.             if (parsenleft < 0)
  302.                 goto again;
  303.             *q = '\0';
  304.             more = 0;
  305.         }
  306.     }
  307.  
  308.     savec = *q;
  309.     *q = '\0';
  310.  
  311. #ifndef SMALL
  312.     if (parsefile->fd == 0 && hist && something) {
  313.         HistEvent he;
  314.         INTOFF;
  315.         history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
  316.             parsenextc);
  317.         INTON;
  318.     }
  319. #endif
  320.  
  321.     if (vflag) {
  322.         out2str(parsenextc);
  323.         flushout(out2);
  324.     }
  325.  
  326.     *q = savec;
  327.  
  328.     return *parsenextc++;
  329. }
  330.  
  331. /*
  332.  * Undo the last call to pgetc.  Only one character may be pushed back.
  333.  * PEOF may be pushed back.
  334.  */
  335.  
  336. void
  337. pungetc() {
  338.     parsenleft++;
  339.     parsenextc--;
  340. }
  341.  
  342. /*
  343.  * Push a string back onto the input at this current parsefile level.
  344.  * We handle aliases this way.
  345.  */
  346. void
  347. pushstring(s, len, ap)
  348.     char *s;
  349.     int len;
  350.     void *ap;
  351.     {
  352.     struct strpush *sp;
  353.  
  354.     INTOFF;
  355. /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
  356.     if (parsefile->strpush) {
  357.         sp = ckmalloc(sizeof (struct strpush));
  358.         sp->prev = parsefile->strpush;
  359.         parsefile->strpush = sp;
  360.     } else
  361.         sp = parsefile->strpush = &(parsefile->basestrpush);
  362.     sp->prevstring = parsenextc;
  363.     sp->prevnleft = parsenleft;
  364.     sp->prevlleft = parselleft;
  365.     sp->ap = (struct alias *)ap;
  366.     if (ap)
  367.         ((struct alias *)ap)->flag |= ALIASINUSE;
  368.     parsenextc = s;
  369.     parsenleft = len;
  370.     INTON;
  371. }
  372.  
  373. void
  374. popstring()
  375. {
  376.     struct strpush *sp = parsefile->strpush;
  377.  
  378.     INTOFF;
  379.     parsenextc = sp->prevstring;
  380.     parsenleft = sp->prevnleft;
  381.     parselleft = sp->prevlleft;
  382. /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
  383.     if (sp->ap)
  384.         sp->ap->flag &= ~ALIASINUSE;
  385.     parsefile->strpush = sp->prev;
  386.     if (sp != &(parsefile->basestrpush))
  387.         ckfree(sp);
  388.     INTON;
  389. }
  390.  
  391. /*
  392.  * Set the input to take input from a file.  If push is set, push the
  393.  * old input onto the stack first.
  394.  */
  395.  
  396. void
  397. setinputfile(fname, push)
  398.     const char *fname;
  399.     int push;
  400. {
  401.     int fd;
  402.     int fd2;
  403.  
  404.     INTOFF;
  405.     if ((fd = open(fname, O_RDONLY)) < 0)
  406.         error("Can't open %s", fname);
  407.     if (fd < 10) {
  408.         fd2 = copyfd(fd, 10);
  409.         close(fd);
  410.         if (fd2 < 0)
  411.             error("Out of file descriptors");
  412.         fd = fd2;
  413.     }
  414.     setinputfd(fd, push);
  415.     INTON;
  416. }
  417.  
  418.  
  419. /*
  420.  * Like setinputfile, but takes an open file descriptor.  Call this with
  421.  * interrupts off.
  422.  */
  423.  
  424. void
  425. setinputfd(fd, push)
  426.     int fd, push;
  427. {
  428.     (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
  429.     if (push) {
  430.         pushfile();
  431.         parsefile->buf = ckmalloc(BUFSIZ);
  432.     }
  433.     if (parsefile->fd > 0)
  434.         close(parsefile->fd);
  435.     parsefile->fd = fd;
  436.     if (parsefile->buf == NULL)
  437.         parsefile->buf = ckmalloc(BUFSIZ);
  438.     parselleft = parsenleft = 0;
  439.     plinno = 1;
  440. }
  441.  
  442.  
  443. /*
  444.  * Like setinputfile, but takes input from a string.
  445.  */
  446.  
  447. void
  448. setinputstring(string, push)
  449.     char *string;
  450.     int push;
  451.     {
  452.     INTOFF;
  453.     if (push)
  454.         pushfile();
  455.     parsenextc = string;
  456.     parselleft = parsenleft = strlen(string);
  457.     parsefile->buf = NULL;
  458.     plinno = 1;
  459.     INTON;
  460. }
  461.  
  462.  
  463.  
  464. /*
  465.  * To handle the "." command, a stack of input files is used.  Pushfile
  466.  * adds a new entry to the stack and popfile restores the previous level.
  467.  */
  468.  
  469. STATIC void
  470. pushfile() {
  471.     struct parsefile *pf;
  472.  
  473.     parsefile->nleft = parsenleft;
  474.     parsefile->lleft = parselleft;
  475.     parsefile->nextc = parsenextc;
  476.     parsefile->linno = plinno;
  477.     pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
  478.     pf->prev = parsefile;
  479.     pf->fd = -1;
  480.     pf->strpush = NULL;
  481.     pf->basestrpush.prev = NULL;
  482.     parsefile = pf;
  483. }
  484.  
  485.  
  486. void
  487. popfile() {
  488.     struct parsefile *pf = parsefile;
  489.  
  490.     INTOFF;
  491.     if (pf->fd >= 0)
  492.         close(pf->fd);
  493.     if (pf->buf)
  494.         ckfree(pf->buf);
  495.     while (pf->strpush)
  496.         popstring();
  497.     parsefile = pf->prev;
  498.     ckfree(pf);
  499.     parsenleft = parsefile->nleft;
  500.     parselleft = parsefile->lleft;
  501.     parsenextc = parsefile->nextc;
  502.     plinno = parsefile->linno;
  503.     INTON;
  504. }
  505.  
  506.  
  507. /*
  508.  * Return to top level.
  509.  */
  510.  
  511. void
  512. popallfiles() {
  513.     while (parsefile != &basepf)
  514.         popfile();
  515. }
  516.  
  517.  
  518.  
  519. /*
  520.  * Close the file(s) that the shell is reading commands from.  Called
  521.  * after a fork is done.
  522.  */
  523.  
  524. void
  525. closescript() {
  526.     popallfiles();
  527.     if (parsefile->fd > 0) {
  528.         close(parsefile->fd);
  529.         parsefile->fd = 0;
  530.     }
  531. }
  532.