147119Sbostic /*-
260698Sbostic * Copyright (c) 1991, 1993
360698Sbostic * The Regents of the University of California. All rights reserved.
447119Sbostic *
547119Sbostic * This code is derived from software contributed to Berkeley by
647119Sbostic * Kenneth Almquist.
747119Sbostic *
847119Sbostic * %sccs.include.redist.c%
947119Sbostic */
1047119Sbostic
1147119Sbostic #ifndef lint
12*69809Schristos static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 06/08/95";
1347119Sbostic #endif /* not lint */
1447119Sbostic
1569272Schristos #include <stdio.h> /* defines BUFSIZ */
1669272Schristos #include <fcntl.h>
1769272Schristos #include <errno.h>
1869272Schristos #include <unistd.h>
1969272Schristos #include <stdlib.h>
20*69809Schristos #include <string.h>
2169272Schristos
2247119Sbostic /*
2347119Sbostic * This file implements the input routines used by the parser.
2447119Sbostic */
2547119Sbostic
2647119Sbostic #include "shell.h"
2769272Schristos #include "redir.h"
2847119Sbostic #include "syntax.h"
2947119Sbostic #include "input.h"
3047119Sbostic #include "output.h"
3154313Smarc #include "options.h"
3247119Sbostic #include "memalloc.h"
3347119Sbostic #include "error.h"
3454313Smarc #include "alias.h"
3554313Smarc #include "parser.h"
3654330Smarc #include "myhistedit.h"
3747119Sbostic
3847119Sbostic #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
3947119Sbostic
4054313Smarc MKINIT
4154313Smarc struct strpush {
4254313Smarc struct strpush *prev; /* preceding string on stack */
4354313Smarc char *prevstring;
4454313Smarc int prevnleft;
4554313Smarc struct alias *ap; /* if push was associated with an alias */
4654313Smarc };
4747119Sbostic
4847119Sbostic /*
4947119Sbostic * The parsefile structure pointed to by the global variable parsefile
5047119Sbostic * contains information about the current file being read.
5147119Sbostic */
5247119Sbostic
5347119Sbostic MKINIT
5447119Sbostic struct parsefile {
5554313Smarc struct parsefile *prev; /* preceding file on stack */
5647119Sbostic int linno; /* current line */
5747119Sbostic int fd; /* file descriptor (or -1 if string) */
5847119Sbostic int nleft; /* number of chars left in buffer */
5947119Sbostic char *nextc; /* next char in buffer */
6047119Sbostic char *buf; /* input buffer */
6154313Smarc struct strpush *strpush; /* for pushing strings at this level */
6254313Smarc struct strpush basestrpush; /* so pushing one is fast */
6347119Sbostic };
6447119Sbostic
6547119Sbostic
6647119Sbostic int plinno = 1; /* input line number */
6747119Sbostic MKINIT int parsenleft; /* copy of parsefile->nleft */
6847119Sbostic char *parsenextc; /* copy of parsefile->nextc */
6947119Sbostic MKINIT struct parsefile basepf; /* top level input file */
7047119Sbostic char basebuf[BUFSIZ]; /* buffer for top level input file */
7147119Sbostic struct parsefile *parsefile = &basepf; /* current input file */
7247119Sbostic char *pushedstring; /* copy of parsenextc when text pushed back */
7347119Sbostic int pushednleft; /* copy of parsenleft when text pushed back */
7454313Smarc int init_editline = 0; /* editline library initialized? */
7554313Smarc int whichprompt; /* 1 == PS1, 2 == PS2 */
7647119Sbostic
7754313Smarc EditLine *el; /* cookie for editline package */
7854313Smarc
7969272Schristos STATIC void pushfile __P((void));
8047119Sbostic
8147119Sbostic #ifdef mkinit
8247119Sbostic INCLUDE "input.h"
8347119Sbostic INCLUDE "error.h"
8447119Sbostic
8547119Sbostic INIT {
8647119Sbostic extern char basebuf[];
8747119Sbostic
8847119Sbostic basepf.nextc = basepf.buf = basebuf;
8947119Sbostic }
9047119Sbostic
9147119Sbostic RESET {
9247119Sbostic if (exception != EXSHELLPROC)
9347119Sbostic parsenleft = 0; /* clear input buffer */
9447119Sbostic popallfiles();
9547119Sbostic }
9647119Sbostic
9747119Sbostic SHELLPROC {
9847119Sbostic popallfiles();
9947119Sbostic }
10047119Sbostic #endif
10147119Sbostic
10247119Sbostic
10347119Sbostic /*
10447119Sbostic * Read a line from the script.
10547119Sbostic */
10647119Sbostic
10747119Sbostic char *
pfgets(line,len)10847119Sbostic pfgets(line, len)
10947119Sbostic char *line;
11069272Schristos int len;
11169272Schristos {
11247119Sbostic register char *p = line;
11347119Sbostic int nleft = len;
11447119Sbostic int c;
11547119Sbostic
11647119Sbostic while (--nleft > 0) {
11747119Sbostic c = pgetc_macro();
11847119Sbostic if (c == PEOF) {
11947119Sbostic if (p == line)
12047119Sbostic return NULL;
12147119Sbostic break;
12247119Sbostic }
12347119Sbostic *p++ = c;
12447119Sbostic if (c == '\n')
12547119Sbostic break;
12647119Sbostic }
12747119Sbostic *p = '\0';
12847119Sbostic return line;
12947119Sbostic }
13047119Sbostic
13147119Sbostic
13247119Sbostic
13347119Sbostic /*
13447119Sbostic * Read a character from the script, returning PEOF on end of file.
13547119Sbostic * Nul characters in the input are silently discarded.
13647119Sbostic */
13747119Sbostic
13847119Sbostic int
pgetc()13947119Sbostic pgetc() {
14047119Sbostic return pgetc_macro();
14147119Sbostic }
14247119Sbostic
14347119Sbostic
14447119Sbostic /*
14547119Sbostic * Refill the input buffer and return the next input character:
14647119Sbostic *
14754313Smarc * 1) If a string was pushed back on the input, pop it;
14847119Sbostic * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
14947119Sbostic * from a string so we can't refill the buffer, return EOF.
15047119Sbostic * 3) Call read to read in the characters.
15147119Sbostic * 4) Delete all nul characters from the buffer.
15247119Sbostic */
15347119Sbostic
15447119Sbostic int
preadbuffer()15547119Sbostic preadbuffer() {
15647119Sbostic register char *p, *q;
15747119Sbostic register int i;
15854313Smarc register int something;
15954313Smarc extern EditLine *el;
16047119Sbostic
16154313Smarc if (parsefile->strpush) {
16254313Smarc popstring();
16347119Sbostic if (--parsenleft >= 0)
16454313Smarc return (*parsenextc++);
16547119Sbostic }
16647119Sbostic if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
16747119Sbostic return PEOF;
16847119Sbostic flushout(&output);
16947119Sbostic flushout(&errout);
17047119Sbostic retry:
17147119Sbostic p = parsenextc = parsefile->buf;
17254313Smarc if (parsefile->fd == 0 && el) {
17355241Smarc const char *rl_cp;
17454313Smarc int len;
17554313Smarc
17654313Smarc rl_cp = el_gets(el, &len);
17754313Smarc if (rl_cp == NULL) {
17854313Smarc i = 0;
17954313Smarc goto eof;
18054313Smarc }
18154313Smarc strcpy(p, rl_cp); /* XXX - BUFSIZE should redesign so not necessary */
18254313Smarc i = len;
18354313Smarc
18454313Smarc } else {
18554313Smarc i = read(parsefile->fd, p, BUFSIZ - 1);
18654313Smarc }
18754313Smarc eof:
18847119Sbostic if (i <= 0) {
18947294Smarc if (i < 0) {
19047294Smarc if (errno == EINTR)
19147294Smarc goto retry;
19247294Smarc if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
19347294Smarc int flags = fcntl(0, F_GETFL, 0);
19450345Sbostic if (flags >= 0 && flags & O_NONBLOCK) {
19550345Sbostic flags &=~ O_NONBLOCK;
19647294Smarc if (fcntl(0, F_SETFL, flags) >= 0) {
19747980Smarc out2str("sh: turning off NDELAY mode\n");
19847294Smarc goto retry;
19947294Smarc }
20047294Smarc }
20147294Smarc }
20247294Smarc }
20347294Smarc parsenleft = EOF_NLEFT;
20447294Smarc return PEOF;
20547119Sbostic }
20654313Smarc parsenleft = i - 1; /* we're returning one char in this call */
20747119Sbostic
20847119Sbostic /* delete nul characters */
20954313Smarc something = 0;
21047119Sbostic for (;;) {
21154313Smarc if (*p == '\0')
21247119Sbostic break;
21354313Smarc if (*p != ' ' && *p != '\t' && *p != '\n')
21454313Smarc something = 1;
21554313Smarc p++;
21654313Smarc if (--i <= 0) {
21754313Smarc *p = '\0';
21854313Smarc goto done; /* no nul characters */
21954313Smarc }
22047119Sbostic }
22154313Smarc /*
22254313Smarc * remove nuls
22354313Smarc */
22454313Smarc q = p++;
22547119Sbostic while (--i > 0) {
22647119Sbostic if (*p != '\0')
22747119Sbostic *q++ = *p;
22847119Sbostic p++;
22947119Sbostic }
23054313Smarc *q = '\0';
23147119Sbostic if (q == parsefile->buf)
23247119Sbostic goto retry; /* buffer contained nothing but nuls */
23347119Sbostic parsenleft = q - parsefile->buf - 1;
23454313Smarc
23554313Smarc done:
23654313Smarc if (parsefile->fd == 0 && hist && something) {
23754313Smarc INTOFF;
23854313Smarc history(hist, whichprompt == 1 ? H_ENTER : H_ADD,
23954313Smarc parsefile->buf);
24054313Smarc INTON;
24154313Smarc }
24254313Smarc if (vflag) {
24354313Smarc /*
24454313Smarc * This isn't right. Most shells coordinate it with
24554313Smarc * reading a line at a time. I honestly don't know if its
24654313Smarc * worth it.
24754313Smarc */
24854313Smarc i = parsenleft + 1;
24954313Smarc p = parsefile->buf;
25054313Smarc for (; i--; p++)
25154313Smarc out2c(*p)
25254313Smarc flushout(out2);
25354313Smarc }
25447119Sbostic return *parsenextc++;
25547119Sbostic }
25647119Sbostic
25747119Sbostic /*
25847119Sbostic * Undo the last call to pgetc. Only one character may be pushed back.
25947119Sbostic * PEOF may be pushed back.
26047119Sbostic */
26147119Sbostic
26247119Sbostic void
pungetc()26347119Sbostic pungetc() {
26447119Sbostic parsenleft++;
26547119Sbostic parsenextc--;
26647119Sbostic }
26747119Sbostic
26847119Sbostic /*
26954313Smarc * Push a string back onto the input at this current parsefile level.
27054313Smarc * We handle aliases this way.
27147119Sbostic */
27247119Sbostic void
pushstring(s,len,ap)27354313Smarc pushstring(s, len, ap)
27454313Smarc char *s;
27554313Smarc int len;
27654313Smarc void *ap;
27747119Sbostic {
27854313Smarc struct strpush *sp;
27954313Smarc
28054313Smarc INTOFF;
28154313Smarc /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
28254313Smarc if (parsefile->strpush) {
28354313Smarc sp = ckmalloc(sizeof (struct strpush));
28454313Smarc sp->prev = parsefile->strpush;
28554313Smarc parsefile->strpush = sp;
28654313Smarc } else
28754313Smarc sp = parsefile->strpush = &(parsefile->basestrpush);
28854313Smarc sp->prevstring = parsenextc;
28954313Smarc sp->prevnleft = parsenleft;
29054313Smarc sp->ap = (struct alias *)ap;
29154313Smarc if (ap)
29254313Smarc ((struct alias *)ap)->flag |= ALIASINUSE;
29354313Smarc parsenextc = s;
29454313Smarc parsenleft = len;
29554313Smarc INTON;
29647119Sbostic }
29747119Sbostic
29869272Schristos void
popstring()29954313Smarc popstring()
30054313Smarc {
30154313Smarc struct strpush *sp = parsefile->strpush;
30247119Sbostic
30354313Smarc INTOFF;
30454313Smarc parsenextc = sp->prevstring;
30554313Smarc parsenleft = sp->prevnleft;
30654313Smarc /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
30754313Smarc if (sp->ap)
30854313Smarc sp->ap->flag &= ~ALIASINUSE;
30954313Smarc parsefile->strpush = sp->prev;
31054313Smarc if (sp != &(parsefile->basestrpush))
31154313Smarc ckfree(sp);
31254313Smarc INTON;
31354313Smarc }
31447119Sbostic
31547119Sbostic /*
31647119Sbostic * Set the input to take input from a file. If push is set, push the
31747119Sbostic * old input onto the stack first.
31847119Sbostic */
31947119Sbostic
32047119Sbostic void
setinputfile(fname,push)32147119Sbostic setinputfile(fname, push)
32247119Sbostic char *fname;
32369272Schristos int push;
32469272Schristos {
32547119Sbostic int fd;
32647119Sbostic int fd2;
32747119Sbostic
32847119Sbostic INTOFF;
32947119Sbostic if ((fd = open(fname, O_RDONLY)) < 0)
33047119Sbostic error("Can't open %s", fname);
33147119Sbostic if (fd < 10) {
33247119Sbostic fd2 = copyfd(fd, 10);
33347119Sbostic close(fd);
33447119Sbostic if (fd2 < 0)
33547119Sbostic error("Out of file descriptors");
33647119Sbostic fd = fd2;
33747119Sbostic }
33847119Sbostic setinputfd(fd, push);
33947119Sbostic INTON;
34047119Sbostic }
34147119Sbostic
34247119Sbostic
34347119Sbostic /*
34447119Sbostic * Like setinputfile, but takes an open file descriptor. Call this with
34547119Sbostic * interrupts off.
34647119Sbostic */
34747119Sbostic
34847119Sbostic void
setinputfd(fd,push)34969272Schristos setinputfd(fd, push)
35069272Schristos int fd, push;
35169272Schristos {
35247119Sbostic if (push) {
35347119Sbostic pushfile();
35447119Sbostic parsefile->buf = ckmalloc(BUFSIZ);
35547119Sbostic }
35647119Sbostic if (parsefile->fd > 0)
35747119Sbostic close(parsefile->fd);
35847119Sbostic parsefile->fd = fd;
35947119Sbostic if (parsefile->buf == NULL)
36047119Sbostic parsefile->buf = ckmalloc(BUFSIZ);
36147119Sbostic parsenleft = 0;
36247119Sbostic plinno = 1;
36347119Sbostic }
36447119Sbostic
36547119Sbostic
36647119Sbostic /*
36747119Sbostic * Like setinputfile, but takes input from a string.
36847119Sbostic */
36947119Sbostic
37047119Sbostic void
setinputstring(string,push)37147119Sbostic setinputstring(string, push)
37247119Sbostic char *string;
37369272Schristos int push;
37447119Sbostic {
37547119Sbostic INTOFF;
37647119Sbostic if (push)
37747119Sbostic pushfile();
37847119Sbostic parsenextc = string;
37947119Sbostic parsenleft = strlen(string);
38047119Sbostic parsefile->buf = NULL;
38147119Sbostic plinno = 1;
38247119Sbostic INTON;
38347119Sbostic }
38447119Sbostic
38547119Sbostic
38647119Sbostic
38747119Sbostic /*
38847119Sbostic * To handle the "." command, a stack of input files is used. Pushfile
38947119Sbostic * adds a new entry to the stack and popfile restores the previous level.
39047119Sbostic */
39147119Sbostic
39247119Sbostic STATIC void
pushfile()39347119Sbostic pushfile() {
39447119Sbostic struct parsefile *pf;
39547119Sbostic
39647119Sbostic parsefile->nleft = parsenleft;
39747119Sbostic parsefile->nextc = parsenextc;
39847119Sbostic parsefile->linno = plinno;
39947119Sbostic pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
40047119Sbostic pf->prev = parsefile;
40147119Sbostic pf->fd = -1;
40254313Smarc pf->strpush = NULL;
40354313Smarc pf->basestrpush.prev = NULL;
40447119Sbostic parsefile = pf;
40547119Sbostic }
40647119Sbostic
40747119Sbostic
40847119Sbostic void
popfile()40947119Sbostic popfile() {
41047119Sbostic struct parsefile *pf = parsefile;
41147119Sbostic
41247119Sbostic INTOFF;
41347119Sbostic if (pf->fd >= 0)
41447119Sbostic close(pf->fd);
41547119Sbostic if (pf->buf)
41647119Sbostic ckfree(pf->buf);
41754313Smarc while (pf->strpush)
41854313Smarc popstring();
41947119Sbostic parsefile = pf->prev;
42047119Sbostic ckfree(pf);
42147119Sbostic parsenleft = parsefile->nleft;
42247119Sbostic parsenextc = parsefile->nextc;
42347119Sbostic plinno = parsefile->linno;
42447119Sbostic INTON;
42547119Sbostic }
42647119Sbostic
42747119Sbostic
42847119Sbostic /*
42947119Sbostic * Return to top level.
43047119Sbostic */
43147119Sbostic
43247119Sbostic void
popallfiles()43347119Sbostic popallfiles() {
43447119Sbostic while (parsefile != &basepf)
43547119Sbostic popfile();
43647119Sbostic }
43747119Sbostic
43847119Sbostic
43947119Sbostic
44047119Sbostic /*
44147119Sbostic * Close the file(s) that the shell is reading commands from. Called
44247119Sbostic * after a fork is done.
44347119Sbostic */
44447119Sbostic
44547119Sbostic void
closescript()44647119Sbostic closescript() {
44747119Sbostic popallfiles();
44847119Sbostic if (parsefile->fd > 0) {
44947119Sbostic close(parsefile->fd);
45047119Sbostic parsefile->fd = 0;
45147119Sbostic }
45247119Sbostic }
453