input.c revision 117261
11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1991, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * This code is derived from software contributed to Berkeley by 61553Srgrimes * Kenneth Almquist. 71553Srgrimes * 81553Srgrimes * Redistribution and use in source and binary forms, with or without 91553Srgrimes * modification, are permitted provided that the following conditions 101553Srgrimes * are met: 111553Srgrimes * 1. Redistributions of source code must retain the above copyright 121553Srgrimes * notice, this list of conditions and the following disclaimer. 131553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141553Srgrimes * notice, this list of conditions and the following disclaimer in the 151553Srgrimes * documentation and/or other materials provided with the distribution. 161553Srgrimes * 3. All advertising materials mentioning features or use of this software 171553Srgrimes * must display the following acknowledgement: 181553Srgrimes * This product includes software developed by the University of 191553Srgrimes * California, Berkeley and its contributors. 201553Srgrimes * 4. Neither the name of the University nor the names of its contributors 211553Srgrimes * may be used to endorse or promote products derived from this software 221553Srgrimes * without specific prior written permission. 231553Srgrimes * 241553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341553Srgrimes * SUCH DAMAGE. 3530642Scharnier */ 361553Srgrimes 3730642Scharnier#ifndef lint 3830642Scharnier#if 0 3930761Scharnierstatic char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; 401553Srgrimes#endif 411553Srgrimes#endif /* not lint */ 421553Srgrimes#include <sys/cdefs.h> 431553Srgrimes__FBSDID("$FreeBSD: head/bin/sh/input.c 117261 2003-07-05 15:18:44Z dds $"); 441553Srgrimes 451553Srgrimes#include <stdio.h> /* defines BUFSIZ */ 461553Srgrimes#include <fcntl.h> 471553Srgrimes#include <errno.h> 481553Srgrimes#include <unistd.h> 491553Srgrimes#include <stdlib.h> 501553Srgrimes#include <string.h> 511553Srgrimes 521553Srgrimes/* 531553Srgrimes * This file implements the input routines used by the parser. 541553Srgrimes */ 551553Srgrimes 561553Srgrimes#include "shell.h" 571553Srgrimes#include "redir.h" 581553Srgrimes#include "syntax.h" 591553Srgrimes#include "input.h" 601553Srgrimes#include "output.h" 611553Srgrimes#include "options.h" 621553Srgrimes#include "memalloc.h" 631553Srgrimes#include "error.h" 641553Srgrimes#include "alias.h" 651553Srgrimes#include "parser.h" 661553Srgrimes#include "myhistedit.h" 671553Srgrimes#include "trap.h" 681553Srgrimes 691553Srgrimes#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 701553Srgrimes 711553SrgrimesMKINIT 721553Srgrimesstruct strpush { 731553Srgrimes struct strpush *prev; /* preceding string on stack */ 741553Srgrimes char *prevstring; 751553Srgrimes int prevnleft; 761553Srgrimes int prevlleft; 771553Srgrimes struct alias *ap; /* if push was associated with an alias */ 781553Srgrimes}; 791553Srgrimes 801553Srgrimes/* 811553Srgrimes * The parsefile structure pointed to by the global variable parsefile 821553Srgrimes * contains information about the current file being read. 831553Srgrimes */ 841553Srgrimes 851553SrgrimesMKINIT 861553Srgrimesstruct parsefile { 871553Srgrimes struct parsefile *prev; /* preceding file on stack */ 881553Srgrimes int linno; /* current line */ 891553Srgrimes int fd; /* file descriptor (or -1 if string) */ 901553Srgrimes int nleft; /* number of chars left in this line */ 911553Srgrimes int lleft; /* number of lines left in this buffer */ 921553Srgrimes char *nextc; /* next char in buffer */ 931553Srgrimes char *buf; /* input buffer */ 941553Srgrimes struct strpush *strpush; /* for pushing strings at this level */ 951553Srgrimes struct strpush basestrpush; /* so pushing one is fast */ 961553Srgrimes}; 971553Srgrimes 981553Srgrimes 991553Srgrimesint plinno = 1; /* input line number */ 1008857SrgrimesMKINIT int parsenleft; /* copy of parsefile->nleft */ 1011553SrgrimesMKINIT int parselleft; /* copy of parsefile->lleft */ 1021553Srgrimeschar *parsenextc; /* copy of parsefile->nextc */ 1031553SrgrimesMKINIT struct parsefile basepf; /* top level input file */ 1041553Srgrimeschar basebuf[BUFSIZ]; /* buffer for top level input file */ 1051553SrgrimesSTATIC struct parsefile *parsefile = &basepf; /* current input file */ 1061553Srgrimesint init_editline = 0; /* editline library initialized? */ 1071553Srgrimesint whichprompt; /* 1 == PS1, 2 == PS2 */ 1081553Srgrimes 1091553SrgrimesEditLine *el; /* cookie for editline package */ 1101553Srgrimes 1111553SrgrimesSTATIC void pushfile(void); 1121553Srgrimesstatic int preadfd(void); 1131553Srgrimes 1141553Srgrimes#ifdef mkinit 1151553SrgrimesINCLUDE "input.h" 1161553SrgrimesINCLUDE "error.h" 1171553Srgrimes 1181553SrgrimesINIT { 1191553Srgrimes extern char basebuf[]; 1201553Srgrimes 1211553Srgrimes basepf.nextc = basepf.buf = basebuf; 1221553Srgrimes} 1231553Srgrimes 1241553SrgrimesRESET { 1251553Srgrimes if (exception != EXSHELLPROC) 1261553Srgrimes parselleft = parsenleft = 0; /* clear input buffer */ 1271553Srgrimes popallfiles(); 1281553Srgrimes} 1291553Srgrimes 1301553SrgrimesSHELLPROC { 1311553Srgrimes popallfiles(); 1321553Srgrimes} 1331553Srgrimes#endif 1341553Srgrimes 1351553Srgrimes 1361553Srgrimes/* 1371553Srgrimes * Read a line from the script. 1381553Srgrimes */ 1391553Srgrimes 1401553Srgrimeschar * 1411553Srgrimespfgets(char *line, int len) 1421553Srgrimes{ 1431553Srgrimes char *p = line; 1441553Srgrimes int nleft = len; 1451553Srgrimes int c; 1461553Srgrimes 1471553Srgrimes while (--nleft > 0) { 1481553Srgrimes c = pgetc_macro(); 1491553Srgrimes if (c == PEOF) { 1501553Srgrimes if (p == line) 1511553Srgrimes return NULL; 1521553Srgrimes break; 1531553Srgrimes } 15430761Scharnier *p++ = c; 1554840Sbde if (c == '\n') 1561553Srgrimes break; 1571553Srgrimes } 1581553Srgrimes *p = '\0'; 1591553Srgrimes return line; 1601553Srgrimes} 1611553Srgrimes 1621553Srgrimes 1631553Srgrimes 1641553Srgrimes/* 1651553Srgrimes * Read a character from the script, returning PEOF on end of file. 1661553Srgrimes * Nul characters in the input are silently discarded. 1671553Srgrimes */ 1681553Srgrimes 1691553Srgrimesint 1701553Srgrimespgetc(void) 1711553Srgrimes{ 1721553Srgrimes return pgetc_macro(); 1731553Srgrimes} 1741553Srgrimes 1751553Srgrimes 1761553Srgrimesstatic int 1771553Srgrimespreadfd(void) 1781553Srgrimes{ 1791553Srgrimes int nr; 1801553Srgrimes parsenextc = parsefile->buf; 1811553Srgrimes 1821553Srgrimes#ifndef NO_HISTORY 1831553Srgrimes if (el != NULL && gotwinch) { 1841553Srgrimes gotwinch = 0; 1851553Srgrimes el_resize(el); 1861553Srgrimes } 1871553Srgrimes#endif 1881553Srgrimesretry: 1891553Srgrimes#ifndef NO_HISTORY 1901553Srgrimes if (parsefile->fd == 0 && el) { 1911553Srgrimes const char *rl_cp; 1921553Srgrimes 1931553Srgrimes rl_cp = el_gets(el, &nr); 1948857Srgrimes if (rl_cp == NULL) 1951553Srgrimes nr = 0; 1961553Srgrimes else { 1971553Srgrimes /* XXX - BUFSIZE should redesign so not necessary */ 1981553Srgrimes (void) strcpy(parsenextc, rl_cp); 1991553Srgrimes } 2001553Srgrimes } else 2011553Srgrimes#endif 2021553Srgrimes nr = read(parsefile->fd, parsenextc, BUFSIZ - 1); 2031553Srgrimes 2041553Srgrimes if (nr <= 0) { 2051553Srgrimes if (nr < 0) { 2061553Srgrimes if (errno == EINTR) 2071553Srgrimes goto retry; 2081553Srgrimes if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 2091553Srgrimes int flags = fcntl(0, F_GETFL, 0); 2101553Srgrimes if (flags >= 0 && flags & O_NONBLOCK) { 2111553Srgrimes flags &=~ O_NONBLOCK; 2121553Srgrimes if (fcntl(0, F_SETFL, flags) >= 0) { 2131553Srgrimes out2str("sh: turning off NDELAY mode\n"); 2141553Srgrimes goto retry; 2151553Srgrimes } 2161553Srgrimes } 2171553Srgrimes } 2181553Srgrimes } 2191553Srgrimes nr = -1; 2201553Srgrimes } 2211553Srgrimes return nr; 2221553Srgrimes} 2231553Srgrimes 2241553Srgrimes/* 2251553Srgrimes * Refill the input buffer and return the next input character: 2261553Srgrimes * 2271553Srgrimes * 1) If a string was pushed back on the input, pop it; 2281553Srgrimes * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 2291553Srgrimes * from a string so we can't refill the buffer, return EOF. 2301553Srgrimes * 3) If there is more in this buffer, use it else call read to fill it. 2311553Srgrimes * 4) Process input up to the next newline, deleting nul characters. 2321553Srgrimes */ 2331553Srgrimes 2341553Srgrimesint 2351553Srgrimespreadbuffer(void) 2361553Srgrimes{ 2371553Srgrimes char *p, *q; 2381553Srgrimes int more; 2391553Srgrimes int something; 2401553Srgrimes char savec; 2411553Srgrimes 2421553Srgrimes if (parsefile->strpush) { 2431553Srgrimes popstring(); 2441553Srgrimes if (--parsenleft >= 0) 2451553Srgrimes return (*parsenextc++); 2461553Srgrimes } 2471553Srgrimes if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 2481553Srgrimes return PEOF; 2491553Srgrimes flushout(&output); 2501553Srgrimes flushout(&errout); 2511553Srgrimes 2521553Srgrimesagain: 2531553Srgrimes if (parselleft <= 0) { 2541553Srgrimes if ((parselleft = preadfd()) == -1) { 2551553Srgrimes parselleft = parsenleft = EOF_NLEFT; 2561553Srgrimes return PEOF; 2571553Srgrimes } 2581553Srgrimes } 2591553Srgrimes 2601553Srgrimes q = p = parsenextc; 2611553Srgrimes 2621553Srgrimes /* delete nul characters */ 2631553Srgrimes something = 0; 2641553Srgrimes for (more = 1; more;) { 2651553Srgrimes switch (*p) { 2661553Srgrimes case '\0': 2671553Srgrimes p++; /* Skip nul */ 2681553Srgrimes goto check; 2691553Srgrimes 2701553Srgrimes case '\t': 2711553Srgrimes case ' ': 2721553Srgrimes break; 2731553Srgrimes 2741553Srgrimes case '\n': 2751553Srgrimes parsenleft = q - parsenextc; 2761553Srgrimes more = 0; /* Stop processing here */ 27730642Scharnier break; 2781553Srgrimes 2791553Srgrimes default: 2801553Srgrimes something = 1; 2811553Srgrimes break; 2821553Srgrimes } 2831553Srgrimes 2841553Srgrimes *q++ = *p++; 2851553Srgrimescheck: 2861553Srgrimes if (--parselleft <= 0) { 2871553Srgrimes parsenleft = q - parsenextc - 1; 2881553Srgrimes if (parsenleft < 0) 2891553Srgrimes goto again; 2901553Srgrimes *q = '\0'; 2911553Srgrimes more = 0; 2921553Srgrimes } 2931553Srgrimes } 2941553Srgrimes 2951553Srgrimes savec = *q; 2961553Srgrimes *q = '\0'; 2971553Srgrimes 2981553Srgrimes#ifndef NO_HISTORY 2991553Srgrimes if (parsefile->fd == 0 && hist && something) { 3001553Srgrimes HistEvent he; 3011553Srgrimes INTOFF; 3021553Srgrimes history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD, 3031553Srgrimes parsenextc); 3041553Srgrimes INTON; 3051553Srgrimes } 3061553Srgrimes#endif 3071553Srgrimes 3081553Srgrimes if (vflag) { 3091553Srgrimes out2str(parsenextc); 3101553Srgrimes flushout(out2); 3111553Srgrimes } 3121553Srgrimes 3131553Srgrimes *q = savec; 3141553Srgrimes 3151553Srgrimes return *parsenextc++; 3161553Srgrimes} 3171553Srgrimes 3181553Srgrimes/* 3191553Srgrimes * Undo the last call to pgetc. Only one character may be pushed back. 3201553Srgrimes * PEOF may be pushed back. 3211553Srgrimes */ 3221553Srgrimes 3231553Srgrimesvoid 3241553Srgrimespungetc(void) 3251553Srgrimes{ 3261553Srgrimes parsenleft++; 3271553Srgrimes parsenextc--; 3281553Srgrimes} 3291553Srgrimes 3301553Srgrimes/* 3311553Srgrimes * Push a string back onto the input at this current parsefile level. 3321553Srgrimes * We handle aliases this way. 3331553Srgrimes */ 3341553Srgrimesvoid 3351553Srgrimespushstring(char *s, int len, void *ap) 3361553Srgrimes{ 3371553Srgrimes struct strpush *sp; 3381553Srgrimes 3391553Srgrimes INTOFF; 3401553Srgrimes/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 3411553Srgrimes if (parsefile->strpush) { 3421553Srgrimes sp = ckmalloc(sizeof (struct strpush)); 3431553Srgrimes sp->prev = parsefile->strpush; 3441553Srgrimes parsefile->strpush = sp; 3451553Srgrimes } else 3461553Srgrimes sp = parsefile->strpush = &(parsefile->basestrpush); 3471553Srgrimes sp->prevstring = parsenextc; 3481553Srgrimes sp->prevnleft = parsenleft; 3491553Srgrimes sp->prevlleft = parselleft; 3501553Srgrimes sp->ap = (struct alias *)ap; 3511553Srgrimes if (ap) 3521553Srgrimes ((struct alias *)ap)->flag |= ALIASINUSE; 353 parsenextc = s; 354 parsenleft = len; 355 INTON; 356} 357 358void 359popstring(void) 360{ 361 struct strpush *sp = parsefile->strpush; 362 363 INTOFF; 364 parsenextc = sp->prevstring; 365 parsenleft = sp->prevnleft; 366 parselleft = sp->prevlleft; 367/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 368 if (sp->ap) 369 sp->ap->flag &= ~ALIASINUSE; 370 parsefile->strpush = sp->prev; 371 if (sp != &(parsefile->basestrpush)) 372 ckfree(sp); 373 INTON; 374} 375 376/* 377 * Set the input to take input from a file. If push is set, push the 378 * old input onto the stack first. 379 */ 380 381void 382setinputfile(char *fname, int push) 383{ 384 int fd; 385 int fd2; 386 387 INTOFF; 388 if ((fd = open(fname, O_RDONLY)) < 0) 389 error("Can't open %s: %s", fname, strerror(errno)); 390 if (fd < 10) { 391 fd2 = copyfd(fd, 10); 392 close(fd); 393 if (fd2 < 0) 394 error("Out of file descriptors"); 395 fd = fd2; 396 } 397 setinputfd(fd, push); 398 INTON; 399} 400 401 402/* 403 * Like setinputfile, but takes an open file descriptor. Call this with 404 * interrupts off. 405 */ 406 407void 408setinputfd(int fd, int push) 409{ 410 (void)fcntl(fd, F_SETFD, FD_CLOEXEC); 411 if (push) { 412 pushfile(); 413 parsefile->buf = ckmalloc(BUFSIZ); 414 } 415 if (parsefile->fd > 0) 416 close(parsefile->fd); 417 parsefile->fd = fd; 418 if (parsefile->buf == NULL) 419 parsefile->buf = ckmalloc(BUFSIZ); 420 parselleft = parsenleft = 0; 421 plinno = 1; 422} 423 424 425/* 426 * Like setinputfile, but takes input from a string. 427 */ 428 429void 430setinputstring(char *string, int push) 431{ 432 INTOFF; 433 if (push) 434 pushfile(); 435 parsenextc = string; 436 parselleft = parsenleft = strlen(string); 437 parsefile->buf = NULL; 438 plinno = 1; 439 INTON; 440} 441 442 443 444/* 445 * To handle the "." command, a stack of input files is used. Pushfile 446 * adds a new entry to the stack and popfile restores the previous level. 447 */ 448 449STATIC void 450pushfile(void) 451{ 452 struct parsefile *pf; 453 454 parsefile->nleft = parsenleft; 455 parsefile->lleft = parselleft; 456 parsefile->nextc = parsenextc; 457 parsefile->linno = plinno; 458 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 459 pf->prev = parsefile; 460 pf->fd = -1; 461 pf->strpush = NULL; 462 pf->basestrpush.prev = NULL; 463 parsefile = pf; 464} 465 466 467void 468popfile(void) 469{ 470 struct parsefile *pf = parsefile; 471 472 INTOFF; 473 if (pf->fd >= 0) 474 close(pf->fd); 475 if (pf->buf) 476 ckfree(pf->buf); 477 while (pf->strpush) 478 popstring(); 479 parsefile = pf->prev; 480 ckfree(pf); 481 parsenleft = parsefile->nleft; 482 parselleft = parsefile->lleft; 483 parsenextc = parsefile->nextc; 484 plinno = parsefile->linno; 485 INTON; 486} 487 488 489/* 490 * Return to top level. 491 */ 492 493void 494popallfiles(void) 495{ 496 while (parsefile != &basepf) 497 popfile(); 498} 499 500 501 502/* 503 * Close the file(s) that the shell is reading commands from. Called 504 * after a fork is done. 505 */ 506 507void 508closescript(void) 509{ 510 popallfiles(); 511 if (parsefile->fd > 0) { 512 close(parsefile->fd); 513 parsefile->fd = 0; 514 } 515} 516