1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * 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 5.8 (Berkeley) 07/15/92"; 13 #endif /* not lint */ 14 15 /* 16 * This file implements the input routines used by the parser. 17 */ 18 19 #include <stdio.h> /* defines BUFSIZ */ 20 #include "shell.h" 21 #include <fcntl.h> 22 #include <errno.h> 23 #include "syntax.h" 24 #include "input.h" 25 #include "output.h" 26 #include "options.h" 27 #include "memalloc.h" 28 #include "error.h" 29 #include "alias.h" 30 #include "parser.h" 31 #include "myhistedit.h" 32 33 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 34 35 MKINIT 36 struct strpush { 37 struct strpush *prev; /* preceding string on stack */ 38 char *prevstring; 39 int prevnleft; 40 struct alias *ap; /* if push was associated with an alias */ 41 }; 42 43 /* 44 * The parsefile structure pointed to by the global variable parsefile 45 * contains information about the current file being read. 46 */ 47 48 MKINIT 49 struct parsefile { 50 struct parsefile *prev; /* preceding file on stack */ 51 int linno; /* current line */ 52 int fd; /* file descriptor (or -1 if string) */ 53 int nleft; /* number of chars left in buffer */ 54 char *nextc; /* next char in buffer */ 55 char *buf; /* input buffer */ 56 struct strpush *strpush; /* for pushing strings at this level */ 57 struct strpush basestrpush; /* so pushing one is fast */ 58 }; 59 60 61 int plinno = 1; /* input line number */ 62 MKINIT int parsenleft; /* copy of parsefile->nleft */ 63 char *parsenextc; /* copy of parsefile->nextc */ 64 MKINIT struct parsefile basepf; /* top level input file */ 65 char basebuf[BUFSIZ]; /* buffer for top level input file */ 66 struct parsefile *parsefile = &basepf; /* current input file */ 67 char *pushedstring; /* copy of parsenextc when text pushed back */ 68 int pushednleft; /* copy of parsenleft when text pushed back */ 69 int init_editline = 0; /* editline library initialized? */ 70 int whichprompt; /* 1 == PS1, 2 == PS2 */ 71 72 EditLine *el; /* cookie for editline package */ 73 74 #ifdef __STDC__ 75 STATIC void pushfile(void); 76 #else 77 STATIC void pushfile(); 78 #endif 79 80 81 82 #ifdef mkinit 83 INCLUDE "input.h" 84 INCLUDE "error.h" 85 86 INIT { 87 extern char basebuf[]; 88 89 basepf.nextc = basepf.buf = basebuf; 90 } 91 92 RESET { 93 if (exception != EXSHELLPROC) 94 parsenleft = 0; /* clear input buffer */ 95 popallfiles(); 96 } 97 98 SHELLPROC { 99 popallfiles(); 100 } 101 #endif 102 103 104 /* 105 * Read a line from the script. 106 */ 107 108 char * 109 pfgets(line, len) 110 char *line; 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 regular_read: 186 i = read(parsefile->fd, p, BUFSIZ - 1); 187 } 188 eof: 189 if (i <= 0) { 190 if (i < 0) { 191 if (errno == EINTR) 192 goto retry; 193 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 194 int flags = fcntl(0, F_GETFL, 0); 195 if (flags >= 0 && flags & O_NONBLOCK) { 196 flags &=~ O_NONBLOCK; 197 if (fcntl(0, F_SETFL, flags) >= 0) { 198 out2str("sh: turning off NDELAY mode\n"); 199 goto retry; 200 } 201 } 202 } 203 } 204 parsenleft = EOF_NLEFT; 205 return PEOF; 206 } 207 parsenleft = i - 1; /* we're returning one char in this call */ 208 209 /* delete nul characters */ 210 something = 0; 211 for (;;) { 212 if (*p == '\0') 213 break; 214 if (*p != ' ' && *p != '\t' && *p != '\n') 215 something = 1; 216 p++; 217 if (--i <= 0) { 218 *p = '\0'; 219 goto done; /* no nul characters */ 220 } 221 } 222 /* 223 * remove nuls 224 */ 225 q = p++; 226 while (--i > 0) { 227 if (*p != '\0') 228 *q++ = *p; 229 p++; 230 } 231 *q = '\0'; 232 if (q == parsefile->buf) 233 goto retry; /* buffer contained nothing but nuls */ 234 parsenleft = q - parsefile->buf - 1; 235 236 done: 237 if (parsefile->fd == 0 && hist && something) { 238 INTOFF; 239 history(hist, whichprompt == 1 ? H_ENTER : H_ADD, 240 parsefile->buf); 241 INTON; 242 } 243 if (vflag) { 244 /* 245 * This isn't right. Most shells coordinate it with 246 * reading a line at a time. I honestly don't know if its 247 * worth it. 248 */ 249 i = parsenleft + 1; 250 p = parsefile->buf; 251 for (; i--; p++) 252 out2c(*p) 253 flushout(out2); 254 } 255 return *parsenextc++; 256 } 257 258 /* 259 * Undo the last call to pgetc. Only one character may be pushed back. 260 * PEOF may be pushed back. 261 */ 262 263 void 264 pungetc() { 265 parsenleft++; 266 parsenextc--; 267 } 268 269 /* 270 * Push a string back onto the input at this current parsefile level. 271 * We handle aliases this way. 272 */ 273 void 274 pushstring(s, len, ap) 275 char *s; 276 int len; 277 void *ap; 278 { 279 struct strpush *sp; 280 281 INTOFF; 282 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 283 if (parsefile->strpush) { 284 sp = ckmalloc(sizeof (struct strpush)); 285 sp->prev = parsefile->strpush; 286 parsefile->strpush = sp; 287 } else 288 sp = parsefile->strpush = &(parsefile->basestrpush); 289 sp->prevstring = parsenextc; 290 sp->prevnleft = parsenleft; 291 sp->ap = (struct alias *)ap; 292 if (ap) 293 ((struct alias *)ap)->flag |= ALIASINUSE; 294 parsenextc = s; 295 parsenleft = len; 296 INTON; 297 } 298 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 { 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 if (push) { 350 pushfile(); 351 parsefile->buf = ckmalloc(BUFSIZ); 352 } 353 if (parsefile->fd > 0) 354 close(parsefile->fd); 355 parsefile->fd = fd; 356 if (parsefile->buf == NULL) 357 parsefile->buf = ckmalloc(BUFSIZ); 358 parsenleft = 0; 359 plinno = 1; 360 } 361 362 363 /* 364 * Like setinputfile, but takes input from a string. 365 */ 366 367 void 368 setinputstring(string, push) 369 char *string; 370 { 371 INTOFF; 372 if (push) 373 pushfile(); 374 parsenextc = string; 375 parsenleft = strlen(string); 376 parsefile->buf = NULL; 377 plinno = 1; 378 INTON; 379 } 380 381 382 383 /* 384 * To handle the "." command, a stack of input files is used. Pushfile 385 * adds a new entry to the stack and popfile restores the previous level. 386 */ 387 388 STATIC void 389 pushfile() { 390 struct parsefile *pf; 391 392 parsefile->nleft = parsenleft; 393 parsefile->nextc = parsenextc; 394 parsefile->linno = plinno; 395 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 396 pf->prev = parsefile; 397 pf->fd = -1; 398 pf->strpush = NULL; 399 pf->basestrpush.prev = NULL; 400 parsefile = pf; 401 } 402 403 404 void 405 popfile() { 406 struct parsefile *pf = parsefile; 407 408 INTOFF; 409 if (pf->fd >= 0) 410 close(pf->fd); 411 if (pf->buf) 412 ckfree(pf->buf); 413 while (pf->strpush) 414 popstring(); 415 parsefile = pf->prev; 416 ckfree(pf); 417 parsenleft = parsefile->nleft; 418 parsenextc = parsefile->nextc; 419 plinno = parsefile->linno; 420 INTON; 421 } 422 423 424 /* 425 * Return to top level. 426 */ 427 428 void 429 popallfiles() { 430 while (parsefile != &basepf) 431 popfile(); 432 } 433 434 435 436 /* 437 * Close the file(s) that the shell is reading commands from. Called 438 * after a fork is done. 439 */ 440 441 void 442 closescript() { 443 popallfiles(); 444 if (parsefile->fd > 0) { 445 close(parsefile->fd); 446 parsefile->fd = 0; 447 } 448 } 449