input.c revision 1.3
1/*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 7/1/91"; 39static char rcsid[] = "$Header: /usr/local/opengrok/home/cvs-mirror/mirrors/netbsd/src/bin/sh/input.c,v 1.3 1993/03/23 00:28:07 cgd Exp $"; 40#endif /* not lint */ 41 42/* 43 * This file implements the input routines used by the parser. 44 */ 45 46#include <stdio.h> /* defines BUFSIZ */ 47#include "shell.h" 48#include <fcntl.h> 49#include <errno.h> 50#include "syntax.h" 51#include "input.h" 52#include "output.h" 53#include "memalloc.h" 54#include "error.h" 55 56#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 57 58 59/* 60 * The parsefile structure pointed to by the global variable parsefile 61 * contains information about the current file being read. 62 */ 63 64MKINIT 65struct parsefile { 66 int linno; /* current line */ 67 int fd; /* file descriptor (or -1 if string) */ 68 int nleft; /* number of chars left in buffer */ 69 char *nextc; /* next char in buffer */ 70 struct parsefile *prev; /* preceding file on stack */ 71 char *buf; /* input buffer */ 72}; 73 74 75int plinno = 1; /* input line number */ 76MKINIT int parsenleft; /* copy of parsefile->nleft */ 77char *parsenextc; /* copy of parsefile->nextc */ 78MKINIT struct parsefile basepf; /* top level input file */ 79char basebuf[BUFSIZ]; /* buffer for top level input file */ 80struct parsefile *parsefile = &basepf; /* current input file */ 81char *pushedstring; /* copy of parsenextc when text pushed back */ 82int pushednleft; /* copy of parsenleft when text pushed back */ 83 84#ifdef __STDC__ 85STATIC void pushfile(void); 86#else 87STATIC void pushfile(); 88#endif 89 90 91 92#ifdef mkinit 93INCLUDE "input.h" 94INCLUDE "error.h" 95 96INIT { 97 extern char basebuf[]; 98 99 basepf.nextc = basepf.buf = basebuf; 100} 101 102RESET { 103 if (exception != EXSHELLPROC) 104 parsenleft = 0; /* clear input buffer */ 105 popallfiles(); 106} 107 108SHELLPROC { 109 popallfiles(); 110} 111#endif 112 113 114/* 115 * Read a line from the script. 116 */ 117 118char * 119pfgets(line, len) 120 char *line; 121 { 122 register char *p = line; 123 int nleft = len; 124 int c; 125 126 while (--nleft > 0) { 127 c = pgetc_macro(); 128 if (c == PEOF) { 129 if (p == line) 130 return NULL; 131 break; 132 } 133 *p++ = c; 134 if (c == '\n') 135 break; 136 } 137 *p = '\0'; 138 return line; 139} 140 141 142 143/* 144 * Read a character from the script, returning PEOF on end of file. 145 * Nul characters in the input are silently discarded. 146 */ 147 148int 149pgetc() { 150 return pgetc_macro(); 151} 152 153 154/* 155 * Refill the input buffer and return the next input character: 156 * 157 * 1) If a string was pushed back on the input, switch back to the regular 158 * buffer. 159 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 160 * from a string so we can't refill the buffer, return EOF. 161 * 3) Call read to read in the characters. 162 * 4) Delete all nul characters from the buffer. 163 */ 164 165int 166preadbuffer() { 167 register char *p, *q; 168 register int i; 169 170 if (pushedstring) { 171 parsenextc = pushedstring; 172 pushedstring = NULL; 173 parsenleft = pushednleft; 174 if (--parsenleft >= 0) 175 return *parsenextc++; 176 } 177 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 178 return PEOF; 179 flushout(&output); 180 flushout(&errout); 181retry: 182 p = parsenextc = parsefile->buf; 183 i = read(parsefile->fd, p, BUFSIZ); 184 if (i <= 0) { 185 if (i < 0) { 186 if (errno == EINTR) 187 goto retry; 188 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 189 int flags = fcntl(0, F_GETFL, 0); 190 if (flags >= 0 && flags & O_NONBLOCK) { 191 flags &=~ O_NONBLOCK; 192 if (fcntl(0, F_SETFL, flags) >= 0) { 193 out2str("sh: turning off NDELAY mode\n"); 194 goto retry; 195 } 196 } 197 } 198 } 199 parsenleft = EOF_NLEFT; 200 return PEOF; 201 } 202 parsenleft = i - 1; 203 204 /* delete nul characters */ 205 for (;;) { 206 if (*p++ == '\0') 207 break; 208 if (--i <= 0) 209 return *parsenextc++; /* no nul characters */ 210 } 211 q = p - 1; 212 while (--i > 0) { 213 if (*p != '\0') 214 *q++ = *p; 215 p++; 216 } 217 if (q == parsefile->buf) 218 goto retry; /* buffer contained nothing but nuls */ 219 parsenleft = q - parsefile->buf - 1; 220 return *parsenextc++; 221} 222 223 224/* 225 * Undo the last call to pgetc. Only one character may be pushed back. 226 * PEOF may be pushed back. 227 */ 228 229void 230pungetc() { 231 parsenleft++; 232 parsenextc--; 233} 234 235 236/* 237 * Push a string back onto the input. This code doesn't work if the user 238 * tries to push back more than one string at once. 239 */ 240 241void 242ppushback(string, length) 243 char *string; 244 { 245 pushedstring = parsenextc; 246 pushednleft = parsenleft; 247 parsenextc = string; 248 parsenleft = length; 249} 250 251 252 253/* 254 * Set the input to take input from a file. If push is set, push the 255 * old input onto the stack first. 256 */ 257 258void 259setinputfile(fname, push) 260 char *fname; 261 { 262 int fd; 263 int fd2; 264 265 INTOFF; 266 if ((fd = open(fname, O_RDONLY)) < 0) 267 error("Can't open %s", fname); 268 if (fd < 10) { 269 fd2 = copyfd(fd, 10); 270 close(fd); 271 if (fd2 < 0) 272 error("Out of file descriptors"); 273 fd = fd2; 274 } 275 setinputfd(fd, push); 276 INTON; 277} 278 279 280/* 281 * Like setinputfile, but takes an open file descriptor. Call this with 282 * interrupts off. 283 */ 284 285void 286setinputfd(fd, push) { 287 if (push) { 288 pushfile(); 289 parsefile->buf = ckmalloc(BUFSIZ); 290 } 291 if (parsefile->fd > 0) 292 close(parsefile->fd); 293 parsefile->fd = fd; 294 if (parsefile->buf == NULL) 295 parsefile->buf = ckmalloc(BUFSIZ); 296 parsenleft = 0; 297 plinno = 1; 298} 299 300 301/* 302 * Like setinputfile, but takes input from a string. 303 */ 304 305void 306setinputstring(string, push) 307 char *string; 308 { 309 INTOFF; 310 if (push) 311 pushfile(); 312 parsenextc = string; 313 parsenleft = strlen(string); 314 parsefile->buf = NULL; 315 plinno = 1; 316 INTON; 317} 318 319 320 321/* 322 * To handle the "." command, a stack of input files is used. Pushfile 323 * adds a new entry to the stack and popfile restores the previous level. 324 */ 325 326STATIC void 327pushfile() { 328 struct parsefile *pf; 329 330 parsefile->nleft = parsenleft; 331 parsefile->nextc = parsenextc; 332 parsefile->linno = plinno; 333 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 334 pf->prev = parsefile; 335 pf->fd = -1; 336 parsefile = pf; 337} 338 339 340void 341popfile() { 342 struct parsefile *pf = parsefile; 343 344 INTOFF; 345 if (pf->fd >= 0) 346 close(pf->fd); 347 if (pf->buf) 348 ckfree(pf->buf); 349 parsefile = pf->prev; 350 ckfree(pf); 351 parsenleft = parsefile->nleft; 352 parsenextc = parsefile->nextc; 353 plinno = parsefile->linno; 354 INTON; 355} 356 357 358/* 359 * Return to top level. 360 */ 361 362void 363popallfiles() { 364 while (parsefile != &basepf) 365 popfile(); 366} 367 368 369 370/* 371 * Close the file(s) that the shell is reading commands from. Called 372 * after a fork is done. 373 */ 374 375void 376closescript() { 377 popallfiles(); 378 if (parsefile->fd > 0) { 379 close(parsefile->fd); 380 parsefile->fd = 0; 381 } 382} 383