input.c revision 1.12
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. 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 38/*static char sccsid[] = "from: @(#)input.c 8.1 (Berkeley) 5/31/93";*/ 39static char *rcsid = "$Id: input.c,v 1.12 1994/12/23 13:24:10 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 <string.h> 48#include <fcntl.h> 49#include <errno.h> 50#include <unistd.h> 51#include "shell.h" 52#include "syntax.h" 53#include "input.h" 54#include "output.h" 55#include "options.h" 56#include "memalloc.h" 57#include "error.h" 58#include "alias.h" 59#include "parser.h" 60#include "extern.h" 61#ifndef NO_HISTORY 62#include "myhistedit.h" 63#endif 64 65#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 66 67MKINIT 68struct strpush { 69 struct strpush *prev; /* preceding string on stack */ 70 char *prevstring; 71 int prevnleft; 72 struct alias *ap; /* if push was associated with an alias */ 73}; 74 75/* 76 * The parsefile structure pointed to by the global variable parsefile 77 * contains information about the current file being read. 78 */ 79 80MKINIT 81struct parsefile { 82 struct parsefile *prev; /* preceding file on stack */ 83 int linno; /* current line */ 84 int fd; /* file descriptor (or -1 if string) */ 85 int nleft; /* number of chars left in buffer */ 86 char *nextc; /* next char in buffer */ 87 char *buf; /* input buffer */ 88 struct strpush *strpush; /* for pushing strings at this level */ 89 struct strpush basestrpush; /* so pushing one is fast */ 90}; 91 92 93int plinno = 1; /* input line number */ 94MKINIT int parsenleft; /* copy of parsefile->nleft */ 95char *parsenextc; /* copy of parsefile->nextc */ 96MKINIT struct parsefile basepf; /* top level input file */ 97char basebuf[BUFSIZ]; /* buffer for top level input file */ 98struct parsefile *parsefile = &basepf; /* current input file */ 99char *pushedstring; /* copy of parsenextc when text pushed back */ 100int pushednleft; /* copy of parsenleft when text pushed back */ 101int init_editline = 0; /* editline library initialized? */ 102int whichprompt; /* 1 == PS1, 2 == PS2 */ 103 104#ifndef NO_HISTORY 105EditLine *el; /* cookie for editline package */ 106#endif 107 108#ifdef __STDC__ 109STATIC void pushfile(void); 110#else 111STATIC void pushfile(); 112#endif 113 114void popstring(); 115 116 117 118#ifdef mkinit 119INCLUDE "input.h" 120INCLUDE "error.h" 121 122INIT { 123 extern char basebuf[]; 124 125 basepf.nextc = basepf.buf = basebuf; 126} 127 128RESET { 129 if (exception != EXSHELLPROC) 130 parsenleft = 0; /* clear input buffer */ 131 popallfiles(); 132} 133 134SHELLPROC { 135 popallfiles(); 136} 137#endif 138 139 140/* 141 * Read a line from the script. 142 */ 143 144char * 145pfgets(line, len) 146 char *line; 147 int len; 148{ 149 register char *p = line; 150 int nleft = len; 151 int c; 152 153 while (--nleft > 0) { 154 c = pgetc_macro(); 155 if (c == PEOF) { 156 if (p == line) 157 return NULL; 158 break; 159 } 160 *p++ = c; 161 if (c == '\n') 162 break; 163 } 164 *p = '\0'; 165 return line; 166} 167 168 169 170/* 171 * Read a character from the script, returning PEOF on end of file. 172 * Nul characters in the input are silently discarded. 173 */ 174 175int 176pgetc() { 177 return pgetc_macro(); 178} 179 180 181/* 182 * Refill the input buffer and return the next input character: 183 * 184 * 1) If a string was pushed back on the input, pop it; 185 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 186 * from a string so we can't refill the buffer, return EOF. 187 * 3) Call read to read in the characters. 188 * 4) Delete all nul characters from the buffer. 189 */ 190 191int 192preadbuffer() { 193 register char *p, *q; 194 register int i; 195 register int something; 196#ifndef NO_HISTORY 197 extern EditLine *el; 198#endif 199 200 if (parsefile->strpush) { 201 popstring(); 202 if (--parsenleft >= 0) 203 return (*parsenextc++); 204 } 205 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 206 return PEOF; 207 flushout(&output); 208 flushout(&errout); 209retry: 210 p = parsenextc = parsefile->buf; 211#ifndef NO_HISTORY 212 if (parsefile->fd == 0 && el) { 213 const char *rl_cp; 214 int len; 215 216 rl_cp = el_gets(el, &len); 217 if (rl_cp == NULL) { 218 i = 0; 219 goto eof; 220 } 221 strcpy(p, rl_cp); /* XXX - BUFSIZE should redesign so not necessary */ 222 i = len; 223 224 } else { 225#endif 226regular_read: 227 i = read(parsefile->fd, p, BUFSIZ - 1); 228#ifndef NO_HISTORY 229 } 230#endif 231eof: 232 if (i <= 0) { 233 if (i < 0) { 234 if (errno == EINTR) 235 goto retry; 236 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 237 int flags = fcntl(0, F_GETFL, 0); 238 if (flags >= 0 && flags & O_NONBLOCK) { 239 flags &=~ O_NONBLOCK; 240 if (fcntl(0, F_SETFL, flags) >= 0) { 241 out2str("sh: turning off NDELAY mode\n"); 242 goto retry; 243 } 244 } 245 } 246 } 247 parsenleft = EOF_NLEFT; 248 return PEOF; 249 } 250 parsenleft = i - 1; /* we're returning one char in this call */ 251 252 /* delete nul characters */ 253 something = 0; 254 for (;;) { 255 if (*p == '\0') 256 break; 257 if (*p != ' ' && *p != '\t' && *p != '\n') 258 something = 1; 259 p++; 260 if (--i <= 0) { 261 *p = '\0'; 262 goto done; /* no nul characters */ 263 } 264 } 265 /* 266 * remove nuls 267 */ 268 q = p++; 269 while (--i > 0) { 270 if (*p != '\0') 271 *q++ = *p; 272 p++; 273 } 274 *q = '\0'; 275 if (q == parsefile->buf) 276 goto retry; /* buffer contained nothing but nuls */ 277 parsenleft = q - parsefile->buf - 1; 278 279done: 280#ifndef NO_HISTORY 281 if (parsefile->fd == 0 && hist && something) { 282 INTOFF; 283 history(hist, whichprompt == 1 ? H_ENTER : H_ADD, 284 parsefile->buf); 285 INTON; 286 } 287#endif 288 if (vflag) { 289 /* 290 * This isn't right. Most shells coordinate it with 291 * reading a line at a time. I honestly don't know if its 292 * worth it. 293 */ 294 i = parsenleft + 1; 295 p = parsefile->buf; 296 for (; i--; p++) 297 out2c(*p) 298 flushout(out2); 299 } 300 return *parsenextc++; 301} 302 303/* 304 * Undo the last call to pgetc. Only one character may be pushed back. 305 * PEOF may be pushed back. 306 */ 307 308void 309pungetc() { 310 parsenleft++; 311 parsenextc--; 312} 313 314/* 315 * Push a string back onto the input at this current parsefile level. 316 * We handle aliases this way. 317 */ 318void 319pushstring(s, len, ap) 320 char *s; 321 int len; 322 void *ap; 323 { 324 struct strpush *sp; 325 326 INTOFF; 327/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 328 if (parsefile->strpush) { 329 sp = ckmalloc(sizeof (struct strpush)); 330 sp->prev = parsefile->strpush; 331 parsefile->strpush = sp; 332 } else 333 sp = parsefile->strpush = &(parsefile->basestrpush); 334 sp->prevstring = parsenextc; 335 sp->prevnleft = parsenleft; 336 sp->ap = (struct alias *)ap; 337 if (ap) 338 ((struct alias *)ap)->flag |= ALIASINUSE; 339 parsenextc = s; 340 parsenleft = len; 341 INTON; 342} 343 344void 345popstring() 346{ 347 struct strpush *sp = parsefile->strpush; 348 349 INTOFF; 350 parsenextc = sp->prevstring; 351 parsenleft = sp->prevnleft; 352/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 353 if (sp->ap) 354 sp->ap->flag &= ~ALIASINUSE; 355 parsefile->strpush = sp->prev; 356 if (sp != &(parsefile->basestrpush)) 357 ckfree(sp); 358 INTON; 359} 360 361/* 362 * Set the input to take input from a file. If push is set, push the 363 * old input onto the stack first. 364 */ 365 366void 367setinputfile(fname, push) 368 char *fname; 369 int push; 370{ 371 int fd; 372 int fd2; 373 374 INTOFF; 375 if ((fd = open(fname, O_RDONLY)) < 0) 376 error("Can't open %s", fname); 377 if (fd < 10) { 378 fd2 = copyfd(fd, 10); 379 close(fd); 380 if (fd2 < 0) 381 error("Out of file descriptors"); 382 fd = fd2; 383 } 384 setinputfd(fd, push); 385 INTON; 386} 387 388 389/* 390 * Like setinputfile, but takes an open file descriptor. Call this with 391 * interrupts off. 392 */ 393 394void 395setinputfd(fd, push) 396 int fd; 397 int push; 398{ 399 if (push) { 400 pushfile(); 401 parsefile->buf = ckmalloc(BUFSIZ); 402 } 403 if (parsefile->fd > 0) 404 close(parsefile->fd); 405 parsefile->fd = fd; 406 if (parsefile->buf == NULL) 407 parsefile->buf = ckmalloc(BUFSIZ); 408 parsenleft = 0; 409 plinno = 1; 410} 411 412 413/* 414 * Like setinputfile, but takes input from a string. 415 */ 416 417void 418setinputstring(string, push) 419 char *string; 420 int push; 421{ 422 INTOFF; 423 if (push) 424 pushfile(); 425 parsenextc = string; 426 parsenleft = strlen(string); 427 parsefile->buf = NULL; 428 plinno = 1; 429 INTON; 430} 431 432 433 434/* 435 * To handle the "." command, a stack of input files is used. Pushfile 436 * adds a new entry to the stack and popfile restores the previous level. 437 */ 438 439STATIC void 440pushfile() { 441 struct parsefile *pf; 442 443 parsefile->nleft = parsenleft; 444 parsefile->nextc = parsenextc; 445 parsefile->linno = plinno; 446 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 447 pf->prev = parsefile; 448 pf->fd = -1; 449 pf->strpush = NULL; 450 pf->basestrpush.prev = NULL; 451 parsefile = pf; 452} 453 454 455void 456popfile() { 457 struct parsefile *pf = parsefile; 458 459 INTOFF; 460 if (pf->fd >= 0) 461 close(pf->fd); 462 if (pf->buf) 463 ckfree(pf->buf); 464 while (pf->strpush) 465 popstring(); 466 parsefile = pf->prev; 467 ckfree(pf); 468 parsenleft = parsefile->nleft; 469 parsenextc = parsefile->nextc; 470 plinno = parsefile->linno; 471 INTON; 472} 473 474 475/* 476 * Return to top level. 477 */ 478 479void 480popallfiles() { 481 while (parsefile != &basepf) 482 popfile(); 483} 484 485 486 487/* 488 * Close the file(s) that the shell is reading commands from. Called 489 * after a fork is done. 490 */ 491 492void 493closescript() { 494 popallfiles(); 495 if (parsefile->fd > 0) { 496 close(parsefile->fd); 497 parsefile->fd = 0; 498 } 499} 500