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