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