Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (show 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 /*-
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 #include "var.h"
57 #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 static void setinputfd(int fd, int push);
112
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 if (fd < 10)
414 fd = savefd(fd, fd);
415 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 static void
428 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
533
534 int lineno_inc(void)
535 {
536 int lineno = plinno++;
537
538 setvarint("LINENO", lineno, 0);
539 return lineno;
540 }