Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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