Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (show annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 10995 byte(s)
-updated to klibc-1.5.15
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.
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 if (fd < 10)
439 fd = savefd(fd);
440 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 }