input.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 static char sccsid[] = "@(#)input.c     5.4 (Berkeley) 7/1/91";
00039 #endif /* not lint */
00040 
00041 /*
00042  * This file implements the input routines used by the parser.
00043  */
00044 
00045 #include <sys/types.h>
00046 #include <stdio.h>      /* defines BUFSIZ */
00047 #include "shell.h"
00048 #include <fcntl.h>
00049 #include <errno.h>
00050 #include "syntax.h"
00051 #include "input.h"
00052 #include "output.h"
00053 #include "memalloc.h"
00054 #include "error.h"
00055 
00056 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
00057 
00058 
00059 /*
00060  * The parsefile structure pointed to by the global variable parsefile
00061  * contains information about the current file being read.
00062  */
00063 
00064 MKINIT
00065 struct parsefile {
00066         int linno;              /* current line */
00067         int fd;                 /* file descriptor (or -1 if string) */
00068         int nleft;              /* number of chars left in buffer */
00069         char *nextc;            /* next char in buffer */
00070         struct parsefile *prev; /* preceding file on stack */
00071         char *buf;              /* input buffer */
00072 };
00073 
00074 
00075 int plinno = 1;                 /* input line number */
00076 MKINIT int parsenleft;          /* copy of parsefile->nleft */
00077 char *parsenextc;               /* copy of parsefile->nextc */
00078 MKINIT struct parsefile basepf; /* top level input file */
00079 char basebuf[BUFSIZ];           /* buffer for top level input file */
00080 struct parsefile *parsefile = &basepf;  /* current input file */
00081 char *pushedstring;             /* copy of parsenextc when text pushed back */
00082 int pushednleft;                /* copy of parsenleft when text pushed back */
00083 
00084 #if READLINE
00085 char *readline __P((const char *prompt));
00086 char *r_use_prompt = NULL;      /* the prompt to use with readline */
00087 #endif
00088 
00089 #ifdef __STDC__
00090 STATIC void pushfile(void);
00091 #else
00092 STATIC void pushfile();
00093 #endif
00094 
00095 
00096 
00097 #ifdef mkinit
00098 INCLUDE "input.h"
00099 INCLUDE "error.h"
00100 
00101 INIT {
00102         extern char basebuf[];
00103 
00104         basepf.nextc = basepf.buf = basebuf;
00105 }
00106 
00107 RESET {
00108         if (exception != EXSHELLPROC)
00109                 parsenleft = 0;            /* clear input buffer */
00110         popallfiles();
00111 }
00112 
00113 SHELLPROC {
00114         popallfiles();
00115 }
00116 #endif
00117 
00118 
00119 /*
00120  * Read a line from the script.
00121  */
00122 
00123 char *
00124 pfgets(line, len)
00125         char *line;
00126         {
00127         register char *p = line;
00128         int nleft = len;
00129         int c;
00130 
00131         while (--nleft > 0) {
00132                 c = pgetc_macro();
00133                 if (c == PEOF) {
00134                         if (p == line)
00135                                 return NULL;
00136                         break;
00137                 }
00138                 *p++ = c;
00139                 if (c == '\n')
00140                         break;
00141         }
00142         *p = '\0';
00143         return line;
00144 }
00145 
00146 
00147 
00148 /*
00149  * Read a character from the script, returning PEOF on end of file.
00150  * Nul characters in the input are silently discarded.
00151  */
00152 
00153 int
00154 pgetc() {
00155         return pgetc_macro();
00156 }
00157 
00158 
00159 /*
00160  * Refill the input buffer and return the next input character:
00161  *
00162  * 1) If a string was pushed back on the input, switch back to the regular
00163  *    buffer.
00164  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
00165  *    from a string so we can't refill the buffer, return EOF.
00166  * 3) Call read to read in the characters.
00167  * 4) Delete all nul characters from the buffer.
00168  */
00169 
00170 int
00171 preadbuffer() {
00172         register char *p, *q;
00173         register int i;
00174 
00175         if (pushedstring) {
00176                 parsenextc = pushedstring;
00177                 pushedstring = NULL;
00178                 parsenleft = pushednleft;
00179                 if (--parsenleft >= 0)
00180                         return *parsenextc++;
00181         }
00182         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
00183                 return PEOF;
00184         flushout(&output);
00185         flushout(&errout);
00186 #if READLINE
00187     /* Use the readline() call if a prompt is to be printed (interactive). */
00188     if (r_use_prompt != NULL) {
00189         char *prompt;
00190         char *line;
00191 
00192         p = parsenextc = parsefile->buf;
00193 
00194         prompt = r_use_prompt;
00195         r_use_prompt = NULL;
00196 
00197         if ((line = readline(prompt)) == NULL) {
00198                 parsenleft = EOF_NLEFT;
00199                 return PEOF;
00200         }
00201         strcpy(p, line);
00202         free(line);
00203         i = strlen(p);
00204         p[i++] = '\n';
00205     } else {
00206 #endif
00207 retry:
00208         p = parsenextc = parsefile->buf;
00209         i = read(parsefile->fd, p, BUFSIZ);
00210         if (i <= 0) {
00211                 if (i < 0) {
00212                         if (errno == EINTR)
00213                                 goto retry;
00214 #ifdef EWOULDBLOCK
00215                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
00216                                 int flags = fcntl(0, F_GETFL, 0);
00217                                 if (flags >= 0 && flags & O_NONBLOCK) {
00218                                         flags &=~ O_NONBLOCK;
00219                                         if (fcntl(0, F_SETFL, flags) >= 0) {
00220                                                 out2str("sh: turning off NDELAY mode\n");
00221                                                 goto retry;
00222                                         }
00223                                 }
00224                         }
00225 #endif
00226                 }
00227                 parsenleft = EOF_NLEFT;
00228                 return PEOF;
00229         }
00230 #if READLINE
00231     }
00232 #endif
00233         parsenleft = i - 1;
00234 
00235         /* delete nul characters */
00236         for (;;) {
00237                 if (*p++ == '\0')
00238                         break;
00239                 if (--i <= 0)
00240                         return *parsenextc++;           /* no nul characters */
00241         }
00242         q = p - 1;
00243         while (--i > 0) {
00244                 if (*p != '\0')
00245                         *q++ = *p;
00246                 p++;
00247         }
00248         if (q == parsefile->buf)
00249                 goto retry;                     /* buffer contained nothing but nuls */
00250         parsenleft = q - parsefile->buf - 1;
00251         return *parsenextc++;
00252 }
00253 
00254 
00255 /*
00256  * Undo the last call to pgetc.  Only one character may be pushed back.
00257  * PEOF may be pushed back.
00258  */
00259 
00260 void
00261 pungetc() {
00262         parsenleft++;
00263         parsenextc--;
00264 }
00265 
00266 
00267 /*
00268  * Push a string back onto the input.  This code doesn't work if the user
00269  * tries to push back more than one string at once.
00270  */
00271 
00272 void
00273 ppushback(string, length)
00274         char *string;
00275         {
00276         pushedstring = parsenextc;
00277         pushednleft = parsenleft;
00278         parsenextc = string;
00279         parsenleft = length;
00280 }
00281 
00282 
00283 
00284 /*
00285  * Set the input to take input from a file.  If push is set, push the
00286  * old input onto the stack first.
00287  */
00288 
00289 void
00290 setinputfile(fname, push)
00291         char *fname;
00292         {
00293         int fd;
00294         int fd2;
00295 
00296         INTOFF;
00297         if ((fd = open(fname, O_RDONLY)) < 0)
00298                 error("Can't open %s", fname);
00299         if (fd < 10) {
00300                 fd2 = copyfd(fd, 10);
00301                 close(fd);
00302                 if (fd2 < 0)
00303                         error("Out of file descriptors");
00304                 fd = fd2;
00305         }
00306         setinputfd(fd, push);
00307         INTON;
00308 }
00309 
00310 
00311 /*
00312  * Like setinputfile, but takes an open file descriptor.  Call this with
00313  * interrupts off.
00314  */
00315 
00316 void
00317 setinputfd(fd, push) {
00318         (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
00319         if (push) {
00320                 pushfile();
00321                 parsefile->buf = ckmalloc(BUFSIZ);
00322         }
00323         if (parsefile->fd > 0)
00324                 close(parsefile->fd);
00325         parsefile->fd = fd;
00326         if (parsefile->buf == NULL)
00327                 parsefile->buf = ckmalloc(BUFSIZ);
00328         parsenleft = 0;
00329         plinno = 1;
00330 }
00331 
00332 
00333 /*
00334  * Like setinputfile, but takes input from a string.
00335  */
00336 
00337 void
00338 setinputstring(string, push)
00339         char *string;
00340         {
00341         INTOFF;
00342         if (push)
00343                 pushfile();
00344         parsenextc = string;
00345         parsenleft = strlen(string);
00346         parsefile->buf = NULL;
00347         plinno = 1;
00348         INTON;
00349 }
00350 
00351 
00352 
00353 /*
00354  * To handle the "." command, a stack of input files is used.  Pushfile
00355  * adds a new entry to the stack and popfile restores the previous level.
00356  */
00357 
00358 STATIC void
00359 pushfile() {
00360         struct parsefile *pf;
00361 
00362         parsefile->nleft = parsenleft;
00363         parsefile->nextc = parsenextc;
00364         parsefile->linno = plinno;
00365         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
00366         pf->prev = parsefile;
00367         pf->fd = -1;
00368         parsefile = pf;
00369 }
00370 
00371 
00372 void
00373 popfile() {
00374         struct parsefile *pf = parsefile;
00375 
00376         INTOFF;
00377         if (pf->fd >= 0)
00378                 close(pf->fd);
00379         if (pf->buf)
00380                 ckfree(pf->buf);
00381         parsefile = pf->prev;
00382         ckfree(pf);
00383         parsenleft = parsefile->nleft;
00384         parsenextc = parsefile->nextc;
00385         plinno = parsefile->linno;
00386         INTON;
00387 }
00388 
00389 
00390 /*
00391  * Return to top level.
00392  */
00393 
00394 void
00395 popallfiles() {
00396         while (parsefile != &basepf)
00397                 popfile();
00398 }
00399 
00400 
00401 
00402 /*
00403  * Close the file(s) that the shell is reading commands from.  Called
00404  * after a fork is done.
00405  */
00406 
00407 void
00408 closescript() {
00409         popallfiles();
00410         if (parsefile->fd > 0) {
00411                 close(parsefile->fd);
00412                 parsefile->fd = 0;
00413         }
00414 }

Generated on Fri Apr 14 22:56:40 2006 for minix by  doxygen 1.4.6