147119Sbostic /*- 247119Sbostic * Copyright (c) 1991 The Regents of the University of California. 347119Sbostic * 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*50345Sbostic static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 07/01/91"; 1347119Sbostic #endif /* not lint */ 1447119Sbostic 1547119Sbostic /* 1647119Sbostic * This file implements the input routines used by the parser. 1747119Sbostic */ 1847119Sbostic 1947119Sbostic #include <stdio.h> /* defines BUFSIZ */ 2047119Sbostic #include "shell.h" 2147119Sbostic #include <fcntl.h> 2247119Sbostic #include <errno.h> 2347119Sbostic #include "syntax.h" 2447119Sbostic #include "input.h" 2547119Sbostic #include "output.h" 2647119Sbostic #include "memalloc.h" 2747119Sbostic #include "error.h" 2847119Sbostic 2947119Sbostic #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 3047119Sbostic 3147119Sbostic 3247119Sbostic /* 3347119Sbostic * The parsefile structure pointed to by the global variable parsefile 3447119Sbostic * contains information about the current file being read. 3547119Sbostic */ 3647119Sbostic 3747119Sbostic MKINIT 3847119Sbostic struct parsefile { 3947119Sbostic int linno; /* current line */ 4047119Sbostic int fd; /* file descriptor (or -1 if string) */ 4147119Sbostic int nleft; /* number of chars left in buffer */ 4247119Sbostic char *nextc; /* next char in buffer */ 4347119Sbostic struct parsefile *prev; /* preceding file on stack */ 4447119Sbostic char *buf; /* input buffer */ 4547119Sbostic }; 4647119Sbostic 4747119Sbostic 4847119Sbostic int plinno = 1; /* input line number */ 4947119Sbostic MKINIT int parsenleft; /* copy of parsefile->nleft */ 5047119Sbostic char *parsenextc; /* copy of parsefile->nextc */ 5147119Sbostic MKINIT struct parsefile basepf; /* top level input file */ 5247119Sbostic char basebuf[BUFSIZ]; /* buffer for top level input file */ 5347119Sbostic struct parsefile *parsefile = &basepf; /* current input file */ 5447119Sbostic char *pushedstring; /* copy of parsenextc when text pushed back */ 5547119Sbostic int pushednleft; /* copy of parsenleft when text pushed back */ 5647119Sbostic 5747119Sbostic #ifdef __STDC__ 5847119Sbostic STATIC void pushfile(void); 5947119Sbostic #else 6047119Sbostic STATIC void pushfile(); 6147119Sbostic #endif 6247119Sbostic 6347119Sbostic 6447119Sbostic 6547119Sbostic #ifdef mkinit 6647119Sbostic INCLUDE "input.h" 6747119Sbostic INCLUDE "error.h" 6847119Sbostic 6947119Sbostic INIT { 7047119Sbostic extern char basebuf[]; 7147119Sbostic 7247119Sbostic basepf.nextc = basepf.buf = basebuf; 7347119Sbostic } 7447119Sbostic 7547119Sbostic RESET { 7647119Sbostic if (exception != EXSHELLPROC) 7747119Sbostic parsenleft = 0; /* clear input buffer */ 7847119Sbostic popallfiles(); 7947119Sbostic } 8047119Sbostic 8147119Sbostic SHELLPROC { 8247119Sbostic popallfiles(); 8347119Sbostic } 8447119Sbostic #endif 8547119Sbostic 8647119Sbostic 8747119Sbostic /* 8847119Sbostic * Read a line from the script. 8947119Sbostic */ 9047119Sbostic 9147119Sbostic char * 9247119Sbostic pfgets(line, len) 9347119Sbostic char *line; 9447119Sbostic { 9547119Sbostic register char *p = line; 9647119Sbostic int nleft = len; 9747119Sbostic int c; 9847119Sbostic 9947119Sbostic while (--nleft > 0) { 10047119Sbostic c = pgetc_macro(); 10147119Sbostic if (c == PEOF) { 10247119Sbostic if (p == line) 10347119Sbostic return NULL; 10447119Sbostic break; 10547119Sbostic } 10647119Sbostic *p++ = c; 10747119Sbostic if (c == '\n') 10847119Sbostic break; 10947119Sbostic } 11047119Sbostic *p = '\0'; 11147119Sbostic return line; 11247119Sbostic } 11347119Sbostic 11447119Sbostic 11547119Sbostic 11647119Sbostic /* 11747119Sbostic * Read a character from the script, returning PEOF on end of file. 11847119Sbostic * Nul characters in the input are silently discarded. 11947119Sbostic */ 12047119Sbostic 12147119Sbostic int 12247119Sbostic pgetc() { 12347119Sbostic return pgetc_macro(); 12447119Sbostic } 12547119Sbostic 12647119Sbostic 12747119Sbostic /* 12847119Sbostic * Refill the input buffer and return the next input character: 12947119Sbostic * 13047119Sbostic * 1) If a string was pushed back on the input, switch back to the regular 13147119Sbostic * buffer. 13247119Sbostic * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 13347119Sbostic * from a string so we can't refill the buffer, return EOF. 13447119Sbostic * 3) Call read to read in the characters. 13547119Sbostic * 4) Delete all nul characters from the buffer. 13647119Sbostic */ 13747119Sbostic 13847119Sbostic int 13947119Sbostic preadbuffer() { 14047119Sbostic register char *p, *q; 14147119Sbostic register int i; 14247119Sbostic 14347119Sbostic if (pushedstring) { 14447119Sbostic parsenextc = pushedstring; 14547119Sbostic pushedstring = NULL; 14647119Sbostic parsenleft = pushednleft; 14747119Sbostic if (--parsenleft >= 0) 14847119Sbostic return *parsenextc++; 14947119Sbostic } 15047119Sbostic if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 15147119Sbostic return PEOF; 15247119Sbostic flushout(&output); 15347119Sbostic flushout(&errout); 15447119Sbostic retry: 15547119Sbostic p = parsenextc = parsefile->buf; 15647119Sbostic i = read(parsefile->fd, p, BUFSIZ); 15747119Sbostic if (i <= 0) { 15847294Smarc if (i < 0) { 15947294Smarc if (errno == EINTR) 16047294Smarc goto retry; 16147294Smarc if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 16247294Smarc int flags = fcntl(0, F_GETFL, 0); 163*50345Sbostic if (flags >= 0 && flags & O_NONBLOCK) { 164*50345Sbostic flags &=~ O_NONBLOCK; 16547294Smarc if (fcntl(0, F_SETFL, flags) >= 0) { 16647980Smarc out2str("sh: turning off NDELAY mode\n"); 16747294Smarc goto retry; 16847294Smarc } 16947294Smarc } 17047294Smarc } 17147294Smarc } 17247294Smarc parsenleft = EOF_NLEFT; 17347294Smarc return PEOF; 17447119Sbostic } 17547119Sbostic parsenleft = i - 1; 17647119Sbostic 17747119Sbostic /* delete nul characters */ 17847119Sbostic for (;;) { 17947119Sbostic if (*p++ == '\0') 18047119Sbostic break; 18147119Sbostic if (--i <= 0) 18247119Sbostic return *parsenextc++; /* no nul characters */ 18347119Sbostic } 18447119Sbostic q = p - 1; 18547119Sbostic while (--i > 0) { 18647119Sbostic if (*p != '\0') 18747119Sbostic *q++ = *p; 18847119Sbostic p++; 18947119Sbostic } 19047119Sbostic if (q == parsefile->buf) 19147119Sbostic goto retry; /* buffer contained nothing but nuls */ 19247119Sbostic parsenleft = q - parsefile->buf - 1; 19347119Sbostic return *parsenextc++; 19447119Sbostic } 19547119Sbostic 19647119Sbostic 19747119Sbostic /* 19847119Sbostic * Undo the last call to pgetc. Only one character may be pushed back. 19947119Sbostic * PEOF may be pushed back. 20047119Sbostic */ 20147119Sbostic 20247119Sbostic void 20347119Sbostic pungetc() { 20447119Sbostic parsenleft++; 20547119Sbostic parsenextc--; 20647119Sbostic } 20747119Sbostic 20847119Sbostic 20947119Sbostic /* 21047119Sbostic * Push a string back onto the input. This code doesn't work if the user 21147119Sbostic * tries to push back more than one string at once. 21247119Sbostic */ 21347119Sbostic 21447119Sbostic void 21547119Sbostic ppushback(string, length) 21647119Sbostic char *string; 21747119Sbostic { 21847119Sbostic pushedstring = parsenextc; 21947119Sbostic pushednleft = parsenleft; 22047119Sbostic parsenextc = string; 22147119Sbostic parsenleft = length; 22247119Sbostic } 22347119Sbostic 22447119Sbostic 22547119Sbostic 22647119Sbostic /* 22747119Sbostic * Set the input to take input from a file. If push is set, push the 22847119Sbostic * old input onto the stack first. 22947119Sbostic */ 23047119Sbostic 23147119Sbostic void 23247119Sbostic setinputfile(fname, push) 23347119Sbostic char *fname; 23447119Sbostic { 23547119Sbostic int fd; 23647119Sbostic int fd2; 23747119Sbostic 23847119Sbostic INTOFF; 23947119Sbostic if ((fd = open(fname, O_RDONLY)) < 0) 24047119Sbostic error("Can't open %s", fname); 24147119Sbostic if (fd < 10) { 24247119Sbostic fd2 = copyfd(fd, 10); 24347119Sbostic close(fd); 24447119Sbostic if (fd2 < 0) 24547119Sbostic error("Out of file descriptors"); 24647119Sbostic fd = fd2; 24747119Sbostic } 24847119Sbostic setinputfd(fd, push); 24947119Sbostic INTON; 25047119Sbostic } 25147119Sbostic 25247119Sbostic 25347119Sbostic /* 25447119Sbostic * Like setinputfile, but takes an open file descriptor. Call this with 25547119Sbostic * interrupts off. 25647119Sbostic */ 25747119Sbostic 25847119Sbostic void 25947119Sbostic setinputfd(fd, push) { 26047119Sbostic if (push) { 26147119Sbostic pushfile(); 26247119Sbostic parsefile->buf = ckmalloc(BUFSIZ); 26347119Sbostic } 26447119Sbostic if (parsefile->fd > 0) 26547119Sbostic close(parsefile->fd); 26647119Sbostic parsefile->fd = fd; 26747119Sbostic if (parsefile->buf == NULL) 26847119Sbostic parsefile->buf = ckmalloc(BUFSIZ); 26947119Sbostic parsenleft = 0; 27047119Sbostic plinno = 1; 27147119Sbostic } 27247119Sbostic 27347119Sbostic 27447119Sbostic /* 27547119Sbostic * Like setinputfile, but takes input from a string. 27647119Sbostic */ 27747119Sbostic 27847119Sbostic void 27947119Sbostic setinputstring(string, push) 28047119Sbostic char *string; 28147119Sbostic { 28247119Sbostic INTOFF; 28347119Sbostic if (push) 28447119Sbostic pushfile(); 28547119Sbostic parsenextc = string; 28647119Sbostic parsenleft = strlen(string); 28747119Sbostic parsefile->buf = NULL; 28847119Sbostic plinno = 1; 28947119Sbostic INTON; 29047119Sbostic } 29147119Sbostic 29247119Sbostic 29347119Sbostic 29447119Sbostic /* 29547119Sbostic * To handle the "." command, a stack of input files is used. Pushfile 29647119Sbostic * adds a new entry to the stack and popfile restores the previous level. 29747119Sbostic */ 29847119Sbostic 29947119Sbostic STATIC void 30047119Sbostic pushfile() { 30147119Sbostic struct parsefile *pf; 30247119Sbostic 30347119Sbostic parsefile->nleft = parsenleft; 30447119Sbostic parsefile->nextc = parsenextc; 30547119Sbostic parsefile->linno = plinno; 30647119Sbostic pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 30747119Sbostic pf->prev = parsefile; 30847119Sbostic pf->fd = -1; 30947119Sbostic parsefile = pf; 31047119Sbostic } 31147119Sbostic 31247119Sbostic 31347119Sbostic void 31447119Sbostic popfile() { 31547119Sbostic struct parsefile *pf = parsefile; 31647119Sbostic 31747119Sbostic INTOFF; 31847119Sbostic if (pf->fd >= 0) 31947119Sbostic close(pf->fd); 32047119Sbostic if (pf->buf) 32147119Sbostic ckfree(pf->buf); 32247119Sbostic parsefile = pf->prev; 32347119Sbostic ckfree(pf); 32447119Sbostic parsenleft = parsefile->nleft; 32547119Sbostic parsenextc = parsefile->nextc; 32647119Sbostic plinno = parsefile->linno; 32747119Sbostic INTON; 32847119Sbostic } 32947119Sbostic 33047119Sbostic 33147119Sbostic /* 33247119Sbostic * Return to top level. 33347119Sbostic */ 33447119Sbostic 33547119Sbostic void 33647119Sbostic popallfiles() { 33747119Sbostic while (parsefile != &basepf) 33847119Sbostic popfile(); 33947119Sbostic } 34047119Sbostic 34147119Sbostic 34247119Sbostic 34347119Sbostic /* 34447119Sbostic * Close the file(s) that the shell is reading commands from. Called 34547119Sbostic * after a fork is done. 34647119Sbostic */ 34747119Sbostic 34847119Sbostic void 34947119Sbostic closescript() { 35047119Sbostic popallfiles(); 35147119Sbostic if (parsefile->fd > 0) { 35247119Sbostic close(parsefile->fd); 35347119Sbostic parsefile->fd = 0; 35447119Sbostic } 35547119Sbostic } 356