1*47119Sbostic /*- 2*47119Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*47119Sbostic * All rights reserved. 4*47119Sbostic * 5*47119Sbostic * This code is derived from software contributed to Berkeley by 6*47119Sbostic * Kenneth Almquist. 7*47119Sbostic * 8*47119Sbostic * %sccs.include.redist.c% 9*47119Sbostic */ 10*47119Sbostic 11*47119Sbostic #ifndef lint 12*47119Sbostic static char sccsid[] = "@(#)input.c 5.1 (Berkeley) 03/07/91"; 13*47119Sbostic #endif /* not lint */ 14*47119Sbostic 15*47119Sbostic /* 16*47119Sbostic * This file implements the input routines used by the parser. 17*47119Sbostic */ 18*47119Sbostic 19*47119Sbostic #include <stdio.h> /* defines BUFSIZ */ 20*47119Sbostic #include "shell.h" 21*47119Sbostic #include <fcntl.h> 22*47119Sbostic #include <errno.h> 23*47119Sbostic #include "syntax.h" 24*47119Sbostic #include "input.h" 25*47119Sbostic #include "output.h" 26*47119Sbostic #include "memalloc.h" 27*47119Sbostic #include "error.h" 28*47119Sbostic 29*47119Sbostic #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 30*47119Sbostic 31*47119Sbostic 32*47119Sbostic /* 33*47119Sbostic * The parsefile structure pointed to by the global variable parsefile 34*47119Sbostic * contains information about the current file being read. 35*47119Sbostic */ 36*47119Sbostic 37*47119Sbostic MKINIT 38*47119Sbostic struct parsefile { 39*47119Sbostic int linno; /* current line */ 40*47119Sbostic int fd; /* file descriptor (or -1 if string) */ 41*47119Sbostic int nleft; /* number of chars left in buffer */ 42*47119Sbostic char *nextc; /* next char in buffer */ 43*47119Sbostic struct parsefile *prev; /* preceding file on stack */ 44*47119Sbostic char *buf; /* input buffer */ 45*47119Sbostic }; 46*47119Sbostic 47*47119Sbostic 48*47119Sbostic int plinno = 1; /* input line number */ 49*47119Sbostic MKINIT int parsenleft; /* copy of parsefile->nleft */ 50*47119Sbostic char *parsenextc; /* copy of parsefile->nextc */ 51*47119Sbostic MKINIT struct parsefile basepf; /* top level input file */ 52*47119Sbostic char basebuf[BUFSIZ]; /* buffer for top level input file */ 53*47119Sbostic struct parsefile *parsefile = &basepf; /* current input file */ 54*47119Sbostic char *pushedstring; /* copy of parsenextc when text pushed back */ 55*47119Sbostic int pushednleft; /* copy of parsenleft when text pushed back */ 56*47119Sbostic 57*47119Sbostic #ifdef __STDC__ 58*47119Sbostic STATIC void pushfile(void); 59*47119Sbostic #else 60*47119Sbostic STATIC void pushfile(); 61*47119Sbostic #endif 62*47119Sbostic 63*47119Sbostic 64*47119Sbostic 65*47119Sbostic #ifdef mkinit 66*47119Sbostic INCLUDE "input.h" 67*47119Sbostic INCLUDE "error.h" 68*47119Sbostic 69*47119Sbostic INIT { 70*47119Sbostic extern char basebuf[]; 71*47119Sbostic 72*47119Sbostic basepf.nextc = basepf.buf = basebuf; 73*47119Sbostic } 74*47119Sbostic 75*47119Sbostic RESET { 76*47119Sbostic if (exception != EXSHELLPROC) 77*47119Sbostic parsenleft = 0; /* clear input buffer */ 78*47119Sbostic popallfiles(); 79*47119Sbostic } 80*47119Sbostic 81*47119Sbostic SHELLPROC { 82*47119Sbostic popallfiles(); 83*47119Sbostic } 84*47119Sbostic #endif 85*47119Sbostic 86*47119Sbostic 87*47119Sbostic /* 88*47119Sbostic * Read a line from the script. 89*47119Sbostic */ 90*47119Sbostic 91*47119Sbostic char * 92*47119Sbostic pfgets(line, len) 93*47119Sbostic char *line; 94*47119Sbostic { 95*47119Sbostic register char *p = line; 96*47119Sbostic int nleft = len; 97*47119Sbostic int c; 98*47119Sbostic 99*47119Sbostic while (--nleft > 0) { 100*47119Sbostic c = pgetc_macro(); 101*47119Sbostic if (c == PEOF) { 102*47119Sbostic if (p == line) 103*47119Sbostic return NULL; 104*47119Sbostic break; 105*47119Sbostic } 106*47119Sbostic *p++ = c; 107*47119Sbostic if (c == '\n') 108*47119Sbostic break; 109*47119Sbostic } 110*47119Sbostic *p = '\0'; 111*47119Sbostic return line; 112*47119Sbostic } 113*47119Sbostic 114*47119Sbostic 115*47119Sbostic 116*47119Sbostic /* 117*47119Sbostic * Read a character from the script, returning PEOF on end of file. 118*47119Sbostic * Nul characters in the input are silently discarded. 119*47119Sbostic */ 120*47119Sbostic 121*47119Sbostic int 122*47119Sbostic pgetc() { 123*47119Sbostic return pgetc_macro(); 124*47119Sbostic } 125*47119Sbostic 126*47119Sbostic 127*47119Sbostic /* 128*47119Sbostic * Refill the input buffer and return the next input character: 129*47119Sbostic * 130*47119Sbostic * 1) If a string was pushed back on the input, switch back to the regular 131*47119Sbostic * buffer. 132*47119Sbostic * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 133*47119Sbostic * from a string so we can't refill the buffer, return EOF. 134*47119Sbostic * 3) Call read to read in the characters. 135*47119Sbostic * 4) Delete all nul characters from the buffer. 136*47119Sbostic */ 137*47119Sbostic 138*47119Sbostic int 139*47119Sbostic preadbuffer() { 140*47119Sbostic register char *p, *q; 141*47119Sbostic register int i; 142*47119Sbostic 143*47119Sbostic if (pushedstring) { 144*47119Sbostic parsenextc = pushedstring; 145*47119Sbostic pushedstring = NULL; 146*47119Sbostic parsenleft = pushednleft; 147*47119Sbostic if (--parsenleft >= 0) 148*47119Sbostic return *parsenextc++; 149*47119Sbostic } 150*47119Sbostic if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 151*47119Sbostic return PEOF; 152*47119Sbostic flushout(&output); 153*47119Sbostic flushout(&errout); 154*47119Sbostic retry: 155*47119Sbostic p = parsenextc = parsefile->buf; 156*47119Sbostic i = read(parsefile->fd, p, BUFSIZ); 157*47119Sbostic if (i <= 0) { 158*47119Sbostic if (i < 0 && errno == EINTR) 159*47119Sbostic goto retry; 160*47119Sbostic parsenleft = EOF_NLEFT; 161*47119Sbostic return PEOF; 162*47119Sbostic } 163*47119Sbostic parsenleft = i - 1; 164*47119Sbostic 165*47119Sbostic /* delete nul characters */ 166*47119Sbostic for (;;) { 167*47119Sbostic if (*p++ == '\0') 168*47119Sbostic break; 169*47119Sbostic if (--i <= 0) 170*47119Sbostic return *parsenextc++; /* no nul characters */ 171*47119Sbostic } 172*47119Sbostic q = p - 1; 173*47119Sbostic while (--i > 0) { 174*47119Sbostic if (*p != '\0') 175*47119Sbostic *q++ = *p; 176*47119Sbostic p++; 177*47119Sbostic } 178*47119Sbostic if (q == parsefile->buf) 179*47119Sbostic goto retry; /* buffer contained nothing but nuls */ 180*47119Sbostic parsenleft = q - parsefile->buf - 1; 181*47119Sbostic return *parsenextc++; 182*47119Sbostic } 183*47119Sbostic 184*47119Sbostic 185*47119Sbostic /* 186*47119Sbostic * Undo the last call to pgetc. Only one character may be pushed back. 187*47119Sbostic * PEOF may be pushed back. 188*47119Sbostic */ 189*47119Sbostic 190*47119Sbostic void 191*47119Sbostic pungetc() { 192*47119Sbostic parsenleft++; 193*47119Sbostic parsenextc--; 194*47119Sbostic } 195*47119Sbostic 196*47119Sbostic 197*47119Sbostic /* 198*47119Sbostic * Push a string back onto the input. This code doesn't work if the user 199*47119Sbostic * tries to push back more than one string at once. 200*47119Sbostic */ 201*47119Sbostic 202*47119Sbostic void 203*47119Sbostic ppushback(string, length) 204*47119Sbostic char *string; 205*47119Sbostic { 206*47119Sbostic pushedstring = parsenextc; 207*47119Sbostic pushednleft = parsenleft; 208*47119Sbostic parsenextc = string; 209*47119Sbostic parsenleft = length; 210*47119Sbostic } 211*47119Sbostic 212*47119Sbostic 213*47119Sbostic 214*47119Sbostic /* 215*47119Sbostic * Set the input to take input from a file. If push is set, push the 216*47119Sbostic * old input onto the stack first. 217*47119Sbostic */ 218*47119Sbostic 219*47119Sbostic void 220*47119Sbostic setinputfile(fname, push) 221*47119Sbostic char *fname; 222*47119Sbostic { 223*47119Sbostic int fd; 224*47119Sbostic int fd2; 225*47119Sbostic 226*47119Sbostic INTOFF; 227*47119Sbostic if ((fd = open(fname, O_RDONLY)) < 0) 228*47119Sbostic error("Can't open %s", fname); 229*47119Sbostic if (fd < 10) { 230*47119Sbostic fd2 = copyfd(fd, 10); 231*47119Sbostic close(fd); 232*47119Sbostic if (fd2 < 0) 233*47119Sbostic error("Out of file descriptors"); 234*47119Sbostic fd = fd2; 235*47119Sbostic } 236*47119Sbostic setinputfd(fd, push); 237*47119Sbostic INTON; 238*47119Sbostic } 239*47119Sbostic 240*47119Sbostic 241*47119Sbostic /* 242*47119Sbostic * Like setinputfile, but takes an open file descriptor. Call this with 243*47119Sbostic * interrupts off. 244*47119Sbostic */ 245*47119Sbostic 246*47119Sbostic void 247*47119Sbostic setinputfd(fd, push) { 248*47119Sbostic if (push) { 249*47119Sbostic pushfile(); 250*47119Sbostic parsefile->buf = ckmalloc(BUFSIZ); 251*47119Sbostic } 252*47119Sbostic if (parsefile->fd > 0) 253*47119Sbostic close(parsefile->fd); 254*47119Sbostic parsefile->fd = fd; 255*47119Sbostic if (parsefile->buf == NULL) 256*47119Sbostic parsefile->buf = ckmalloc(BUFSIZ); 257*47119Sbostic parsenleft = 0; 258*47119Sbostic plinno = 1; 259*47119Sbostic } 260*47119Sbostic 261*47119Sbostic 262*47119Sbostic /* 263*47119Sbostic * Like setinputfile, but takes input from a string. 264*47119Sbostic */ 265*47119Sbostic 266*47119Sbostic void 267*47119Sbostic setinputstring(string, push) 268*47119Sbostic char *string; 269*47119Sbostic { 270*47119Sbostic INTOFF; 271*47119Sbostic if (push) 272*47119Sbostic pushfile(); 273*47119Sbostic parsenextc = string; 274*47119Sbostic parsenleft = strlen(string); 275*47119Sbostic parsefile->buf = NULL; 276*47119Sbostic plinno = 1; 277*47119Sbostic INTON; 278*47119Sbostic } 279*47119Sbostic 280*47119Sbostic 281*47119Sbostic 282*47119Sbostic /* 283*47119Sbostic * To handle the "." command, a stack of input files is used. Pushfile 284*47119Sbostic * adds a new entry to the stack and popfile restores the previous level. 285*47119Sbostic */ 286*47119Sbostic 287*47119Sbostic STATIC void 288*47119Sbostic pushfile() { 289*47119Sbostic struct parsefile *pf; 290*47119Sbostic 291*47119Sbostic parsefile->nleft = parsenleft; 292*47119Sbostic parsefile->nextc = parsenextc; 293*47119Sbostic parsefile->linno = plinno; 294*47119Sbostic pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 295*47119Sbostic pf->prev = parsefile; 296*47119Sbostic pf->fd = -1; 297*47119Sbostic parsefile = pf; 298*47119Sbostic } 299*47119Sbostic 300*47119Sbostic 301*47119Sbostic void 302*47119Sbostic popfile() { 303*47119Sbostic struct parsefile *pf = parsefile; 304*47119Sbostic 305*47119Sbostic INTOFF; 306*47119Sbostic if (pf->fd >= 0) 307*47119Sbostic close(pf->fd); 308*47119Sbostic if (pf->buf) 309*47119Sbostic ckfree(pf->buf); 310*47119Sbostic parsefile = pf->prev; 311*47119Sbostic ckfree(pf); 312*47119Sbostic parsenleft = parsefile->nleft; 313*47119Sbostic parsenextc = parsefile->nextc; 314*47119Sbostic plinno = parsefile->linno; 315*47119Sbostic INTON; 316*47119Sbostic } 317*47119Sbostic 318*47119Sbostic 319*47119Sbostic /* 320*47119Sbostic * Return to top level. 321*47119Sbostic */ 322*47119Sbostic 323*47119Sbostic void 324*47119Sbostic popallfiles() { 325*47119Sbostic while (parsefile != &basepf) 326*47119Sbostic popfile(); 327*47119Sbostic } 328*47119Sbostic 329*47119Sbostic 330*47119Sbostic 331*47119Sbostic /* 332*47119Sbostic * Close the file(s) that the shell is reading commands from. Called 333*47119Sbostic * after a fork is done. 334*47119Sbostic */ 335*47119Sbostic 336*47119Sbostic void 337*47119Sbostic closescript() { 338*47119Sbostic popallfiles(); 339*47119Sbostic if (parsefile->fd > 0) { 340*47119Sbostic close(parsefile->fd); 341*47119Sbostic parsefile->fd = 0; 342*47119Sbostic } 343*47119Sbostic } 344