input.c revision 262951
1249259Sdim/*- 2249259Sdim * Copyright (c) 1991, 1993 3249259Sdim * The Regents of the University of California. All rights reserved. 4249259Sdim * 5249259Sdim * This code is derived from software contributed to Berkeley by 6249259Sdim * Kenneth Almquist. 7249259Sdim * 8249259Sdim * Redistribution and use in source and binary forms, with or without 9249259Sdim * modification, are permitted provided that the following conditions 10249259Sdim * are met: 11249259Sdim * 1. Redistributions of source code must retain the above copyright 12249259Sdim * notice, this list of conditions and the following disclaimer. 13249259Sdim * 2. Redistributions in binary form must reproduce the above copyright 14249259Sdim * notice, this list of conditions and the following disclaimer in the 15249259Sdim * documentation and/or other materials provided with the distribution. 16249259Sdim * 4. Neither the name of the University nor the names of its contributors 17249259Sdim * may be used to endorse or promote products derived from this software 18249259Sdim * without specific prior written permission. 19249259Sdim * 20249259Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21249259Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22249259Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23249259Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24249259Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25249259Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26249259Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27249259Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28249259Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29249259Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30249259Sdim * SUCH DAMAGE. 31249259Sdim */ 32249259Sdim 33249259Sdim#ifndef lint 34249259Sdim#if 0 35249259Sdimstatic char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; 36249259Sdim#endif 37249259Sdim#endif /* not lint */ 38249259Sdim#include <sys/cdefs.h> 39249259Sdim__FBSDID("$FreeBSD: stable/10/bin/sh/input.c 262951 2014-03-09 17:04:31Z jmmv $"); 40249259Sdim 41249259Sdim#include <stdio.h> /* defines BUFSIZ */ 42249259Sdim#include <fcntl.h> 43249259Sdim#include <errno.h> 44249259Sdim#include <unistd.h> 45249259Sdim#include <stdlib.h> 46249259Sdim#include <string.h> 47249259Sdim 48249259Sdim/* 49249259Sdim * This file implements the input routines used by the parser. 50249259Sdim */ 51249259Sdim 52249259Sdim#include "shell.h" 53249259Sdim#include "redir.h" 54249259Sdim#include "syntax.h" 55249259Sdim#include "input.h" 56249259Sdim#include "output.h" 57249259Sdim#include "options.h" 58249259Sdim#include "memalloc.h" 59249259Sdim#include "error.h" 60249259Sdim#include "alias.h" 61249259Sdim#include "parser.h" 62249259Sdim#include "myhistedit.h" 63249259Sdim#include "trap.h" 64249259Sdim 65249259Sdim#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 66249259Sdim 67249259Sdimstruct strpush { 68249259Sdim struct strpush *prev; /* preceding string on stack */ 69249259Sdim const char *prevstring; 70249259Sdim int prevnleft; 71249259Sdim int prevlleft; 72249259Sdim struct alias *ap; /* if push was associated with an alias */ 73249259Sdim}; 74249259Sdim 75249259Sdim/* 76249259Sdim * The parsefile structure pointed to by the global variable parsefile 77249259Sdim * contains information about the current file being read. 78249259Sdim */ 79249259Sdim 80249259Sdimstruct parsefile { 81249259Sdim struct parsefile *prev; /* preceding file on stack */ 82249259Sdim int linno; /* current line */ 83249259Sdim int fd; /* file descriptor (or -1 if string) */ 84249259Sdim int nleft; /* number of chars left in this line */ 85249259Sdim int lleft; /* number of lines left in this buffer */ 86249259Sdim const char *nextc; /* next char in buffer */ 87249259Sdim char *buf; /* input buffer */ 88249259Sdim struct strpush *strpush; /* for pushing strings at this level */ 89249259Sdim struct strpush basestrpush; /* so pushing one is fast */ 90249259Sdim}; 91249259Sdim 92249259Sdim 93249259Sdimint plinno = 1; /* input line number */ 94249259Sdimint parsenleft; /* copy of parsefile->nleft */ 95249259Sdimstatic int parselleft; /* copy of parsefile->lleft */ 96249259Sdimconst char *parsenextc; /* copy of parsefile->nextc */ 97249259Sdimstatic char basebuf[BUFSIZ + 1];/* buffer for top level input file */ 98249259Sdimstatic struct parsefile basepf = { /* top level input file */ 99249259Sdim .nextc = basebuf, 100249259Sdim .buf = basebuf 101249259Sdim}; 102249259Sdimstatic struct parsefile *parsefile = &basepf; /* current input file */ 103249259Sdimint whichprompt; /* 1 == PS1, 2 == PS2 */ 104249259Sdim 105249259SdimEditLine *el; /* cookie for editline package */ 106249259Sdim 107249259Sdimstatic void pushfile(void); 108249259Sdimstatic int preadfd(void); 109249259Sdimstatic void popstring(void); 110249259Sdim 111249259Sdimvoid 112249259Sdimresetinput(void) 113249259Sdim{ 114249259Sdim popallfiles(); 115249259Sdim parselleft = parsenleft = 0; /* clear input buffer */ 116249259Sdim} 117249259Sdim 118249259Sdim 119249259Sdim/* 120249259Sdim * Read a line from the script. 121249259Sdim */ 122249259Sdim 123249259Sdimchar * 124249259Sdimpfgets(char *line, int len) 125249259Sdim{ 126249259Sdim char *p = line; 127249259Sdim int nleft = len; 128249259Sdim int c; 129249259Sdim 130249259Sdim while (--nleft > 0) { 131249259Sdim c = pgetc_macro(); 132249259Sdim if (c == PEOF) { 133249259Sdim if (p == line) 134249259Sdim return NULL; 135249259Sdim break; 136249259Sdim } 137249259Sdim *p++ = c; 138249259Sdim if (c == '\n') 139249259Sdim break; 140249259Sdim } 141249259Sdim *p = '\0'; 142249259Sdim return line; 143249259Sdim} 144249259Sdim 145249259Sdim 146249259Sdim 147249259Sdim/* 148249259Sdim * Read a character from the script, returning PEOF on end of file. 149249259Sdim * Nul characters in the input are silently discarded. 150249259Sdim */ 151249259Sdim 152249259Sdimint 153249259Sdimpgetc(void) 154249259Sdim{ 155249259Sdim return pgetc_macro(); 156249259Sdim} 157249259Sdim 158249259Sdim 159249259Sdimstatic int 160249259Sdimpreadfd(void) 161249259Sdim{ 162249259Sdim int nr; 163249259Sdim parsenextc = parsefile->buf; 164249259Sdim 165249259Sdimretry: 166249259Sdim#ifndef NO_HISTORY 167249259Sdim if (parsefile->fd == 0 && el) { 168249259Sdim static const char *rl_cp; 169249259Sdim static int el_len; 170249259Sdim 171249259Sdim if (rl_cp == NULL) { 172249259Sdim el_resize(el); 173249259Sdim rl_cp = el_gets(el, &el_len); 174249259Sdim } 175249259Sdim if (rl_cp == NULL) 176249259Sdim nr = el_len == 0 ? 0 : -1; 177249259Sdim else { 178249259Sdim nr = el_len; 179249259Sdim if (nr > BUFSIZ) 180249259Sdim nr = BUFSIZ; 181249259Sdim memcpy(parsefile->buf, rl_cp, nr); 182249259Sdim if (nr != el_len) { 183249259Sdim el_len -= nr; 184249259Sdim rl_cp += nr; 185249259Sdim } else 186249259Sdim rl_cp = NULL; 187249259Sdim } 188249259Sdim } else 189249259Sdim#endif 190249259Sdim nr = read(parsefile->fd, parsefile->buf, BUFSIZ); 191249259Sdim 192249259Sdim if (nr <= 0) { 193249259Sdim if (nr < 0) { 194249259Sdim if (errno == EINTR) 195249259Sdim goto retry; 196249259Sdim if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 197249259Sdim int flags = fcntl(0, F_GETFL, 0); 198249259Sdim if (flags >= 0 && flags & O_NONBLOCK) { 199249259Sdim flags &=~ O_NONBLOCK; 200249259Sdim if (fcntl(0, F_SETFL, flags) >= 0) { 201249259Sdim out2fmt_flush("sh: turning off NDELAY mode\n"); 202249259Sdim goto retry; 203249259Sdim } 204249259Sdim } 205249259Sdim } 206249259Sdim } 207249259Sdim nr = -1; 208249259Sdim } 209249259Sdim return nr; 210249259Sdim} 211249259Sdim 212249259Sdim/* 213249259Sdim * Refill the input buffer and return the next input character: 214249259Sdim * 215249259Sdim * 1) If a string was pushed back on the input, pop it; 216249259Sdim * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 217249259Sdim * from a string so we can't refill the buffer, return EOF. 218249259Sdim * 3) If there is more in this buffer, use it else call read to fill it. 219249259Sdim * 4) Process input up to the next newline, deleting nul characters. 220249259Sdim */ 221249259Sdim 222249259Sdimint 223249259Sdimpreadbuffer(void) 224249259Sdim{ 225249259Sdim char *p, *q; 226249259Sdim int more; 227249259Sdim char savec; 228249259Sdim 229249259Sdim while (parsefile->strpush) { 230249259Sdim /* 231249259Sdim * Add a space to the end of an alias to ensure that the 232249259Sdim * alias remains in use while parsing its last word. 233249259Sdim * This avoids alias recursions. 234249259Sdim */ 235249259Sdim if (parsenleft == -1 && parsefile->strpush->ap != NULL) 236249259Sdim return ' '; 237249259Sdim popstring(); 238249259Sdim if (--parsenleft >= 0) 239249259Sdim return (*parsenextc++); 240249259Sdim } 241249259Sdim if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 242249259Sdim return PEOF; 243249259Sdim flushout(&output); 244249259Sdim flushout(&errout); 245249259Sdim 246249259Sdimagain: 247249259Sdim if (parselleft <= 0) { 248249259Sdim if ((parselleft = preadfd()) == -1) { 249249259Sdim parselleft = parsenleft = EOF_NLEFT; 250249259Sdim return PEOF; 251249259Sdim } 252249259Sdim } 253249259Sdim 254249259Sdim q = p = parsefile->buf + (parsenextc - parsefile->buf); 255249259Sdim 256249259Sdim /* delete nul characters */ 257249259Sdim for (more = 1; more;) { 258249259Sdim switch (*p) { 259249259Sdim case '\0': 260249259Sdim p++; /* Skip nul */ 261249259Sdim goto check; 262249259Sdim 263249259Sdim case '\n': 264249259Sdim parsenleft = q - parsenextc; 265249259Sdim more = 0; /* Stop processing here */ 266249259Sdim break; 267249259Sdim 268249259Sdim default: 269249259Sdim break; 270249259Sdim } 271249259Sdim 272249259Sdim *q++ = *p++; 273249259Sdimcheck: 274249259Sdim if (--parselleft <= 0) { 275249259Sdim parsenleft = q - parsenextc - 1; 276249259Sdim if (parsenleft < 0) 277249259Sdim goto again; 278249259Sdim *q = '\0'; 279249259Sdim more = 0; 280249259Sdim } 281249259Sdim } 282249259Sdim 283249259Sdim savec = *q; 284249259Sdim *q = '\0'; 285249259Sdim 286249259Sdim#ifndef NO_HISTORY 287249259Sdim if (parsefile->fd == 0 && hist && 288249259Sdim parsenextc[strspn(parsenextc, " \t\n")] != '\0') { 289249259Sdim HistEvent he; 290249259Sdim INTOFF; 291249259Sdim history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD, 292249259Sdim parsenextc); 293249259Sdim INTON; 294249259Sdim } 295249259Sdim#endif 296249259Sdim 297249259Sdim if (vflag) { 298249259Sdim out2str(parsenextc); 299249259Sdim flushout(out2); 300249259Sdim } 301249259Sdim 302249259Sdim *q = savec; 303249259Sdim 304249259Sdim return *parsenextc++; 305249259Sdim} 306249259Sdim 307249259Sdim/* 308249259Sdim * Returns if we are certain we are at EOF. Does not cause any more input 309249259Sdim * to be read from the outside world. 310249259Sdim */ 311249259Sdim 312249259Sdimint 313249259Sdimpreadateof(void) 314249259Sdim{ 315249259Sdim if (parsenleft > 0) 316249259Sdim return 0; 317249259Sdim if (parsefile->strpush) 318249259Sdim return 0; 319249259Sdim if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 320249259Sdim return 1; 321249259Sdim return 0; 322249259Sdim} 323249259Sdim 324249259Sdim/* 325249259Sdim * Undo the last call to pgetc. Only one character may be pushed back. 326249259Sdim * PEOF may be pushed back. 327249259Sdim */ 328249259Sdim 329249259Sdimvoid 330249259Sdimpungetc(void) 331249259Sdim{ 332249259Sdim parsenleft++; 333249259Sdim parsenextc--; 334249259Sdim} 335249259Sdim 336249259Sdim/* 337249259Sdim * Push a string back onto the input at this current parsefile level. 338249259Sdim * We handle aliases this way. 339249259Sdim */ 340249259Sdimvoid 341249259Sdimpushstring(char *s, int len, struct alias *ap) 342249259Sdim{ 343249259Sdim struct strpush *sp; 344249259Sdim 345249259Sdim INTOFF; 346249259Sdim/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/ 347249259Sdim if (parsefile->strpush) { 348249259Sdim sp = ckmalloc(sizeof (struct strpush)); 349249259Sdim sp->prev = parsefile->strpush; 350249259Sdim parsefile->strpush = sp; 351249259Sdim } else 352249259Sdim sp = parsefile->strpush = &(parsefile->basestrpush); 353249259Sdim sp->prevstring = parsenextc; 354249259Sdim sp->prevnleft = parsenleft; 355249259Sdim sp->prevlleft = parselleft; 356249259Sdim sp->ap = ap; 357249259Sdim if (ap) 358249259Sdim ap->flag |= ALIASINUSE; 359249259Sdim parsenextc = s; 360249259Sdim parsenleft = len; 361249259Sdim INTON; 362249259Sdim} 363249259Sdim 364249259Sdimstatic void 365249259Sdimpopstring(void) 366249259Sdim{ 367249259Sdim struct strpush *sp = parsefile->strpush; 368249259Sdim 369249259Sdim INTOFF; 370249259Sdim if (sp->ap) { 371249259Sdim if (parsenextc != sp->ap->val && 372249259Sdim (parsenextc[-1] == ' ' || parsenextc[-1] == '\t')) 373249259Sdim forcealias(); 374249259Sdim sp->ap->flag &= ~ALIASINUSE; 375249259Sdim } 376249259Sdim parsenextc = sp->prevstring; 377249259Sdim parsenleft = sp->prevnleft; 378249259Sdim parselleft = sp->prevlleft; 379249259Sdim/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 380249259Sdim parsefile->strpush = sp->prev; 381249259Sdim if (sp != &(parsefile->basestrpush)) 382249259Sdim ckfree(sp); 383249259Sdim INTON; 384249259Sdim} 385249259Sdim 386249259Sdim/* 387249259Sdim * Set the input to take input from a file. If push is set, push the 388249259Sdim * old input onto the stack first. 389249259Sdim */ 390249259Sdim 391249259Sdimvoid 392249259Sdimsetinputfile(const char *fname, int push) 393249259Sdim{ 394249259Sdim int fd; 395249259Sdim int fd2; 396249259Sdim 397249259Sdim INTOFF; 398249259Sdim if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0) 399249259Sdim error("cannot open %s: %s", fname, strerror(errno)); 400249259Sdim if (fd < 10) { 401249259Sdim fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10); 402249259Sdim close(fd); 403249259Sdim if (fd2 < 0) 404249259Sdim error("Out of file descriptors"); 405249259Sdim fd = fd2; 406249259Sdim } 407249259Sdim setinputfd(fd, push); 408249259Sdim INTON; 409249259Sdim} 410249259Sdim 411249259Sdim 412249259Sdim/* 413249259Sdim * Like setinputfile, but takes an open file descriptor (which should have 414249259Sdim * its FD_CLOEXEC flag already set). Call this with interrupts off. 415249259Sdim */ 416249259Sdim 417249259Sdimvoid 418249259Sdimsetinputfd(int fd, int push) 419249259Sdim{ 420249259Sdim if (push) { 421249259Sdim pushfile(); 422249259Sdim parsefile->buf = ckmalloc(BUFSIZ + 1); 423249259Sdim } 424249259Sdim if (parsefile->fd > 0) 425249259Sdim close(parsefile->fd); 426249259Sdim parsefile->fd = fd; 427249259Sdim if (parsefile->buf == NULL) 428249259Sdim parsefile->buf = ckmalloc(BUFSIZ + 1); 429249259Sdim parselleft = parsenleft = 0; 430249259Sdim plinno = 1; 431249259Sdim} 432249259Sdim 433249259Sdim 434249259Sdim/* 435249259Sdim * Like setinputfile, but takes input from a string. 436249259Sdim */ 437249259Sdim 438249259Sdimvoid 439249259Sdimsetinputstring(const char *string, int push) 440249259Sdim{ 441249259Sdim INTOFF; 442249259Sdim if (push) 443249259Sdim pushfile(); 444249259Sdim parsenextc = string; 445249259Sdim parselleft = parsenleft = strlen(string); 446249259Sdim parsefile->buf = NULL; 447249259Sdim plinno = 1; 448249259Sdim INTON; 449249259Sdim} 450249259Sdim 451249259Sdim 452249259Sdim 453249259Sdim/* 454249259Sdim * To handle the "." command, a stack of input files is used. Pushfile 455249259Sdim * adds a new entry to the stack and popfile restores the previous level. 456249259Sdim */ 457249259Sdim 458249259Sdimstatic void 459249259Sdimpushfile(void) 460249259Sdim{ 461249259Sdim struct parsefile *pf; 462249259Sdim 463249259Sdim parsefile->nleft = parsenleft; 464249259Sdim parsefile->lleft = parselleft; 465249259Sdim parsefile->nextc = parsenextc; 466249259Sdim parsefile->linno = plinno; 467249259Sdim pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 468249259Sdim pf->prev = parsefile; 469249259Sdim pf->fd = -1; 470249259Sdim pf->strpush = NULL; 471249259Sdim pf->basestrpush.prev = NULL; 472249259Sdim parsefile = pf; 473249259Sdim} 474249259Sdim 475249259Sdim 476249259Sdimvoid 477249259Sdimpopfile(void) 478249259Sdim{ 479249259Sdim struct parsefile *pf = parsefile; 480249259Sdim 481249259Sdim INTOFF; 482249259Sdim if (pf->fd >= 0) 483249259Sdim close(pf->fd); 484249259Sdim if (pf->buf) 485249259Sdim ckfree(pf->buf); 486249259Sdim while (pf->strpush) 487249259Sdim popstring(); 488249259Sdim parsefile = pf->prev; 489249259Sdim ckfree(pf); 490249259Sdim parsenleft = parsefile->nleft; 491249259Sdim parselleft = parsefile->lleft; 492249259Sdim parsenextc = parsefile->nextc; 493249259Sdim plinno = parsefile->linno; 494249259Sdim INTON; 495249259Sdim} 496249259Sdim 497249259Sdim 498249259Sdim/* 499249259Sdim * Return current file (to go back to it later using popfilesupto()). 500249259Sdim */ 501249259Sdim 502249259Sdimstruct parsefile * 503249259Sdimgetcurrentfile(void) 504249259Sdim{ 505249259Sdim return parsefile; 506249259Sdim} 507249259Sdim 508249259Sdim 509249259Sdim/* 510249259Sdim * Pop files until the given file is on top again. Useful for regular 511249259Sdim * builtins that read shell commands from files or strings. 512249259Sdim * If the given file is not an active file, an error is raised. 513249259Sdim */ 514249259Sdim 515249259Sdimvoid 516249259Sdimpopfilesupto(struct parsefile *file) 517249259Sdim{ 518249259Sdim while (parsefile != file && parsefile != &basepf) 519249259Sdim popfile(); 520249259Sdim if (parsefile != file) 521249259Sdim error("popfilesupto() misused"); 522249259Sdim} 523249259Sdim 524249259Sdim/* 525249259Sdim * Return to top level. 526249259Sdim */ 527249259Sdim 528249259Sdimvoid 529249259Sdimpopallfiles(void) 530249259Sdim{ 531249259Sdim while (parsefile != &basepf) 532249259Sdim popfile(); 533249259Sdim} 534249259Sdim 535249259Sdim 536249259Sdim 537249259Sdim/* 538249259Sdim * Close the file(s) that the shell is reading commands from. Called 539249259Sdim * after a fork is done. 540249259Sdim */ 541249259Sdim 542249259Sdimvoid 543249259Sdimclosescript(void) 544249259Sdim{ 545249259Sdim popallfiles(); 546249259Sdim if (parsefile->fd > 0) { 547249259Sdim close(parsefile->fd); 548249259Sdim parsefile->fd = 0; 549249259Sdim } 550249259Sdim} 551249259Sdim