input: Move newline loop into preadbuffer
[dash.git] / src / input.c
blob193235d1688d7e5272d9a49afb26b3fb18a04e22
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 pnr;
196 int nr;
198 nr = input_get_lleft(parsefile);
200 unget = parsefile->nextc - buf;
201 if (unget > PUNGETC_MAX)
202 unget = PUNGETC_MAX;
204 memmove(buf, parsefile->nextc - unget, unget + nr);
205 buf += unget;
206 parsefile->nextc = buf;
207 buf += nr;
209 nr = BUFSIZ - nr;
210 if (!IS_DEFINED_SMALL && !nr)
211 return nr;
213 pnr = nr;
214 retry:
215 nr = pnr;
216 #ifndef SMALL
217 if (parsefile->fd == 0 && el) {
218 static const char *rl_cp;
219 static int el_len;
221 if (rl_cp == NULL) {
222 struct stackmark smark;
223 pushstackmark(&smark, stackblocksize());
224 rl_cp = el_gets(el, &el_len);
225 popstackmark(&smark);
227 if (rl_cp == NULL)
228 nr = 0;
229 else {
230 if (nr > el_len)
231 nr = el_len;
232 memcpy(buf, rl_cp, nr);
233 if (nr != el_len) {
234 el_len -= nr;
235 rl_cp += nr;
236 } else
237 rl_cp = 0;
240 } else
241 #endif
242 if (parsefile->fd)
243 nr = read(parsefile->fd, buf, nr);
244 else {
245 nr = 0;
247 do {
248 int err;
250 err = read(0, buf, 1);
251 if (err <= 0) {
252 if (nr)
253 break;
255 nr = err;
256 if (errno != EWOULDBLOCK)
257 break;
258 if (stdin_clear_nonblock() < 0)
259 break;
261 out2str("sh: turning off NDELAY mode\n");
262 goto retry;
265 nr++;
266 } while (0);
269 if (nr < 0) {
270 if (errno == EINTR && !(basepf.prev && pending_sig))
271 goto retry;
273 return nr;
277 * Refill the input buffer and return the next input character:
279 * 1) If a string was pushed back on the input, pop it;
280 * 2) If we are reading from a string we can't refill the buffer, return EOF.
281 * 3) If there is more stuff in this buffer, use it else call read to fill it.
282 * 4) Process input up to the next newline, deleting nul characters.
285 static int preadbuffer(void)
287 int first = whichprompt == 1;
288 int something;
289 char savec;
290 int more;
291 char *q;
293 if (unlikely(parsefile->strpush)) {
294 popstring();
295 return __pgetc();
297 if (parsefile->buf == NULL)
298 return PEOF;
299 flushall();
301 q = parsefile->nextc;
302 something = !first;
304 more = input_get_lleft(parsefile);
305 if (more <= 0) {
306 int nr;
308 again:
309 nr = q - parsefile->nextc;
310 more = preadfd();
311 q = parsefile->nextc + nr;
312 if (more <= 0) {
313 input_set_lleft(parsefile, parsefile->nleft = 0);
314 if (!IS_DEFINED_SMALL && nr > 0)
315 goto save;
316 return PEOF;
320 /* delete nul characters */
321 for (;;) {
322 int c;
324 more--;
325 c = *q;
327 if (!c) {
328 memmove(q, q + 1, more);
329 goto check;
332 q++;
334 if (IS_DEFINED_SMALL)
335 goto check;
337 switch (c) {
338 case '\n':
339 goto done;
341 default:
342 something = 1;
343 /* fall through */
345 case '\t':
346 case ' ':
347 break;
350 check:
351 if (more <= 0) {
352 if (!IS_DEFINED_SMALL)
353 goto again;
354 break;
357 done:
358 input_set_lleft(parsefile, more);
360 save:
361 parsefile->nleft = q - parsefile->nextc - 1;
362 if (!IS_DEFINED_SMALL)
363 savec = *q;
364 *q = '\0';
366 if (parsefile->fd == 0 && hist && something) {
367 HistEvent he;
368 INTOFF;
369 history(hist, &he, first ? H_ENTER : H_APPEND,
370 parsefile->nextc);
371 INTON;
374 if (vflag) {
375 out2str(parsefile->nextc);
376 #ifdef FLUSHERR
377 flushout(out2);
378 #endif
381 if (!IS_DEFINED_SMALL)
382 *q = savec;
384 return (signed char)*parsefile->nextc++;
387 void pungetn(int n)
389 parsefile->unget += n;
393 * Undo a call to pgetc. Only two characters may be pushed back.
394 * PEOF may be pushed back.
397 void
398 pungetc(void)
400 pungetn(1);
404 * Push a string back onto the input at this current parsefile level.
405 * We handle aliases this way.
407 void
408 pushstring(char *s, void *ap)
410 struct strpush *sp;
411 size_t len;
413 len = strlen(s);
414 INTOFF;
415 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
416 if ((unsigned long)parsefile->strpush |
417 (unsigned long)parsefile->spfree) {
418 sp = ckmalloc(sizeof (struct strpush));
419 sp->prev = parsefile->strpush;
420 parsefile->strpush = sp;
421 } else
422 sp = parsefile->strpush = &(parsefile->basestrpush);
423 sp->prevstring = parsefile->nextc;
424 sp->prevnleft = parsefile->nleft;
425 sp->unget = parsefile->unget;
426 sp->spfree = parsefile->spfree;
427 sp->ap = (struct alias *)ap;
428 if (ap) {
429 ((struct alias *)ap)->flag |= ALIASINUSE;
430 sp->string = ((struct alias *)ap)->name;
432 parsefile->nextc = s;
433 parsefile->nleft = len;
434 parsefile->unget = 0;
435 parsefile->spfree = NULL;
436 INTON;
439 static void popstring(void)
441 struct strpush *sp = parsefile->strpush;
443 INTOFF;
444 if (sp->ap && parsefile->nextc > sp->string) {
445 if (parsefile->nextc[-1] == ' ' ||
446 parsefile->nextc[-1] == '\t') {
447 checkkwd |= CHKALIAS;
449 if (sp->string != sp->ap->name) {
450 ckfree(sp->string);
453 parsefile->nextc = sp->prevstring;
454 parsefile->nleft = sp->prevnleft;
455 parsefile->unget = sp->unget;
456 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
457 parsefile->strpush = sp->prev;
458 parsefile->spfree = sp;
459 INTON;
463 * Set the input to take input from a file. If push is set, push the
464 * old input onto the stack first.
468 setinputfile(const char *fname, int flags)
470 int fd;
472 INTOFF;
473 fd = sh_open(fname, O_RDONLY, flags & INPUT_NOFILE_OK);
474 if (fd < 0)
475 goto out;
476 if (fd < 10)
477 fd = savefd(fd, fd);
478 setinputfd(fd, flags & INPUT_PUSH_FILE);
479 out:
480 INTON;
481 return fd;
486 * Like setinputfile, but takes an open file descriptor. Call this with
487 * interrupts off.
490 static void
491 setinputfd(int fd, int push)
493 pushfile();
494 if (!push)
495 toppf = parsefile;
496 parsefile->fd = fd;
497 parsefile->nextc = parsefile->buf = ckmalloc(IBUFSIZ);
498 input_set_lleft(parsefile, parsefile->nleft = 0);
499 plinno = 1;
504 * Like setinputfile, but takes input from a string.
507 void
508 setinputstring(char *string)
510 INTOFF;
511 pushfile();
512 parsefile->nextc = string;
513 parsefile->nleft = strlen(string);
514 parsefile->buf = NULL;
515 plinno = 1;
516 INTON;
522 * To handle the "." command, a stack of input files is used. Pushfile
523 * adds a new entry to the stack and popfile restores the previous level.
526 STATIC void
527 pushfile(void)
529 struct parsefile *pf;
531 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
532 pf->prev = parsefile;
533 pf->fd = -1;
534 pf->strpush = NULL;
535 pf->spfree = NULL;
536 pf->basestrpush.prev = NULL;
537 pf->unget = 0;
538 parsefile = pf;
541 void pushstdin(void)
543 INTOFF;
544 basepf.prev = parsefile;
545 parsefile = &basepf;
546 INTON;
549 void
550 popfile(void)
552 struct parsefile *pf = parsefile;
554 INTOFF;
555 parsefile = pf->prev;
556 pf->prev = NULL;
557 if (pf == &basepf)
558 goto out;
560 if (pf->fd >= 0)
561 close(pf->fd);
562 if (pf->buf)
563 ckfree(pf->buf);
564 if (parsefile->spfree)
565 freestrings(parsefile->spfree);
566 while (pf->strpush) {
567 popstring();
568 freestrings(parsefile->spfree);
570 ckfree(pf);
572 out:
573 INTON;
577 void __attribute__((noinline)) unwindfiles(struct parsefile *stop)
579 while (basepf.prev || parsefile != stop)
580 popfile();
585 * Return to top level.
588 void
589 popallfiles(void)
591 unwindfiles(toppf);