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