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