expand: Support multi-byte characters during field splitting
[dash.git] / src / input.c
blob1c598b2e9b3ce528b95ae69c6e29c3df97f020a0
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 !int_pending())
92 pgetc();
95 FORKRESET {
96 popallfiles();
97 if (parsefile->fd > 0) {
98 close(parsefile->fd);
99 parsefile->fd = 0;
102 #endif
105 static void freestrings(struct strpush *sp)
107 INTOFF;
108 do {
109 struct strpush *psp;
111 if (sp->ap) {
112 sp->ap->flag &= ~ALIASINUSE;
113 if (sp->ap->flag & ALIASDEAD) {
114 unalias(sp->ap->name);
118 psp = sp;
119 sp = sp->spfree;
121 if (psp != &(parsefile->basestrpush))
122 ckfree(psp);
123 } while (sp);
125 parsefile->spfree = NULL;
126 INTON;
130 static int __pgetc(void)
132 int c;
134 if (parsefile->unget)
135 return parsefile->lastc[--parsefile->unget];
137 if (--parsefile->nleft >= 0)
138 c = (signed char)*parsefile->nextc++;
139 else
140 c = preadbuffer();
142 parsefile->lastc[1] = parsefile->lastc[0];
143 parsefile->lastc[0] = c;
145 return c;
150 * Read a character from the script, returning PEOF on end of file.
151 * Nul characters in the input are silently discarded.
154 int pgetc(void)
156 struct strpush *sp = parsefile->spfree;
158 if (unlikely(sp))
159 freestrings(sp);
161 return __pgetc();
164 static int stdin_clear_nonblock(void)
166 int flags = fcntl(0, F_GETFL, 0);
168 if (flags >= 0) {
169 flags &=~ O_NONBLOCK;
170 flags = fcntl(0, F_SETFL, flags);
173 return flags;
176 static int
177 preadfd(void)
179 int nr;
180 char *buf = parsefile->buf;
181 parsefile->nextc = buf;
183 retry:
184 #ifndef SMALL
185 if (parsefile->fd == 0 && el) {
186 static const char *rl_cp;
187 static int el_len;
189 if (rl_cp == NULL) {
190 struct stackmark smark;
191 pushstackmark(&smark, stackblocksize());
192 rl_cp = el_gets(el, &el_len);
193 popstackmark(&smark);
195 if (rl_cp == NULL)
196 nr = 0;
197 else {
198 nr = el_len;
199 if (nr > IBUFSIZ - 1)
200 nr = IBUFSIZ - 1;
201 memcpy(buf, rl_cp, nr);
202 if (nr != el_len) {
203 el_len -= nr;
204 rl_cp += nr;
205 } else
206 rl_cp = 0;
209 } else
210 #endif
211 if (parsefile->fd)
212 nr = read(parsefile->fd, buf, IBUFSIZ - 1);
213 else {
214 unsigned len = IBUFSIZ - 1;
216 nr = 0;
218 do {
219 int err;
221 err = read(0, buf, 1);
222 if (err <= 0) {
223 if (nr)
224 break;
226 nr = err;
227 if (errno != EWOULDBLOCK)
228 break;
229 if (stdin_clear_nonblock() < 0)
230 break;
232 out2str("sh: turning off NDELAY mode\n");
233 goto retry;
236 nr++;
237 } while (!IS_DEFINED_SMALL && *buf++ != '\n' && --len);
240 if (nr < 0) {
241 if (errno == EINTR)
242 goto retry;
244 return nr;
248 * Refill the input buffer and return the next input character:
250 * 1) If a string was pushed back on the input, pop it;
251 * 2) If we are reading from a string we can't refill the buffer, return EOF.
252 * 3) If there is more stuff in this buffer, use it else call read to fill it.
253 * 4) Process input up to the next newline, deleting nul characters.
256 static int preadbuffer(void)
258 int first = whichprompt == 1;
259 int something;
260 char savec;
261 int more;
262 char *q;
264 if (unlikely(parsefile->strpush)) {
265 popstring();
266 return __pgetc();
268 if (parsefile->buf == NULL)
269 return PEOF;
270 flushall();
272 more = input_get_lleft(parsefile);
273 if (more <= 0) {
274 again:
275 if ((more = preadfd()) <= 0) {
276 input_set_lleft(parsefile, parsefile->nleft = 0);
277 return PEOF;
281 q = parsefile->nextc;
283 /* delete nul characters */
284 something = !first;
285 for (;;) {
286 int c;
288 more--;
289 c = *q;
291 if (!c) {
292 memmove(q, q + 1, more);
293 goto check;
296 q++;
298 if (IS_DEFINED_SMALL)
299 goto check;
301 switch (c) {
302 case '\n':
303 parsefile->nleft = q - parsefile->nextc - 1;
304 goto done;
306 default:
307 something = 1;
308 /* fall through */
310 case '\t':
311 case ' ':
312 break;
315 check:
316 if (more <= 0) {
317 parsefile->nleft = q - parsefile->nextc - 1;
318 if (parsefile->nleft < 0)
319 goto again;
320 break;
323 done:
324 input_set_lleft(parsefile, more);
326 if (!IS_DEFINED_SMALL)
327 savec = *q;
328 *q = '\0';
330 if (parsefile->fd == 0 && hist && something) {
331 HistEvent he;
332 INTOFF;
333 history(hist, &he, first ? H_ENTER : H_APPEND,
334 parsefile->nextc);
335 INTON;
338 if (vflag) {
339 out2str(parsefile->nextc);
340 #ifdef FLUSHERR
341 flushout(out2);
342 #endif
345 if (!IS_DEFINED_SMALL)
346 *q = savec;
348 return (signed char)*parsefile->nextc++;
352 * Undo a call to pgetc. Only two characters may be pushed back.
353 * PEOF may be pushed back.
356 void
357 pungetc(void)
359 parsefile->unget++;
363 * Push a string back onto the input at this current parsefile level.
364 * We handle aliases this way.
366 void
367 pushstring(char *s, void *ap)
369 struct strpush *sp;
370 size_t len;
372 len = strlen(s);
373 INTOFF;
374 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
375 if ((unsigned long)parsefile->strpush |
376 (unsigned long)parsefile->spfree) {
377 sp = ckmalloc(sizeof (struct strpush));
378 sp->prev = parsefile->strpush;
379 parsefile->strpush = sp;
380 } else
381 sp = parsefile->strpush = &(parsefile->basestrpush);
382 sp->prevstring = parsefile->nextc;
383 sp->prevnleft = parsefile->nleft;
384 sp->unget = parsefile->unget;
385 sp->spfree = parsefile->spfree;
386 memcpy(sp->lastc, parsefile->lastc, sizeof(sp->lastc));
387 sp->ap = (struct alias *)ap;
388 if (ap) {
389 ((struct alias *)ap)->flag |= ALIASINUSE;
390 sp->string = ((struct alias *)ap)->name;
392 parsefile->nextc = s;
393 parsefile->nleft = len;
394 parsefile->unget = 0;
395 parsefile->spfree = NULL;
396 INTON;
399 static void popstring(void)
401 struct strpush *sp = parsefile->strpush;
403 INTOFF;
404 if (sp->ap && parsefile->nextc > sp->string) {
405 if (parsefile->nextc[-1] == ' ' ||
406 parsefile->nextc[-1] == '\t') {
407 checkkwd |= CHKALIAS;
409 if (sp->string != sp->ap->name) {
410 ckfree(sp->string);
413 parsefile->nextc = sp->prevstring;
414 parsefile->nleft = sp->prevnleft;
415 parsefile->unget = sp->unget;
416 memcpy(parsefile->lastc, sp->lastc, sizeof(sp->lastc));
417 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
418 parsefile->strpush = sp->prev;
419 parsefile->spfree = sp;
420 INTON;
424 * Set the input to take input from a file. If push is set, push the
425 * old input onto the stack first.
429 setinputfile(const char *fname, int flags)
431 int fd;
433 INTOFF;
434 fd = sh_open(fname, O_RDONLY, flags & INPUT_NOFILE_OK);
435 if (fd < 0)
436 goto out;
437 if (fd < 10)
438 fd = savefd(fd, fd);
439 setinputfd(fd, flags & INPUT_PUSH_FILE);
440 out:
441 INTON;
442 return fd;
447 * Like setinputfile, but takes an open file descriptor. Call this with
448 * interrupts off.
451 static void
452 setinputfd(int fd, int push)
454 if (push) {
455 pushfile();
456 parsefile->buf = 0;
458 parsefile->fd = fd;
459 if (parsefile->buf == NULL)
460 parsefile->buf = ckmalloc(IBUFSIZ);
461 input_set_lleft(parsefile, parsefile->nleft = 0);
462 plinno = 1;
467 * Like setinputfile, but takes input from a string.
470 void
471 setinputstring(char *string)
473 INTOFF;
474 pushfile();
475 parsefile->nextc = string;
476 parsefile->nleft = strlen(string);
477 parsefile->buf = NULL;
478 plinno = 1;
479 INTON;
485 * To handle the "." command, a stack of input files is used. Pushfile
486 * adds a new entry to the stack and popfile restores the previous level.
489 STATIC void
490 pushfile(void)
492 struct parsefile *pf;
494 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
495 pf->prev = parsefile;
496 pf->fd = -1;
497 pf->strpush = NULL;
498 pf->spfree = NULL;
499 pf->basestrpush.prev = NULL;
500 pf->unget = 0;
501 parsefile = pf;
505 void
506 popfile(void)
508 struct parsefile *pf = parsefile;
510 INTOFF;
511 if (pf->fd >= 0)
512 close(pf->fd);
513 if (pf->buf)
514 ckfree(pf->buf);
515 if (parsefile->spfree)
516 freestrings(parsefile->spfree);
517 while (pf->strpush) {
518 popstring();
519 freestrings(parsefile->spfree);
521 parsefile = pf->prev;
522 ckfree(pf);
523 INTON;
527 void unwindfiles(struct parsefile *stop)
529 while (parsefile != stop)
530 popfile();
535 * Return to top level.
538 void
539 popallfiles(void)
541 unwindfiles(&basepf);