Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/input.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (hide annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years, 2 months ago) by niro
File MIME type: text/plain
File size: 10995 byte(s)
-updated to klibc-1.5.15
1 niro 532 /*-
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.
6     *
7     * This code is derived from software contributed to Berkeley by
8     * Kenneth Almquist.
9     *
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.
21     *
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.
33     */
34    
35     #include <stdio.h> /* defines BUFSIZ */
36     #include <fcntl.h>
37     #include <unistd.h>
38     #include <stdlib.h>
39     #include <string.h>
40    
41     /*
42     * This file implements the input routines used by the parser.
43     */
44    
45     #include "shell.h"
46     #include "redir.h"
47     #include "syntax.h"
48     #include "input.h"
49     #include "output.h"
50     #include "options.h"
51     #include "memalloc.h"
52     #include "error.h"
53     #include "alias.h"
54     #include "parser.h"
55     #include "main.h"
56     #ifndef SMALL
57     #include "myhistedit.h"
58     #endif
59    
60     #ifdef HETIO
61     #include "hetio.h"
62     #endif
63    
64     #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
65     #define IBUFSIZ (BUFSIZ + 1)
66    
67     MKINIT
68     struct strpush {
69     struct strpush *prev; /* preceding string on stack */
70     char *prevstring;
71     int prevnleft;
72     struct alias *ap; /* if push was associated with an alias */
73     char *string; /* remember the string since it may change */
74     };
75    
76     /*
77     * The parsefile structure pointed to by the global variable parsefile
78     * contains information about the current file being read.
79     */
80    
81     MKINIT
82     struct parsefile {
83     struct parsefile *prev; /* preceding file on stack */
84     int linno; /* current line */
85     int fd; /* file descriptor (or -1 if string) */
86     int nleft; /* number of chars left in this line */
87     int lleft; /* number of chars left in this buffer */
88     char *nextc; /* next char in buffer */
89     char *buf; /* input buffer */
90     struct strpush *strpush; /* for pushing strings at this level */
91     struct strpush basestrpush; /* so pushing one is fast */
92     };
93    
94    
95     int plinno = 1; /* input line number */
96     int parsenleft; /* copy of parsefile->nleft */
97     MKINIT int parselleft; /* copy of parsefile->lleft */
98     char *parsenextc; /* copy of parsefile->nextc */
99     MKINIT struct parsefile basepf; /* top level input file */
100     MKINIT char basebuf[IBUFSIZ]; /* buffer for top level input file */
101     struct parsefile *parsefile = &basepf; /* current input file */
102     int whichprompt; /* 1 == PS1, 2 == PS2 */
103    
104     #ifndef SMALL
105     EditLine *el; /* cookie for editline package */
106     #endif
107    
108     STATIC void pushfile(void);
109     static int preadfd(void);
110    
111     #ifdef mkinit
112     INCLUDE <stdio.h>
113     INCLUDE "input.h"
114     INCLUDE "error.h"
115    
116     INIT {
117     basepf.nextc = basepf.buf = basebuf;
118     }
119    
120     RESET {
121     parselleft = parsenleft = 0; /* clear input buffer */
122     popallfiles();
123     }
124     #endif
125    
126    
127     /*
128     * Read a line from the script.
129     */
130    
131     char *
132     pfgets(char *line, int len)
133     {
134     char *p = line;
135     int nleft = len;
136     int c;
137    
138     while (--nleft > 0) {
139     c = pgetc2();
140     if (c == PEOF) {
141     if (p == line)
142     return NULL;
143     break;
144     }
145     *p++ = c;
146     if (c == '\n')
147     break;
148     }
149     *p = '\0';
150     return line;
151     }
152    
153    
154     /*
155     * Read a character from the script, returning PEOF on end of file.
156     * Nul characters in the input are silently discarded.
157     */
158    
159     int
160     pgetc(void)
161     {
162     return pgetc_macro();
163     }
164    
165    
166     /*
167     * Same as pgetc(), but ignores PEOA.
168     */
169    
170     int
171     pgetc2()
172     {
173     int c;
174     do {
175     c = pgetc_macro();
176     } while (c == PEOA);
177     return c;
178     }
179    
180    
181     static int
182     preadfd(void)
183     {
184     int nr;
185     char *buf = parsefile->buf;
186     parsenextc = buf;
187    
188     retry:
189     #ifndef SMALL
190     if (parsefile->fd == 0 && el) {
191     static const char *rl_cp;
192     static int el_len;
193    
194     if (rl_cp == NULL)
195     rl_cp = el_gets(el, &el_len);
196     if (rl_cp == NULL)
197     nr = 0;
198     else {
199     nr = el_len;
200     if (nr > IBUFSIZ - 1)
201     nr = IBUFSIZ - 1;
202     memcpy(buf, rl_cp, nr);
203     if (nr != el_len) {
204     el_len -= nr;
205     rl_cp += nr;
206     } else
207     rl_cp = 0;
208     }
209    
210     } else
211     #endif
212    
213     #ifdef HETIO
214     nr = hetio_read_input(parsefile->fd);
215     if (nr == -255)
216     #endif
217     nr = read(parsefile->fd, buf, IBUFSIZ - 1);
218    
219    
220     if (nr < 0) {
221     if (errno == EINTR)
222     goto retry;
223     if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
224     int flags = fcntl(0, F_GETFL, 0);
225     if (flags >= 0 && flags & O_NONBLOCK) {
226     flags &=~ O_NONBLOCK;
227     if (fcntl(0, F_SETFL, flags) >= 0) {
228     out2str("sh: turning off NDELAY mode\n");
229     goto retry;
230     }
231     }
232     }
233     }
234     return nr;
235     }
236    
237     /*
238     * Refill the input buffer and return the next input character:
239     *
240     * 1) If a string was pushed back on the input, pop it;
241     * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
242     * from a string so we can't refill the buffer, return EOF.
243     * 3) If the is more stuff in this buffer, use it else call read to fill it.
244     * 4) Process input up to the next newline, deleting nul characters.
245     */
246    
247     int
248     preadbuffer(void)
249     {
250     char *q;
251     int more;
252     #ifndef SMALL
253     int something;
254     #endif
255     char savec;
256    
257     while (unlikely(parsefile->strpush)) {
258     if (
259     parsenleft == -1 && parsefile->strpush->ap &&
260     parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
261     ) {
262     return PEOA;
263     }
264     popstring();
265     if (--parsenleft >= 0)
266     return (signed char)*parsenextc++;
267     }
268     if (unlikely(parsenleft == EOF_NLEFT || parsefile->buf == NULL))
269     return PEOF;
270     flushout(&output);
271     #ifdef FLUSHERR
272     flushout(&errout);
273     #endif
274    
275     more = parselleft;
276     if (more <= 0) {
277     again:
278     if ((more = preadfd()) <= 0) {
279     parselleft = parsenleft = EOF_NLEFT;
280     return PEOF;
281     }
282     }
283    
284     q = parsenextc;
285    
286     /* delete nul characters */
287     #ifndef SMALL
288     something = 0;
289     #endif
290     for (;;) {
291     int c;
292    
293     more--;
294     c = *q;
295    
296     if (!c)
297     memmove(q, q + 1, more);
298     else {
299     q++;
300    
301     if (c == '\n') {
302     parsenleft = q - parsenextc - 1;
303     break;
304     }
305    
306     #ifndef SMALL
307     switch (c) {
308     default:
309     something = 1;
310     /* fall through */
311     case '\t':
312     case ' ':
313     break;
314     }
315     #endif
316     }
317    
318     if (more <= 0) {
319     parsenleft = q - parsenextc - 1;
320     if (parsenleft < 0)
321     goto again;
322     break;
323     }
324     }
325     parselleft = more;
326    
327     savec = *q;
328     *q = '\0';
329    
330     #ifndef SMALL
331     if (parsefile->fd == 0 && hist && something) {
332     HistEvent he;
333     INTOFF;
334     history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
335     parsenextc);
336     INTON;
337     }
338     #endif
339    
340     if (vflag) {
341     out2str(parsenextc);
342     #ifdef FLUSHERR
343     flushout(out2);
344     #endif
345     }
346    
347     *q = savec;
348    
349     return (signed char)*parsenextc++;
350     }
351    
352     /*
353     * Undo the last call to pgetc. Only one character may be pushed back.
354     * PEOF may be pushed back.
355     */
356    
357     void
358     pungetc(void)
359     {
360     parsenleft++;
361     parsenextc--;
362     }
363    
364     /*
365     * Push a string back onto the input at this current parsefile level.
366     * We handle aliases this way.
367     */
368     void
369     pushstring(char *s, void *ap)
370     {
371     struct strpush *sp;
372     size_t len;
373    
374     len = strlen(s);
375     INTOFF;
376     /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
377     if (parsefile->strpush) {
378     sp = ckmalloc(sizeof (struct strpush));
379     sp->prev = parsefile->strpush;
380     parsefile->strpush = sp;
381     } else
382     sp = parsefile->strpush = &(parsefile->basestrpush);
383     sp->prevstring = parsenextc;
384     sp->prevnleft = parsenleft;
385     sp->ap = (struct alias *)ap;
386     if (ap) {
387     ((struct alias *)ap)->flag |= ALIASINUSE;
388     sp->string = s;
389     }
390     parsenextc = s;
391     parsenleft = len;
392     INTON;
393     }
394    
395     void
396     popstring(void)
397     {
398     struct strpush *sp = parsefile->strpush;
399    
400     INTOFF;
401     if (sp->ap) {
402     if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
403     checkkwd |= CHKALIAS;
404     }
405     if (sp->string != sp->ap->val) {
406     ckfree(sp->string);
407     }
408     sp->ap->flag &= ~ALIASINUSE;
409     if (sp->ap->flag & ALIASDEAD) {
410     unalias(sp->ap->name);
411     }
412     }
413     parsenextc = sp->prevstring;
414     parsenleft = sp->prevnleft;
415     /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
416     parsefile->strpush = sp->prev;
417     if (sp != &(parsefile->basestrpush))
418     ckfree(sp);
419     INTON;
420     }
421    
422     /*
423     * Set the input to take input from a file. If push is set, push the
424     * old input onto the stack first.
425     */
426    
427     int
428     setinputfile(const char *fname, int flags)
429     {
430     int fd;
431    
432     INTOFF;
433     if ((fd = open(fname, O_RDONLY)) < 0) {
434     if (flags & INPUT_NOFILE_OK)
435     goto out;
436     sh_error("Can't open %s", fname);
437     }
438 niro 815 if (fd < 10)
439     fd = savefd(fd);
440 niro 532 setinputfd(fd, flags & INPUT_PUSH_FILE);
441     out:
442     INTON;
443     return fd;
444     }
445    
446    
447     /*
448     * Like setinputfile, but takes an open file descriptor. Call this with
449     * interrupts off.
450     */
451    
452     void
453     setinputfd(int fd, int push)
454     {
455     if (push) {
456     pushfile();
457     parsefile->buf = 0;
458     }
459     parsefile->fd = fd;
460     if (parsefile->buf == NULL)
461     parsefile->buf = ckmalloc(IBUFSIZ);
462     parselleft = parsenleft = 0;
463     plinno = 1;
464     }
465    
466    
467     /*
468     * Like setinputfile, but takes input from a string.
469     */
470    
471     void
472     setinputstring(char *string)
473     {
474     INTOFF;
475     pushfile();
476     parsenextc = string;
477     parsenleft = strlen(string);
478     parsefile->buf = NULL;
479     plinno = 1;
480     INTON;
481     }
482    
483    
484    
485     /*
486     * To handle the "." command, a stack of input files is used. Pushfile
487     * adds a new entry to the stack and popfile restores the previous level.
488     */
489    
490     STATIC void
491     pushfile(void)
492     {
493     struct parsefile *pf;
494    
495     parsefile->nleft = parsenleft;
496     parsefile->lleft = parselleft;
497     parsefile->nextc = parsenextc;
498     parsefile->linno = plinno;
499     pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
500     pf->prev = parsefile;
501     pf->fd = -1;
502     pf->strpush = NULL;
503     pf->basestrpush.prev = NULL;
504     parsefile = pf;
505     }
506    
507    
508     void
509     popfile(void)
510     {
511     struct parsefile *pf = parsefile;
512    
513     INTOFF;
514     if (pf->fd >= 0)
515     close(pf->fd);
516     if (pf->buf)
517     ckfree(pf->buf);
518     while (pf->strpush)
519     popstring();
520     parsefile = pf->prev;
521     ckfree(pf);
522     parsenleft = parsefile->nleft;
523     parselleft = parsefile->lleft;
524     parsenextc = parsefile->nextc;
525     plinno = parsefile->linno;
526     INTON;
527     }
528    
529    
530     /*
531     * Return to top level.
532     */
533    
534     void
535     popallfiles(void)
536     {
537     while (parsefile != &basepf)
538     popfile();
539     }
540    
541    
542    
543     /*
544     * Close the file(s) that the shell is reading commands from. Called
545     * after a fork is done.
546     */
547    
548     void
549     closescript(void)
550     {
551     popallfiles();
552     if (parsefile->fd > 0) {
553     close(parsefile->fd);
554     parsefile->fd = 0;
555     }
556     }