~ubuntu-branches/ubuntu/hardy/klibc/hardy-updates

« back to all changes in this revision

Viewing changes to dash/input.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeff Bailey
  • Date: 2006-01-04 20:24:52 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104202452-ec4v3n829rymukuv
Tags: 1.1.15-0ubuntu1
* New upstream version.

* Patch to fix compilation on parisc64 kernels.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 (*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 *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
}