input: Disable lleft in SMALL mode
[dash.git] / src / input.c
blob7b37ae21c619e4f9c4cd38e5cfd724593de1bcbc
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 "eval.h"
46 #include "shell.h"
47 #include "redir.h"
48 #include "syntax.h"
49 #include "input.h"
50 #include "output.h"
51 #include "options.h"
52 #include "memalloc.h"
53 #include "error.h"
54 #include "alias.h"
55 #include "parser.h"
56 #include "main.h"
57 #include "myhistedit.h"
59 #define IBUFSIZ (BUFSIZ + 1)
62 MKINIT struct parsefile basepf; /* top level input file */
63 MKINIT char basebuf[IBUFSIZ]; /* buffer for top level input file */
64 struct parsefile *parsefile = &basepf; /* current input file */
65 int whichprompt; /* 1 == PS1, 2 == PS2 */
67 STATIC void pushfile(void);
68 static void popstring(void);
69 static int preadfd(void);
70 static void setinputfd(int fd, int push);
71 static int preadbuffer(void);
73 #ifdef mkinit
74 INCLUDE <stdio.h>
75 INCLUDE <unistd.h>
76 INCLUDE "input.h"
77 INCLUDE "error.h"
78 INCLUDE "syntax.h"
80 INIT {
81 basepf.nextc = basepf.buf = basebuf;
82 basepf.linno = 1;
85 RESET {
86 /* clear input buffer */
87 popallfiles();
88 basepf.unget = 0;
89 while (basepf.lastc[0] != '\n' &&
90 basepf.lastc[0] != PEOF)
91 pgetc();
94 FORKRESET {
95 popallfiles();
96 if (parsefile->fd > 0) {
97 close(parsefile->fd);
98 parsefile->fd = 0;
101 #endif
104 static void freestrings(struct strpush *sp)
106 INTOFF;
107 do {
108 struct strpush *psp;
110 if (sp->ap) {
111 sp->ap->flag &= ~ALIASINUSE;
112 if (sp->ap->flag & ALIASDEAD) {
113 unalias(sp->ap->name);
117 psp = sp;
118 sp = sp->spfree;
120 if (psp != &(parsefile->basestrpush))
121 ckfree(psp);
122 } while (sp);
124 parsefile->spfree = NULL;
125 INTON;
129 static int __pgetc(void)
131 int c;
133 if (parsefile->unget)
134 return parsefile->lastc[--parsefile->unget];
136 if (--parsefile->nleft >= 0)
137 c = (signed char)*parsefile->nextc++;
138 else
139 c = preadbuffer();
141 parsefile->lastc[1] = parsefile->lastc[0];
142 parsefile->lastc[0] = c;
144 return c;
149 * Read a character from the script, returning PEOF on end of file.
150 * Nul characters in the input are silently discarded.
153 int pgetc(void)
155 struct strpush *sp = parsefile->spfree;
157 if (unlikely(sp))
158 freestrings(sp);
160 return __pgetc();
163 static int stdin_clear_nonblock(void)
165 int flags = fcntl(0, F_GETFL, 0);
167 if (flags >= 0) {
168 flags &=~ O_NONBLOCK;
169 flags = fcntl(0, F_SETFL, flags);
172 return flags;
175 static int
176 preadfd(void)
178 int nr;
179 char *buf = parsefile->buf;
180 parsefile->nextc = buf;
182 retry:
183 #ifndef SMALL
184 if (parsefile->fd == 0 && el) {
185 static const char *rl_cp;
186 static int el_len;
188 if (rl_cp == NULL) {
189 struct stackmark smark;
190 pushstackmark(&smark, stackblocksize());
191 rl_cp = el_gets(el, &el_len);
192 popstackmark(&smark);
194 if (rl_cp == NULL)
195 nr = 0;
196 else {
197 nr = el_len;
198 if (nr > IBUFSIZ - 1)
199 nr = IBUFSIZ - 1;
200 memcpy(buf, rl_cp, nr);
201 if (nr != el_len) {
202 el_len -= nr;
203 rl_cp += nr;
204 } else
205 rl_cp = 0;
208 } else
209 #endif
210 if (parsefile->fd)
211 nr = read(parsefile->fd, buf, IBUFSIZ - 1);
212 else {
213 unsigned len = IBUFSIZ - 1;
215 nr = 0;
217 do {
218 int err;
220 err = read(0, buf, 1);
221 if (err <= 0) {
222 if (nr)
223 break;
225 nr = err;
226 if (errno != EWOULDBLOCK)
227 break;
228 if (stdin_clear_nonblock() < 0)
229 break;
231 out2str("sh: turning off NDELAY mode\n");
232 goto retry;
235 nr++;
236 } while (!IS_DEFINED_SMALL && *buf++ != '\n' && --len);
239 if (nr < 0) {
240 if (errno == EINTR)
241 goto retry;
243 return nr;
247 * Refill the input buffer and return the next input character:
249 * 1) If a string was pushed back on the input, pop it;
250 * 2) If we are reading from a string we can't refill the buffer, return EOF.
251 * 3) If there is more stuff in this buffer, use it else call read to fill it.
252 * 4) Process input up to the next newline, deleting nul characters.
255 static int preadbuffer(void)
257 int something;
258 char savec;
259 int more;
260 char *q;
262 if (unlikely(parsefile->strpush)) {
263 popstring();
264 return __pgetc();
266 if (parsefile->buf == NULL)
267 return PEOF;
268 flushall();
270 more = input_get_lleft(parsefile);
271 if (more <= 0) {
272 again:
273 if ((more = preadfd()) <= 0) {
274 input_set_lleft(parsefile, parsefile->nleft = 0);
275 return PEOF;
279 q = parsefile->nextc;
281 /* delete nul characters */
282 something = 0;
283 for (;;) {
284 int c;
286 more--;
287 c = *q;
289 if (!c) {
290 memmove(q, q + 1, more);
291 goto check;
294 q++;
296 if (IS_DEFINED_SMALL)
297 goto check;
299 switch (c) {
300 case '\n':
301 parsefile->nleft = q - parsefile->nextc - 1;
302 goto check;
304 default:
305 something = 1;
306 /* fall through */
308 case '\t':
309 case ' ':
310 break;
313 check:
314 if (more <= 0) {
315 parsefile->nleft = q - parsefile->nextc - 1;
316 if (parsefile->nleft < 0)
317 goto again;
318 break;
321 input_set_lleft(parsefile, more);
323 if (!IS_DEFINED_SMALL)
324 savec = *q;
325 *q = '\0';
327 if (parsefile->fd == 0 && hist && something) {
328 HistEvent he;
329 INTOFF;
330 history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
331 parsefile->nextc);
332 INTON;
335 if (vflag) {
336 out2str(parsefile->nextc);
337 #ifdef FLUSHERR
338 flushout(out2);
339 #endif
342 if (!IS_DEFINED_SMALL)
343 *q = savec;
345 return (signed char)*parsefile->nextc++;
349 * Undo a call to pgetc. Only two characters may be pushed back.
350 * PEOF may be pushed back.
353 void
354 pungetc(void)
356 parsefile->unget++;
360 * Push a string back onto the input at this current parsefile level.
361 * We handle aliases this way.
363 void
364 pushstring(char *s, void *ap)
366 struct strpush *sp;
367 size_t len;
369 len = strlen(s);
370 INTOFF;
371 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
372 if ((unsigned long)parsefile->strpush |
373 (unsigned long)parsefile->spfree) {
374 sp = ckmalloc(sizeof (struct strpush));
375 sp->prev = parsefile->strpush;
376 parsefile->strpush = sp;
377 } else
378 sp = parsefile->strpush = &(parsefile->basestrpush);
379 sp->prevstring = parsefile->nextc;
380 sp->prevnleft = parsefile->nleft;
381 sp->unget = parsefile->unget;
382 sp->spfree = parsefile->spfree;
383 memcpy(sp->lastc, parsefile->lastc, sizeof(sp->lastc));
384 sp->ap = (struct alias *)ap;
385 if (ap) {
386 ((struct alias *)ap)->flag |= ALIASINUSE;
387 sp->string = s;
389 parsefile->nextc = s;
390 parsefile->nleft = len;
391 parsefile->unget = 0;
392 parsefile->spfree = NULL;
393 INTON;
396 static void popstring(void)
398 struct strpush *sp = parsefile->strpush;
400 INTOFF;
401 if (sp->ap) {
402 if (parsefile->nextc[-1] == ' ' ||
403 parsefile->nextc[-1] == '\t') {
404 checkkwd |= CHKALIAS;
406 if (sp->string != sp->ap->val) {
407 ckfree(sp->string);
410 parsefile->nextc = sp->prevstring;
411 parsefile->nleft = sp->prevnleft;
412 parsefile->unget = sp->unget;
413 memcpy(parsefile->lastc, sp->lastc, sizeof(sp->lastc));
414 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
415 parsefile->strpush = sp->prev;
416 parsefile->spfree = sp;
417 INTON;
421 * Set the input to take input from a file. If push is set, push the
422 * old input onto the stack first.
426 setinputfile(const char *fname, int flags)
428 int fd;
430 INTOFF;
431 fd = sh_open(fname, O_RDONLY, flags & INPUT_NOFILE_OK);
432 if (fd < 0)
433 goto out;
434 if (fd < 10)
435 fd = savefd(fd, fd);
436 setinputfd(fd, flags & INPUT_PUSH_FILE);
437 out:
438 INTON;
439 return fd;
444 * Like setinputfile, but takes an open file descriptor. Call this with
445 * interrupts off.
448 static void
449 setinputfd(int fd, int push)
451 if (push) {
452 pushfile();
453 parsefile->buf = 0;
455 parsefile->fd = fd;
456 if (parsefile->buf == NULL)
457 parsefile->buf = ckmalloc(IBUFSIZ);
458 input_set_lleft(parsefile, parsefile->nleft = 0);
459 plinno = 1;
464 * Like setinputfile, but takes input from a string.
467 void
468 setinputstring(char *string)
470 INTOFF;
471 pushfile();
472 parsefile->nextc = string;
473 parsefile->nleft = strlen(string);
474 parsefile->buf = NULL;
475 plinno = 1;
476 INTON;
482 * To handle the "." command, a stack of input files is used. Pushfile
483 * adds a new entry to the stack and popfile restores the previous level.
486 STATIC void
487 pushfile(void)
489 struct parsefile *pf;
491 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
492 pf->prev = parsefile;
493 pf->fd = -1;
494 pf->strpush = NULL;
495 pf->spfree = NULL;
496 pf->basestrpush.prev = NULL;
497 pf->unget = 0;
498 parsefile = pf;
502 void
503 popfile(void)
505 struct parsefile *pf = parsefile;
507 INTOFF;
508 if (pf->fd >= 0)
509 close(pf->fd);
510 if (pf->buf)
511 ckfree(pf->buf);
512 if (parsefile->spfree)
513 freestrings(parsefile->spfree);
514 while (pf->strpush) {
515 popstring();
516 freestrings(parsefile->spfree);
518 parsefile = pf->prev;
519 ckfree(pf);
520 INTON;
524 void unwindfiles(struct parsefile *stop)
526 while (parsefile != stop)
527 popfile();
532 * Return to top level.
535 void
536 popallfiles(void)
538 unwindfiles(&basepf);