Home | History | Annotate | Line # | Download | only in sh
input.c revision 1.15
      1 /*	$NetBSD: input.c,v 1.15 1995/06/07 16:28:03 cgd 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 #ifndef lint
     40 #if 0
     41 static char sccsid[] = "@(#)input.c	8.2 (Berkeley) 5/4/95";
     42 #else
     43 static char rcsid[] = "$NetBSD: input.c,v 1.15 1995/06/07 16:28:03 cgd Exp $";
     44 #endif
     45 #endif /* not lint */
     46 
     47 #include <stdio.h>	/* defines BUFSIZ */
     48 #include <fcntl.h>
     49 #include <errno.h>
     50 #include <unistd.h>
     51 #include <stdlib.h>
     52 #include <string.h>
     53 
     54 /*
     55  * This file implements the input routines used by the parser.
     56  */
     57 
     58 #include "shell.h"
     59 #include "redir.h"
     60 #include "syntax.h"
     61 #include "input.h"
     62 #include "output.h"
     63 #include "options.h"
     64 #include "memalloc.h"
     65 #include "error.h"
     66 #include "alias.h"
     67 #include "parser.h"
     68 #include "myhistedit.h"
     69 
     70 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
     71 
     72 MKINIT
     73 struct strpush {
     74 	struct strpush *prev;	/* preceding string on stack */
     75 	char *prevstring;
     76 	int prevnleft;
     77 	struct alias *ap;	/* if push was associated with an alias */
     78 };
     79 
     80 /*
     81  * The parsefile structure pointed to by the global variable parsefile
     82  * contains information about the current file being read.
     83  */
     84 
     85 MKINIT
     86 struct parsefile {
     87 	struct parsefile *prev;	/* preceding file on stack */
     88 	int linno;		/* current line */
     89 	int fd;			/* file descriptor (or -1 if string) */
     90 	int nleft;		/* number of chars left in buffer */
     91 	char *nextc;		/* next char in buffer */
     92 	char *buf;		/* input buffer */
     93 	struct strpush *strpush; /* for pushing strings at this level */
     94 	struct strpush basestrpush; /* so pushing one is fast */
     95 };
     96 
     97 
     98 int plinno = 1;			/* input line number */
     99 MKINIT int parsenleft;		/* copy of parsefile->nleft */
    100 char *parsenextc;		/* copy of parsefile->nextc */
    101 MKINIT struct parsefile basepf;	/* top level input file */
    102 char basebuf[BUFSIZ];		/* buffer for top level input file */
    103 struct parsefile *parsefile = &basepf;	/* current input file */
    104 char *pushedstring;		/* copy of parsenextc when text pushed back */
    105 int pushednleft;		/* copy of parsenleft when text pushed back */
    106 int init_editline = 0;		/* editline library initialized? */
    107 int whichprompt;		/* 1 == PS1, 2 == PS2 */
    108 
    109 EditLine *el;			/* cookie for editline package */
    110 
    111 STATIC void pushfile __P((void));
    112 
    113 #ifdef mkinit
    114 INCLUDE "input.h"
    115 INCLUDE "error.h"
    116 
    117 INIT {
    118 	extern char basebuf[];
    119 
    120 	basepf.nextc = basepf.buf = basebuf;
    121 }
    122 
    123 RESET {
    124 	if (exception != EXSHELLPROC)
    125 		parsenleft = 0;            /* clear input buffer */
    126 	popallfiles();
    127 }
    128 
    129 SHELLPROC {
    130 	popallfiles();
    131 }
    132 #endif
    133 
    134 
    135 /*
    136  * Read a line from the script.
    137  */
    138 
    139 char *
    140 pfgets(line, len)
    141 	char *line;
    142 	int len;
    143 {
    144 	register char *p = line;
    145 	int nleft = len;
    146 	int c;
    147 
    148 	while (--nleft > 0) {
    149 		c = pgetc_macro();
    150 		if (c == PEOF) {
    151 			if (p == line)
    152 				return NULL;
    153 			break;
    154 		}
    155 		*p++ = c;
    156 		if (c == '\n')
    157 			break;
    158 	}
    159 	*p = '\0';
    160 	return line;
    161 }
    162 
    163 
    164 
    165 /*
    166  * Read a character from the script, returning PEOF on end of file.
    167  * Nul characters in the input are silently discarded.
    168  */
    169 
    170 int
    171 pgetc() {
    172 	return pgetc_macro();
    173 }
    174 
    175 
    176 /*
    177  * Refill the input buffer and return the next input character:
    178  *
    179  * 1) If a string was pushed back on the input, pop it;
    180  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
    181  *    from a string so we can't refill the buffer, return EOF.
    182  * 3) Call read to read in the characters.
    183  * 4) Delete all nul characters from the buffer.
    184  */
    185 
    186 int
    187 preadbuffer() {
    188 	register char *p, *q;
    189 	register int i;
    190 	register int something;
    191 	extern EditLine *el;
    192 
    193 	if (parsefile->strpush) {
    194 		popstring();
    195 		if (--parsenleft >= 0)
    196 			return (*parsenextc++);
    197 	}
    198 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
    199 		return PEOF;
    200 	flushout(&output);
    201 	flushout(&errout);
    202 retry:
    203 	p = parsenextc = parsefile->buf;
    204 	if (parsefile->fd == 0 && el) {
    205 		const char *rl_cp;
    206 		int len;
    207 
    208 		rl_cp = el_gets(el, &len);
    209 		if (rl_cp == NULL) {
    210 			i = 0;
    211 			goto eof;
    212 		}
    213 		strcpy(p, rl_cp);  /* XXX - BUFSIZE should redesign so not necessary */
    214 		i = len;
    215 
    216 	} else {
    217 		i = read(parsefile->fd, p, BUFSIZ - 1);
    218 	}
    219 eof:
    220 	if (i <= 0) {
    221                 if (i < 0) {
    222                         if (errno == EINTR)
    223                                 goto retry;
    224                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
    225                                 int flags = fcntl(0, F_GETFL, 0);
    226                                 if (flags >= 0 && flags & O_NONBLOCK) {
    227                                         flags &=~ O_NONBLOCK;
    228                                         if (fcntl(0, F_SETFL, flags) >= 0) {
    229 						out2str("sh: turning off NDELAY mode\n");
    230                                                 goto retry;
    231                                         }
    232                                 }
    233                         }
    234                 }
    235                 parsenleft = EOF_NLEFT;
    236                 return PEOF;
    237 	}
    238 	parsenleft = i - 1;	/* we're returning one char in this call */
    239 
    240 	/* delete nul characters */
    241 	something = 0;
    242 	for (;;) {
    243 		if (*p == '\0')
    244 			break;
    245 		if (*p != ' ' && *p != '\t' && *p != '\n')
    246 			something = 1;
    247 		p++;
    248 		if (--i <= 0) {
    249 			*p = '\0';
    250 			goto done;		/* no nul characters */
    251 		}
    252 	}
    253 	/*
    254 	 * remove nuls
    255 	 */
    256 	q = p++;
    257 	while (--i > 0) {
    258 		if (*p != '\0')
    259 			*q++ = *p;
    260 		p++;
    261 	}
    262 	*q = '\0';
    263 	if (q == parsefile->buf)
    264 		goto retry;			/* buffer contained nothing but nuls */
    265 	parsenleft = q - parsefile->buf - 1;
    266 
    267 done:
    268 	if (parsefile->fd == 0 && hist && something) {
    269 		INTOFF;
    270 		history(hist, whichprompt == 1 ? H_ENTER : H_ADD,
    271 			   parsefile->buf);
    272 		INTON;
    273 	}
    274 	if (vflag) {
    275 		/*
    276 		 * This isn't right.  Most shells coordinate it with
    277 		 * reading a line at a time.  I honestly don't know if its
    278 		 * worth it.
    279 		 */
    280 		i = parsenleft + 1;
    281 		p = parsefile->buf;
    282 		for (; i--; p++)
    283 			out2c(*p)
    284 		flushout(out2);
    285 	}
    286 	return *parsenextc++;
    287 }
    288 
    289 /*
    290  * Undo the last call to pgetc.  Only one character may be pushed back.
    291  * PEOF may be pushed back.
    292  */
    293 
    294 void
    295 pungetc() {
    296 	parsenleft++;
    297 	parsenextc--;
    298 }
    299 
    300 /*
    301  * Push a string back onto the input at this current parsefile level.
    302  * We handle aliases this way.
    303  */
    304 void
    305 pushstring(s, len, ap)
    306 	char *s;
    307 	int len;
    308 	void *ap;
    309 	{
    310 	struct strpush *sp;
    311 
    312 	INTOFF;
    313 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
    314 	if (parsefile->strpush) {
    315 		sp = ckmalloc(sizeof (struct strpush));
    316 		sp->prev = parsefile->strpush;
    317 		parsefile->strpush = sp;
    318 	} else
    319 		sp = parsefile->strpush = &(parsefile->basestrpush);
    320 	sp->prevstring = parsenextc;
    321 	sp->prevnleft = parsenleft;
    322 	sp->ap = (struct alias *)ap;
    323 	if (ap)
    324 		((struct alias *)ap)->flag |= ALIASINUSE;
    325 	parsenextc = s;
    326 	parsenleft = len;
    327 	INTON;
    328 }
    329 
    330 void
    331 popstring()
    332 {
    333 	struct strpush *sp = parsefile->strpush;
    334 
    335 	INTOFF;
    336 	parsenextc = sp->prevstring;
    337 	parsenleft = sp->prevnleft;
    338 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
    339 	if (sp->ap)
    340 		sp->ap->flag &= ~ALIASINUSE;
    341 	parsefile->strpush = sp->prev;
    342 	if (sp != &(parsefile->basestrpush))
    343 		ckfree(sp);
    344 	INTON;
    345 }
    346 
    347 /*
    348  * Set the input to take input from a file.  If push is set, push the
    349  * old input onto the stack first.
    350  */
    351 
    352 void
    353 setinputfile(fname, push)
    354 	char *fname;
    355 	int push;
    356 {
    357 	int fd;
    358 	int fd2;
    359 
    360 	INTOFF;
    361 	if ((fd = open(fname, O_RDONLY)) < 0)
    362 		error("Can't open %s", fname);
    363 	if (fd < 10) {
    364 		fd2 = copyfd(fd, 10);
    365 		close(fd);
    366 		if (fd2 < 0)
    367 			error("Out of file descriptors");
    368 		fd = fd2;
    369 	}
    370 	setinputfd(fd, push);
    371 	INTON;
    372 }
    373 
    374 
    375 /*
    376  * Like setinputfile, but takes an open file descriptor.  Call this with
    377  * interrupts off.
    378  */
    379 
    380 void
    381 setinputfd(fd, push)
    382 	int fd, push;
    383 {
    384 	if (push) {
    385 		pushfile();
    386 		parsefile->buf = ckmalloc(BUFSIZ);
    387 	}
    388 	if (parsefile->fd > 0)
    389 		close(parsefile->fd);
    390 	parsefile->fd = fd;
    391 	if (parsefile->buf == NULL)
    392 		parsefile->buf = ckmalloc(BUFSIZ);
    393 	parsenleft = 0;
    394 	plinno = 1;
    395 }
    396 
    397 
    398 /*
    399  * Like setinputfile, but takes input from a string.
    400  */
    401 
    402 void
    403 setinputstring(string, push)
    404 	char *string;
    405 	int push;
    406 	{
    407 	INTOFF;
    408 	if (push)
    409 		pushfile();
    410 	parsenextc = string;
    411 	parsenleft = strlen(string);
    412 	parsefile->buf = NULL;
    413 	plinno = 1;
    414 	INTON;
    415 }
    416 
    417 
    418 
    419 /*
    420  * To handle the "." command, a stack of input files is used.  Pushfile
    421  * adds a new entry to the stack and popfile restores the previous level.
    422  */
    423 
    424 STATIC void
    425 pushfile() {
    426 	struct parsefile *pf;
    427 
    428 	parsefile->nleft = parsenleft;
    429 	parsefile->nextc = parsenextc;
    430 	parsefile->linno = plinno;
    431 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
    432 	pf->prev = parsefile;
    433 	pf->fd = -1;
    434 	pf->strpush = NULL;
    435 	pf->basestrpush.prev = NULL;
    436 	parsefile = pf;
    437 }
    438 
    439 
    440 void
    441 popfile() {
    442 	struct parsefile *pf = parsefile;
    443 
    444 	INTOFF;
    445 	if (pf->fd >= 0)
    446 		close(pf->fd);
    447 	if (pf->buf)
    448 		ckfree(pf->buf);
    449 	while (pf->strpush)
    450 		popstring();
    451 	parsefile = pf->prev;
    452 	ckfree(pf);
    453 	parsenleft = parsefile->nleft;
    454 	parsenextc = parsefile->nextc;
    455 	plinno = parsefile->linno;
    456 	INTON;
    457 }
    458 
    459 
    460 /*
    461  * Return to top level.
    462  */
    463 
    464 void
    465 popallfiles() {
    466 	while (parsefile != &basepf)
    467 		popfile();
    468 }
    469 
    470 
    471 
    472 /*
    473  * Close the file(s) that the shell is reading commands from.  Called
    474  * after a fork is done.
    475  */
    476 
    477 void
    478 closescript() {
    479 	popallfiles();
    480 	if (parsefile->fd > 0) {
    481 		close(parsefile->fd);
    482 		parsefile->fd = 0;
    483 	}
    484 }
    485