builtin: Use pgetc in read(1)
[dash.git] / src / input.c
blob6779069dade5ab7411dc8111b9ad3f2fc9fcaf43
1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1997-2005
5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <stdio.h> /* defines BUFSIZ */
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <string.h>
42 * This file implements the input routines used by the parser.
45 #include "alias.h"
46 #include "error.h"
47 #include "eval.h"
48 #include "input.h"
49 #include "main.h"
50 #include "memalloc.h"
51 #include "myhistedit.h"
52 #include "options.h"
53 #include "output.h"
54 #include "parser.h"
55 #include "redir.h"
56 #include "shell.h"
57 #include "syntax.h"
58 #include "trap.h"
60 #define IBUFSIZ (BUFSIZ + PUNGETC_MAX + 1)
63 MKINIT struct parsefile basepf; /* top level input file */
64 MKINIT char basebuf[IBUFSIZ]; /* buffer for top level input file */
65 MKINIT struct parsefile *toppf = &basepf;
66 struct parsefile *parsefile = &basepf; /* current input file */
67 int whichprompt; /* 1 == PS1, 2 == PS2 */
69 STATIC void pushfile(void);
70 static void popstring(void);
71 static int preadfd(void);
72 static void setinputfd(int fd, int push);
73 static int preadbuffer(void);
75 #ifdef mkinit
76 INCLUDE <stdio.h>
77 INCLUDE <unistd.h>
78 INCLUDE "input.h"
79 INCLUDE "error.h"
80 INCLUDE "syntax.h"
82 INIT {
83 basepf.nextc = basepf.buf = basebuf;
84 basepf.linno = 1;
87 RESET {
88 int c;
90 /* clear input buffer */
91 popallfiles();
93 c = PEOF;
94 if (toppf->nextc - toppf->buf > toppf->unget)
95 c = toppf->nextc[-toppf->unget - 1];
96 while (c != '\n' && c != PEOF && !int_pending())
97 c = pgetc();
100 FORKRESET {
101 popallfiles();
102 if (parsefile->fd > 0) {
103 close(parsefile->fd);
104 parsefile->fd = 0;
107 #endif
110 static void freestrings(struct strpush *sp)
112 INTOFF;
113 do {
114 struct strpush *psp;
116 if (sp->ap) {
117 sp->ap->flag &= ~ALIASINUSE;
118 if (sp->ap->flag & ALIASDEAD) {
119 unalias(sp->ap->name);
123 psp = sp;
124 sp = sp->spfree;
126 if (psp != &(parsefile->basestrpush))
127 ckfree(psp);
128 } while (sp);
130 parsefile->spfree = NULL;
131 INTON;
135 static int __pgetc(void)
137 int c;
139 if (parsefile->unget) {
140 long unget = -(long)(unsigned)parsefile->unget--;
142 if (parsefile->nleft < 0)
143 return preadbuffer();
145 return parsefile->nextc[unget];
148 if (--parsefile->nleft >= 0)
149 c = (signed char)*parsefile->nextc++;
150 else
151 c = preadbuffer();
153 return c;
158 * Read a character from the script, returning PEOF on end of file.
159 * Nul characters in the input are silently discarded.
162 int __attribute__((noinline)) pgetc(void)
164 struct strpush *sp = parsefile->spfree;
166 if (unlikely(sp))
167 freestrings(sp);
169 return __pgetc();
172 int pgetc_eoa(void)
174 return parsefile->strpush && parsefile->nleft == -1 &&
175 parsefile->strpush->ap ? PEOA : pgetc();
178 static int stdin_clear_nonblock(void)
180 int flags = fcntl(0, F_GETFL, 0);
182 if (flags >= 0) {
183 flags &=~ O_NONBLOCK;
184 flags = fcntl(0, F_SETFL, flags);
187 return flags;
190 static int
191 preadfd(void)
193 char *buf = parsefile->buf;
194 int unget;
195 int nr;
197 unget = parsefile->nextc - buf;
198 if (unget > PUNGETC_MAX)
199 unget = PUNGETC_MAX;
201 memmove(buf, parsefile->nextc - unget, unget);
202 parsefile->nextc = buf += unget;
204 retry:
205 #ifndef SMALL
206 if (parsefile->fd == 0 && el) {
207 static const char *rl_cp;
208 static int el_len;
210 if (rl_cp == NULL) {
211 struct stackmark smark;
212 pushstackmark(&smark, stackblocksize());
213 rl_cp = el_gets(el, &el_len);
214 popstackmark(&smark);
216 if (rl_cp == NULL)
217 nr = 0;
218 else {
219 nr = el_len;
220 if (nr > BUFSIZ)
221 nr = BUFSIZ;
222 memcpy(buf, rl_cp, nr);
223 if (nr != el_len) {
224 el_len -= nr;
225 rl_cp += nr;
226 } else
227 rl_cp = 0;
230 } else
231 #endif
232 if (parsefile->fd)
233 nr = read(parsefile->fd, buf, BUFSIZ);
234 else {
235 unsigned len = BUFSIZ;
237 nr = 0;
239 do {
240 int err;
242 err = read(0, buf, 1);
243 if (err <= 0) {
244 if (nr)
245 break;
247 nr = err;
248 if (errno != EWOULDBLOCK)
249 break;
250 if (stdin_clear_nonblock() < 0)
251 break;
253 out2str("sh: turning off NDELAY mode\n");
254 goto retry;
257 nr++;
258 } while (!IS_DEFINED_SMALL && *buf++ != '\n' && --len);
261 if (nr < 0) {
262 if (errno == EINTR && !(basepf.prev && pending_sig))
263 goto retry;
265 return nr;
269 * Refill the input buffer and return the next input character:
271 * 1) If a string was pushed back on the input, pop it;
272 * 2) If we are reading from a string we can't refill the buffer, return EOF.
273 * 3) If there is more stuff in this buffer, use it else call read to fill it.
274 * 4) Process input up to the next newline, deleting nul characters.
277 static int preadbuffer(void)
279 int first = whichprompt == 1;
280 int something;
281 char savec;
282 int more;
283 char *q;
285 if (unlikely(parsefile->strpush)) {
286 popstring();
287 return __pgetc();
289 if (parsefile->buf == NULL)
290 return PEOF;
291 flushall();
293 more = input_get_lleft(parsefile);
294 if (more <= 0) {
295 again:
296 if ((more = preadfd()) <= 0) {
297 input_set_lleft(parsefile, parsefile->nleft = 0);
298 return PEOF;
302 q = parsefile->nextc;
304 /* delete nul characters */
305 something = !first;
306 for (;;) {
307 int c;
309 more--;
310 c = *q;
312 if (!c) {
313 memmove(q, q + 1, more);
314 goto check;
317 q++;
319 if (IS_DEFINED_SMALL)
320 goto check;
322 switch (c) {
323 case '\n':
324 parsefile->nleft = q - parsefile->nextc - 1;
325 goto done;
327 default:
328 something = 1;
329 /* fall through */
331 case '\t':
332 case ' ':
333 break;
336 check:
337 if (more <= 0) {
338 parsefile->nleft = q - parsefile->nextc - 1;
339 if (parsefile->nleft < 0)
340 goto again;
341 break;
344 done:
345 input_set_lleft(parsefile, more);
347 if (!IS_DEFINED_SMALL)
348 savec = *q;
349 *q = '\0';
351 if (parsefile->fd == 0 && hist && something) {
352 HistEvent he;
353 INTOFF;
354 history(hist, &he, first ? H_ENTER : H_APPEND,
355 parsefile->nextc);
356 INTON;
359 if (vflag) {
360 out2str(parsefile->nextc);
361 #ifdef FLUSHERR
362 flushout(out2);
363 #endif
366 if (!IS_DEFINED_SMALL)
367 *q = savec;
369 return (signed char)*parsefile->nextc++;
372 void pungetn(int n)
374 parsefile->unget += n;
378 * Undo a call to pgetc. Only two characters may be pushed back.
379 * PEOF may be pushed back.
382 void
383 pungetc(void)
385 pungetn(1);
389 * Push a string back onto the input at this current parsefile level.
390 * We handle aliases this way.
392 void
393 pushstring(char *s, void *ap)
395 struct strpush *sp;
396 size_t len;
398 len = strlen(s);
399 INTOFF;
400 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
401 if ((unsigned long)parsefile->strpush |
402 (unsigned long)parsefile->spfree) {
403 sp = ckmalloc(sizeof (struct strpush));
404 sp->prev = parsefile->strpush;
405 parsefile->strpush = sp;
406 } else
407 sp = parsefile->strpush = &(parsefile->basestrpush);
408 sp->prevstring = parsefile->nextc;
409 sp->prevnleft = parsefile->nleft;
410 sp->unget = parsefile->unget;
411 sp->spfree = parsefile->spfree;
412 sp->ap = (struct alias *)ap;
413 if (ap) {
414 ((struct alias *)ap)->flag |= ALIASINUSE;
415 sp->string = ((struct alias *)ap)->name;
417 parsefile->nextc = s;
418 parsefile->nleft = len;
419 parsefile->unget = 0;
420 parsefile->spfree = NULL;
421 INTON;
424 static void popstring(void)
426 struct strpush *sp = parsefile->strpush;
428 INTOFF;
429 if (sp->ap && parsefile->nextc > sp->string) {
430 if (parsefile->nextc[-1] == ' ' ||
431 parsefile->nextc[-1] == '\t') {
432 checkkwd |= CHKALIAS;
434 if (sp->string != sp->ap->name) {
435 ckfree(sp->string);
438 parsefile->nextc = sp->prevstring;
439 parsefile->nleft = sp->prevnleft;
440 parsefile->unget = sp->unget;
441 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
442 parsefile->strpush = sp->prev;
443 parsefile->spfree = sp;
444 INTON;
448 * Set the input to take input from a file. If push is set, push the
449 * old input onto the stack first.
453 setinputfile(const char *fname, int flags)
455 int fd;
457 INTOFF;
458 fd = sh_open(fname, O_RDONLY, flags & INPUT_NOFILE_OK);
459 if (fd < 0)
460 goto out;
461 if (fd < 10)
462 fd = savefd(fd, fd);
463 setinputfd(fd, flags & INPUT_PUSH_FILE);
464 out:
465 INTON;
466 return fd;
471 * Like setinputfile, but takes an open file descriptor. Call this with
472 * interrupts off.
475 static void
476 setinputfd(int fd, int push)
478 pushfile();
479 if (!push)
480 toppf = parsefile;
481 parsefile->fd = fd;
482 parsefile->nextc = parsefile->buf = ckmalloc(IBUFSIZ);
483 input_set_lleft(parsefile, parsefile->nleft = 0);
484 plinno = 1;
489 * Like setinputfile, but takes input from a string.
492 void
493 setinputstring(char *string)
495 INTOFF;
496 pushfile();
497 parsefile->nextc = string;
498 parsefile->nleft = strlen(string);
499 parsefile->buf = NULL;
500 plinno = 1;
501 INTON;
507 * To handle the "." command, a stack of input files is used. Pushfile
508 * adds a new entry to the stack and popfile restores the previous level.
511 STATIC void
512 pushfile(void)
514 struct parsefile *pf;
516 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
517 pf->prev = parsefile;
518 pf->fd = -1;
519 pf->strpush = NULL;
520 pf->spfree = NULL;
521 pf->basestrpush.prev = NULL;
522 pf->unget = 0;
523 parsefile = pf;
526 void pushstdin(void)
528 INTOFF;
529 basepf.prev = parsefile;
530 parsefile = &basepf;
531 INTON;
534 void
535 popfile(void)
537 struct parsefile *pf = parsefile;
539 INTOFF;
540 parsefile = pf->prev;
541 pf->prev = NULL;
542 if (pf == &basepf)
543 goto out;
545 if (pf->fd >= 0)
546 close(pf->fd);
547 if (pf->buf)
548 ckfree(pf->buf);
549 if (parsefile->spfree)
550 freestrings(parsefile->spfree);
551 while (pf->strpush) {
552 popstring();
553 freestrings(parsefile->spfree);
555 ckfree(pf);
557 out:
558 INTON;
562 void __attribute__((noinline)) unwindfiles(struct parsefile *stop)
564 while (basepf.prev || parsefile != stop)
565 popfile();
570 * Return to top level.
573 void
574 popallfiles(void)
576 unwindfiles(toppf);