Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 11135 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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     int fd2;
432    
433     INTOFF;
434     if ((fd = open(fname, O_RDONLY)) < 0) {
435     if (flags & INPUT_NOFILE_OK)
436     goto out;
437     sh_error("Can't open %s", fname);
438     }
439     if (fd < 10) {
440     fd2 = copyfd(fd, 10);
441     close(fd);
442     if (fd2 < 0)
443     sh_error("Out of file descriptors");
444     fd = fd2;
445     }
446     setinputfd(fd, flags & INPUT_PUSH_FILE);
447     out:
448     INTON;
449     return fd;
450     }
451    
452    
453     /*
454     * Like setinputfile, but takes an open file descriptor. Call this with
455     * interrupts off.
456     */
457    
458     void
459     setinputfd(int fd, int push)
460     {
461     (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
462     if (push) {
463     pushfile();
464     parsefile->buf = 0;
465     }
466     parsefile->fd = fd;
467     if (parsefile->buf == NULL)
468     parsefile->buf = ckmalloc(IBUFSIZ);
469     parselleft = parsenleft = 0;
470     plinno = 1;
471     }
472    
473    
474     /*
475     * Like setinputfile, but takes input from a string.
476     */
477    
478     void
479     setinputstring(char *string)
480     {
481     INTOFF;
482     pushfile();
483     parsenextc = string;
484     parsenleft = strlen(string);
485     parsefile->buf = NULL;
486     plinno = 1;
487     INTON;
488     }
489    
490    
491    
492     /*
493     * To handle the "." command, a stack of input files is used. Pushfile
494     * adds a new entry to the stack and popfile restores the previous level.
495     */
496    
497     STATIC void
498     pushfile(void)
499     {
500     struct parsefile *pf;
501    
502     parsefile->nleft = parsenleft;
503     parsefile->lleft = parselleft;
504     parsefile->nextc = parsenextc;
505     parsefile->linno = plinno;
506     pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
507     pf->prev = parsefile;
508     pf->fd = -1;
509     pf->strpush = NULL;
510     pf->basestrpush.prev = NULL;
511     parsefile = pf;
512     }
513    
514    
515     void
516     popfile(void)
517     {
518     struct parsefile *pf = parsefile;
519    
520     INTOFF;
521     if (pf->fd >= 0)
522     close(pf->fd);
523     if (pf->buf)
524     ckfree(pf->buf);
525     while (pf->strpush)
526     popstring();
527     parsefile = pf->prev;
528     ckfree(pf);
529     parsenleft = parsefile->nleft;
530     parselleft = parsefile->lleft;
531     parsenextc = parsefile->nextc;
532     plinno = parsefile->linno;
533     INTON;
534     }
535    
536    
537     /*
538     * Return to top level.
539     */
540    
541     void
542     popallfiles(void)
543     {
544     while (parsefile != &basepf)
545     popfile();
546     }
547    
548    
549    
550     /*
551     * Close the file(s) that the shell is reading commands from. Called
552     * after a fork is done.
553     */
554    
555     void
556     closescript(void)
557     {
558     popallfiles();
559     if (parsefile->fd > 0) {
560     close(parsefile->fd);
561     parsefile->fd = 0;
562     }
563     }