~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/3rdparty/qtcsh/sh.dol.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * sh.dol.c: Variable substitutions
 
3
 */
 
4
/*-
 
5
 * Copyright (c) 1980, 1991 The Regents of the University of California.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions
 
10
 * are met:
 
11
 * 1. Redistributions of source code must retain the above copyright
 
12
 *    notice, this list of conditions and the following disclaimer.
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer in the
 
15
 *    documentation and/or other materials provided with the distribution.
 
16
 * 3. All advertising materials mentioning features or use of this software
 
17
 *    must display the following acknowledgement:
 
18
 *      This product includes software developed by the University of
 
19
 *      California, Berkeley and its contributors.
 
20
 * 4. Neither the name of the University nor the names of its contributors
 
21
 *    may be used to endorse or promote products derived from this software
 
22
 *    without specific prior written permission.
 
23
 *
 
24
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
25
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
26
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
27
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
28
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
29
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
30
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
31
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
33
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
34
 * SUCH DAMAGE.
 
35
 */
 
36
#include "sh.h"
 
37
 
 
38
RCSID("$Id$")
 
39
 
 
40
/*
 
41
 * C shell
 
42
 */
 
43
 
 
44
/*
 
45
 * These routines perform variable substitution and quoting via ' and ".
 
46
 * To this point these constructs have been preserved in the divided
 
47
 * input words.  Here we expand variables and turn quoting via ' and " into
 
48
 * QUOTE bits on characters (which prevent further interpretation).
 
49
 * If the `:q' modifier was applied during history expansion, then
 
50
 * some QUOTEing may have occurred already, so we dont "trim()" here.
 
51
 */
 
52
 
 
53
static int Dpeekc, Dpeekrd;     /* Peeks for DgetC and Dreadc */
 
54
static Char *Dcp, **Dvp;        /* Input vector for Dreadc */
 
55
 
 
56
#define DEOF    -1
 
57
 
 
58
#define unDgetC(c)      Dpeekc = c
 
59
 
 
60
#define QUOTES          (_QF|_QB|_ESC)  /* \ ' " ` */
 
61
 
 
62
/*
 
63
 * The following variables give the information about the current
 
64
 * $ expansion, recording the current word position, the remaining
 
65
 * words within this expansion, the count of remaining words, and the
 
66
 * information about any : modifier which is being applied.
 
67
 */
 
68
#define MAXWLEN (BUFSIZE - 4)
 
69
#ifndef COMPAT
 
70
#define MAXMOD MAXWLEN          /* This cannot overflow */
 
71
#endif /* COMPAT */
 
72
static Char *dolp;              /* Remaining chars from this word */
 
73
static Char **dolnxt;           /* Further words */
 
74
static int dolcnt;              /* Count of further words */
 
75
#ifdef COMPAT
 
76
static Char dolmod;             /* : modifier character */
 
77
#else
 
78
static Char dolmod[MAXMOD];     /* : modifier character */
 
79
static int dolnmod;             /* Number of modifiers */
 
80
#endif /* COMPAT */
 
81
static int dolmcnt;             /* :gx -> 10000, else 1 */
 
82
static int dolwcnt;             /* :ax -> 10000, else 1 */
 
83
 
 
84
static  void     Dfix2          __P((Char **));
 
85
static  Char    *Dpack          __P((Char *, Char *));
 
86
static  int      Dword          __P((void));
 
87
static  void     dolerror       __P((Char *));
 
88
static  int      DgetC          __P((int));
 
89
static  void     Dgetdol        __P((void));
 
90
static  void     fixDolMod      __P((void));
 
91
static  void     setDolp        __P((Char *));
 
92
static  void     unDredc        __P((int));
 
93
static  int      Dredc          __P((void));
 
94
static  void     Dtestq         __P((int));
 
95
 
 
96
/*
 
97
 * Fix up the $ expansions and quotations in the
 
98
 * argument list to command t.
 
99
 */
 
100
void
 
101
Dfix(t)
 
102
    register struct command *t;
 
103
{
 
104
    register Char **pp;
 
105
    register Char *p;
 
106
 
 
107
    if (noexec)
 
108
        return;
 
109
    /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
 
110
    for (pp = t->t_dcom; (p = *pp++) != NULL;) {
 
111
        for (; *p; p++) {
 
112
            if (cmap(*p, _DOL | QUOTES)) {      /* $, \, ', ", ` */
 
113
                Dfix2(t->t_dcom);       /* found one */
 
114
                blkfree(t->t_dcom);
 
115
                t->t_dcom = gargv;
 
116
                gargv = 0;
 
117
                return;
 
118
            }
 
119
        }
 
120
    }
 
121
}
 
122
 
 
123
/*
 
124
 * $ substitute one word, for i/o redirection
 
125
 */
 
126
Char   *
 
127
Dfix1(cp)
 
128
    register Char *cp;
 
129
{
 
130
    Char   *Dv[2];
 
131
 
 
132
    if (noexec)
 
133
        return (0);
 
134
    Dv[0] = cp;
 
135
    Dv[1] = NULL;
 
136
    Dfix2(Dv);
 
137
    if (gargc != 1) {
 
138
        setname(short2str(cp));
 
139
        stderror(ERR_NAME | ERR_AMBIG);
 
140
    }
 
141
    cp = Strsave(gargv[0]);
 
142
    blkfree(gargv), gargv = 0;
 
143
    return (cp);
 
144
}
 
145
 
 
146
/*
 
147
 * Subroutine to do actual fixing after state initialization.
 
148
 */
 
149
static void
 
150
Dfix2(v)
 
151
    Char  **v;
 
152
{
 
153
    ginit();                    /* Initialize glob's area pointers */
 
154
    Dvp = v;
 
155
    Dcp = STRNULL;              /* Setup input vector for Dreadc */
 
156
    unDgetC(0);
 
157
    unDredc(0);                 /* Clear out any old peeks (at error) */
 
158
    dolp = 0;
 
159
    dolcnt = 0;                 /* Clear out residual $ expands (...) */
 
160
    while (Dword())
 
161
        continue;
 
162
}
 
163
 
 
164
/*
 
165
 * Pack up more characters in this word
 
166
 */
 
167
static Char *
 
168
Dpack(wbuf, wp)
 
169
    Char   *wbuf, *wp;
 
170
{
 
171
    register int c;
 
172
    register int i = MAXWLEN - (int) (wp - wbuf);
 
173
 
 
174
    for (;;) {
 
175
        c = DgetC(DODOL);
 
176
        if (c == '\\') {
 
177
            c = DgetC(0);
 
178
            if (c == DEOF) {
 
179
                unDredc(c);
 
180
                *wp = 0;
 
181
                Gcat(STRNULL, wbuf);
 
182
                return (NULL);
 
183
            }
 
184
            if (c == '\n')
 
185
                c = ' ';
 
186
            else
 
187
                c |= QUOTE;
 
188
        }
 
189
        if (c == DEOF) {
 
190
            unDredc(c);
 
191
            *wp = 0;
 
192
            Gcat(STRNULL, wbuf);
 
193
            return (NULL);
 
194
        }
 
195
        if (cmap(c, _SP | _NL | _QF | _QB)) {   /* sp \t\n'"` */
 
196
            unDgetC(c);
 
197
            if (cmap(c, QUOTES))
 
198
                return (wp);
 
199
            *wp++ = 0;
 
200
            Gcat(STRNULL, wbuf);
 
201
            return (NULL);
 
202
        }
 
203
        if (--i <= 0)
 
204
            stderror(ERR_WTOOLONG);
 
205
        *wp++ = (Char) c;
 
206
    }
 
207
}
 
208
 
 
209
/*
 
210
 * Get a word.  This routine is analogous to the routine
 
211
 * word() in sh.lex.c for the main lexical input.  One difference
 
212
 * here is that we don't get a newline to terminate our expansion.
 
213
 * Rather, DgetC will return a DEOF when we hit the end-of-input.
 
214
 */
 
215
static int
 
216
Dword()
 
217
{
 
218
    register int c, c1;
 
219
    Char    wbuf[BUFSIZE];
 
220
    register Char *wp = wbuf;
 
221
    register int i = MAXWLEN;
 
222
    register bool dolflg;
 
223
    bool    sofar = 0, done = 0;
 
224
 
 
225
    while (!done) {
 
226
        done = 1;
 
227
        c = DgetC(DODOL);
 
228
        switch (c) {
 
229
 
 
230
        case DEOF:
 
231
            if (sofar == 0)
 
232
                return (0);
 
233
            /* finish this word and catch the code above the next time */
 
234
            unDredc(c);
 
235
            /*FALLTHROUGH*/
 
236
 
 
237
        case '\n':
 
238
            *wp = 0;
 
239
            Gcat(STRNULL, wbuf);
 
240
            return (1);
 
241
 
 
242
        case ' ':
 
243
        case '\t':
 
244
            done = 0;
 
245
            break;
 
246
 
 
247
        case '`':
 
248
            /* We preserve ` quotations which are done yet later */
 
249
            *wp++ = (Char) c, --i;
 
250
            /*FALLTHROUGH*/
 
251
        case '\'':
 
252
        case '"':
 
253
            /*
 
254
             * Note that DgetC never returns a QUOTES character from an
 
255
             * expansion, so only true input quotes will get us here or out.
 
256
             */
 
257
            c1 = c;
 
258
            dolflg = c1 == '"' ? DODOL : 0;
 
259
            for (;;) {
 
260
                c = DgetC(dolflg);
 
261
                if (c == c1)
 
262
                    break;
 
263
                if (c == '\n' || c == DEOF)
 
264
                    stderror(ERR_UNMATCHED, c1);
 
265
                if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE)) {
 
266
                    if ((wp[-1] & TRIM) == '\\')
 
267
                        --wp;
 
268
                    ++i;
 
269
                }
 
270
                if (--i <= 0)
 
271
                    stderror(ERR_WTOOLONG);
 
272
                switch (c1) {
 
273
 
 
274
                case '"':
 
275
                    /*
 
276
                     * Leave any `s alone for later. Other chars are all
 
277
                     * quoted, thus `...` can tell it was within "...".
 
278
                     */
 
279
                    *wp++ = c == '`' ? '`' : c | QUOTE;
 
280
                    break;
 
281
 
 
282
                case '\'':
 
283
                    /* Prevent all further interpretation */
 
284
                    *wp++ = c | QUOTE;
 
285
                    break;
 
286
 
 
287
                case '`':
 
288
                    /* Leave all text alone for later */
 
289
                    *wp++ = (Char) c;
 
290
                    break;
 
291
 
 
292
                default:
 
293
                    break;
 
294
                }
 
295
            }
 
296
            if (c1 == '`')
 
297
                *wp++ = '`' /* i--; eliminated */;
 
298
            sofar = 1;
 
299
            if ((wp = Dpack(wbuf, wp)) == NULL)
 
300
                return (1);
 
301
            else {
 
302
#ifdef masscomp
 
303
    /*
 
304
     * Avoid a nasty message from the RTU 4.1A & RTU 5.0 compiler concerning
 
305
     * the "overuse of registers". According to the compiler release notes,
 
306
     * incorrect code may be produced unless the offending expression is
 
307
     * rewritten. Therefore, we can't just ignore it, DAS DEC-90.
 
308
     */
 
309
                i = MAXWLEN;
 
310
                i -= (int) (wp - wbuf);
 
311
#else /* !masscomp */
 
312
                i = MAXWLEN - (int) (wp - wbuf);
 
313
#endif /* masscomp */
 
314
                done = 0;
 
315
            }
 
316
            break;
 
317
 
 
318
        case '\\':
 
319
            c = DgetC(0);       /* No $ subst! */
 
320
            if (c == '\n' || c == DEOF) {
 
321
                done = 0;
 
322
                break;
 
323
            }
 
324
            c |= QUOTE;
 
325
            break;
 
326
 
 
327
        default:
 
328
            break;
 
329
        }
 
330
        if (done) {
 
331
            unDgetC(c);
 
332
            sofar = 1;
 
333
            if ((wp = Dpack(wbuf, wp)) == NULL)
 
334
                return (1);
 
335
            else {
 
336
#ifdef masscomp
 
337
    /*
 
338
     * Avoid a nasty message from the RTU 4.1A & RTU 5.0 compiler concerning
 
339
     * the "overuse of registers". According to the compiler release notes,
 
340
     * incorrect code may be produced unless the offending expression is
 
341
     * rewritten. Therefore, we can't just ignore it, DAS DEC-90.
 
342
     */
 
343
                i = MAXWLEN;
 
344
                i -= (int) (wp - wbuf);
 
345
#else /* !masscomp */
 
346
                i = MAXWLEN - (int) (wp - wbuf);
 
347
#endif /* masscomp */
 
348
                done = 0;
 
349
            }
 
350
        }
 
351
    }
 
352
    /* Really NOTREACHED */
 
353
    return (0);
 
354
}
 
355
 
 
356
 
 
357
/*
 
358
 * Get a character, performing $ substitution unless flag is 0.
 
359
 * Any QUOTES character which is returned from a $ expansion is
 
360
 * QUOTEd so that it will not be recognized above.
 
361
 */
 
362
static int
 
363
DgetC(flag)
 
364
    register int flag;
 
365
{
 
366
    register int c;
 
367
 
 
368
top:
 
369
    if ((c = Dpeekc) != 0) {
 
370
        Dpeekc = 0;
 
371
        return (c);
 
372
    }
 
373
    if (lap) {
 
374
        c = *lap++ & (QUOTE | TRIM);
 
375
        if (c == 0) {
 
376
            lap = 0;
 
377
            goto top;
 
378
        }
 
379
quotspec:
 
380
        if (cmap(c, QUOTES))
 
381
            return (c | QUOTE);
 
382
        return (c);
 
383
    }
 
384
    if (dolp) {
 
385
        if ((c = *dolp++ & (QUOTE | TRIM)) != 0)
 
386
            goto quotspec;
 
387
        if (dolcnt > 0) {
 
388
            setDolp(*dolnxt++);
 
389
            --dolcnt;
 
390
            return (' ');
 
391
        }
 
392
        dolp = 0;
 
393
    }
 
394
    if (dolcnt > 0) {
 
395
        setDolp(*dolnxt++);
 
396
        --dolcnt;
 
397
        goto top;
 
398
    }
 
399
    c = Dredc();
 
400
    if (c == '$' && flag) {
 
401
        Dgetdol();
 
402
        goto top;
 
403
    }
 
404
    return (c);
 
405
}
 
406
 
 
407
static Char *nulvec[] = { NULL };
 
408
static struct varent nulargv = {nulvec, STRargv, VAR_READWRITE, 
 
409
                                { NULL, NULL, NULL }, 0 };
 
410
 
 
411
static void
 
412
dolerror(s)
 
413
    Char   *s;
 
414
{
 
415
    setname(short2str(s));
 
416
    stderror(ERR_NAME | ERR_RANGE);
 
417
}
 
418
 
 
419
/*
 
420
 * Handle the multitudinous $ expansion forms.
 
421
 * Ugh.
 
422
 */
 
423
static void
 
424
Dgetdol()
 
425
{
 
426
    register Char *np;
 
427
    register struct varent *vp = NULL;
 
428
    Char    name[4 * MAXVARLEN + 1];
 
429
    int     c, sc;
 
430
    int     subscr = 0, lwb = 1, upb = 0;
 
431
    bool    dimen = 0, bitset = 0, length = 0;
 
432
    char    tnp;
 
433
    Char    wbuf[BUFSIZE];
 
434
    static Char *dolbang = NULL;
 
435
 
 
436
#ifdef COMPAT
 
437
    dolmod = dolmcnt = dolwcnt = 0;
 
438
#else
 
439
    dolnmod = dolmcnt = dolwcnt = 0;
 
440
#endif /* COMPAT */
 
441
    c = sc = DgetC(0);
 
442
    if (c == '{')
 
443
        c = DgetC(0);           /* sc is { to take } later */
 
444
    if ((c & TRIM) == '#')
 
445
        dimen++, c = DgetC(0);  /* $# takes dimension */
 
446
    else if (c == '?')
 
447
        bitset++, c = DgetC(0); /* $? tests existence */
 
448
    else if (c == '%')
 
449
        length++, c = DgetC(0); /* $% returns length in chars */
 
450
    switch (c) {
 
451
 
 
452
    case '!':
 
453
        if (dimen || bitset || length)
 
454
            stderror(ERR_SYNTAX);
 
455
        if (backpid != 0) {
 
456
            if (dolbang) 
 
457
                xfree((ptr_t) dolbang);
 
458
            setDolp(dolbang = putn(backpid));
 
459
        }
 
460
        goto eatbrac;
 
461
 
 
462
    case '$':
 
463
        if (dimen || bitset || length)
 
464
            stderror(ERR_SYNTAX);
 
465
        setDolp(doldol);
 
466
        goto eatbrac;
 
467
 
 
468
#ifdef COHERENT
 
469
    /* Coherent compiler doesn't allow case-labels that are not 
 
470
       constant-expressions */
 
471
#ifdef SHORT_STRINGS
 
472
    case 0100074:
 
473
#else /* !SHORT_STRINGS */
 
474
    case 0274:
 
475
#endif
 
476
#else /* !COHERENT */
 
477
    case '<'|QUOTE:
 
478
#endif
 
479
        if (bitset)
 
480
            stderror(ERR_NOTALLOWED, "$?<");
 
481
        if (dimen)
 
482
            stderror(ERR_NOTALLOWED, "$#<");
 
483
        if (length)
 
484
            stderror(ERR_NOTALLOWED, "$%<");
 
485
        {
 
486
#ifdef BSDSIGS
 
487
            sigmask_t omask = sigsetmask(sigblock(0) & ~sigmask(SIGINT));
 
488
#else /* !BSDSIGS */
 
489
            (void) sigrelse(SIGINT);
 
490
#endif /* BSDSIGS */
 
491
            for (np = wbuf; force_read(OLDSTD, &tnp, 1) == 1; np++) {
 
492
                *np = (unsigned char) tnp;
 
493
                if (np >= &wbuf[BUFSIZE - 1])
 
494
                    stderror(ERR_LTOOLONG);
 
495
                if (tnp == '\n')
 
496
                    break;
 
497
            }
 
498
            *np = 0;
 
499
#ifdef BSDSIGS
 
500
            (void) sigsetmask(omask);
 
501
#else /* !BSDSIGS */
 
502
            (void) sighold(SIGINT);
 
503
#endif /* BSDSIGS */
 
504
        }
 
505
 
 
506
#ifdef COMPAT
 
507
        /*
 
508
         * KLUDGE: dolmod is set here because it will cause setDolp to call
 
509
         * domod and thus to copy wbuf. Otherwise setDolp would use it
 
510
         * directly. If we saved it ourselves, no one would know when to free
 
511
         * it. The actual function of the 'q' causes filename expansion not to
 
512
         * be done on the interpolated value.
 
513
         */
 
514
        /* 
 
515
         * If we do that, then other modifiers don't work.
 
516
         * in addition, let the user specify :q if wanted
 
517
         * [christos]
 
518
         */
 
519
/*old*/ dolmod = 'q';
 
520
/*new*/ dolmod[dolnmod++] = 'q';
 
521
        dolmcnt = 10000;
 
522
#endif /* COMPAT */
 
523
 
 
524
        fixDolMod();
 
525
        setDolp(wbuf);
 
526
        goto eatbrac;
 
527
 
 
528
    case '*':
 
529
        (void) Strcpy(name, STRargv);
 
530
        vp = adrof(STRargv);
 
531
        subscr = -1;            /* Prevent eating [...] */
 
532
        break;
 
533
 
 
534
    case DEOF:
 
535
    case '\n':
 
536
        np = dimen ? STRargv : (bitset ? STRstatus : NULL);
 
537
        if (np) {
 
538
            bitset = 0;
 
539
            (void) Strcpy(name, np);
 
540
            vp = adrof(np);
 
541
            subscr = -1;                /* Prevent eating [...] */
 
542
            unDredc(c);
 
543
            break;
 
544
        }
 
545
        else
 
546
            stderror(ERR_SYNTAX);
 
547
        /*NOTREACHED*/
 
548
 
 
549
    default:
 
550
        np = name;
 
551
        if (Isdigit(c)) {
 
552
            if (dimen)
 
553
                stderror(ERR_NOTALLOWED, "$#<num>");
 
554
            subscr = 0;
 
555
            do {
 
556
                subscr = subscr * 10 + c - '0';
 
557
                c = DgetC(0);
 
558
            } while (Isdigit(c));
 
559
            unDredc(c);
 
560
            if (subscr < 0) {
 
561
                dolerror(vp->v_name);
 
562
                return;
 
563
            }
 
564
            if (subscr == 0) {
 
565
                if (bitset) {
 
566
                    dolp = dolzero ? STR1 : STR0;
 
567
                    goto eatbrac;
 
568
                }
 
569
                if (ffile == 0)
 
570
                    stderror(ERR_DOLZERO);
 
571
                if (length) {
 
572
                    Char *cp;
 
573
                    length = Strlen(ffile);
 
574
                    cp = putn(length);
 
575
                    addla(cp);
 
576
                    xfree((ptr_t) cp);
 
577
                }
 
578
                else {
 
579
                    fixDolMod();
 
580
                    setDolp(ffile);
 
581
                }
 
582
                goto eatbrac;
 
583
            }
 
584
#if 0
 
585
            if (bitset)
 
586
                stderror(ERR_NOTALLOWED, "$?<num>");
 
587
            if (length)
 
588
                stderror(ERR_NOTALLOWED, "$%<num>");
 
589
#endif
 
590
            vp = adrof(STRargv);
 
591
            if (vp == 0) {
 
592
                vp = &nulargv;
 
593
                goto eatmod;
 
594
            }
 
595
            break;
 
596
        }
 
597
        if (!alnum(c)) {
 
598
            np = dimen ? STRargv : (bitset ? STRstatus : NULL);
 
599
            if (np) {
 
600
                bitset = 0;
 
601
                (void) Strcpy(name, np);
 
602
                vp = adrof(np);
 
603
                subscr = -1;            /* Prevent eating [...] */
 
604
                unDredc(c);
 
605
                break;
 
606
            }
 
607
            else
 
608
                stderror(ERR_VARALNUM);
 
609
        }
 
610
        for (;;) {
 
611
            *np++ = (Char) c;
 
612
            c = DgetC(0);
 
613
            if (!alnum(c))
 
614
                break;
 
615
            if (np >= &name[MAXVARLEN])
 
616
                stderror(ERR_VARTOOLONG);
 
617
        }
 
618
        *np++ = 0;
 
619
        unDredc(c);
 
620
        vp = adrof(name);
 
621
    }
 
622
    if (bitset) {
 
623
        dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
 
624
        goto eatbrac;
 
625
    }
 
626
    if (vp == 0) {
 
627
        np = str2short(getenv(short2str(name)));
 
628
        if (np) {
 
629
            fixDolMod();
 
630
            setDolp(np);
 
631
            goto eatbrac;
 
632
        }
 
633
        udvar(name);
 
634
        /* NOTREACHED */
 
635
    }
 
636
    c = DgetC(0);
 
637
    upb = blklen(vp->vec);
 
638
    if (dimen == 0 && subscr == 0 && c == '[') {
 
639
        np = name;
 
640
        for (;;) {
 
641
            c = DgetC(DODOL);   /* Allow $ expand within [ ] */
 
642
            if (c == ']')
 
643
                break;
 
644
            if (c == '\n' || c == DEOF)
 
645
                stderror(ERR_INCBR);
 
646
            if (np >= &name[sizeof(name) / sizeof(Char) - 2])
 
647
                stderror(ERR_VARTOOLONG);
 
648
            *np++ = (Char) c;
 
649
        }
 
650
        *np = 0, np = name;
 
651
        if (dolp || dolcnt)     /* $ exp must end before ] */
 
652
            stderror(ERR_EXPORD);
 
653
        if (!*np)
 
654
            stderror(ERR_SYNTAX);
 
655
        if (Isdigit(*np)) {
 
656
            int     i;
 
657
 
 
658
            for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
 
659
                continue;
 
660
            if ((i < 0 || i > upb) && !any("-*", *np)) {
 
661
                dolerror(vp->v_name);
 
662
                return;
 
663
            }
 
664
            lwb = i;
 
665
            if (!*np)
 
666
                upb = lwb, np = STRstar;
 
667
        }
 
668
        if (*np == '*')
 
669
            np++;
 
670
        else if (*np != '-')
 
671
            stderror(ERR_MISSING, '-');
 
672
        else {
 
673
            register int i = upb;
 
674
 
 
675
            np++;
 
676
            if (Isdigit(*np)) {
 
677
                i = 0;
 
678
                while (Isdigit(*np))
 
679
                    i = i * 10 + *np++ - '0';
 
680
                if (i < 0 || i > upb) {
 
681
                    dolerror(vp->v_name);
 
682
                    return;
 
683
                }
 
684
            }
 
685
            if (i < lwb)
 
686
                upb = lwb - 1;
 
687
            else
 
688
                upb = i;
 
689
        }
 
690
        if (lwb == 0) {
 
691
            if (upb != 0) {
 
692
                dolerror(vp->v_name);
 
693
                return;
 
694
            }
 
695
            upb = -1;
 
696
        }
 
697
        if (*np)
 
698
            stderror(ERR_SYNTAX);
 
699
    }
 
700
    else {
 
701
        if (subscr > 0) {
 
702
            if (subscr > upb)
 
703
                lwb = 1, upb = 0;
 
704
            else
 
705
                lwb = upb = subscr;
 
706
        }
 
707
        unDredc(c);
 
708
    }
 
709
    if (dimen) {
 
710
        Char   *cp = putn(upb - lwb + 1);
 
711
 
 
712
        /* this is a kludge. It prevents Dgetdol() from */
 
713
        /* pushing erroneous ${#<error> values into the labuf. */
 
714
        if (sc == '{') {
 
715
            c = Dredc();
 
716
            if (c != '}')
 
717
            {
 
718
                xfree((ptr_t) cp);
 
719
                stderror(ERR_MISSING, '}');
 
720
                return;
 
721
            }
 
722
            unDredc(c);
 
723
        }
 
724
        addla(cp);
 
725
        xfree((ptr_t) cp);
 
726
    }
 
727
    else if (length) {
 
728
        int i;
 
729
        Char   *cp;
 
730
        for (i = lwb - 1, length = 0; i < upb; i++)
 
731
            length += Strlen(vp->vec[i]);
 
732
#ifdef notdef
 
733
        /* We don't want that, since we can always compute it by adding $#xxx */
 
734
        length += i - 1;        /* Add the number of spaces in */
 
735
#endif
 
736
        cp = putn(length);
 
737
        addla(cp);
 
738
        xfree((ptr_t) cp);
 
739
    }
 
740
    else {
 
741
eatmod:
 
742
        fixDolMod();
 
743
        dolnxt = &vp->vec[lwb - 1];
 
744
        dolcnt = upb - lwb + 1;
 
745
    }
 
746
eatbrac:
 
747
    if (sc == '{') {
 
748
        c = Dredc();
 
749
        if (c != '}')
 
750
            stderror(ERR_MISSING, '}');
 
751
    }
 
752
}
 
753
 
 
754
static void
 
755
fixDolMod()
 
756
{
 
757
    register int c;
 
758
 
 
759
    c = DgetC(0);
 
760
    if (c == ':') {
 
761
#ifndef COMPAT
 
762
        do {
 
763
#endif /* COMPAT */
 
764
            c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
 
765
            if (c == 'g' || c == 'a') {
 
766
                if (c == 'g')
 
767
                    dolmcnt = 10000;
 
768
                else
 
769
                    dolwcnt = 10000;
 
770
                c = DgetC(0);
 
771
            }
 
772
            if ((c == 'g' && dolmcnt != 10000) || 
 
773
                (c == 'a' && dolwcnt != 10000)) {
 
774
                if (c == 'g')
 
775
                    dolmcnt = 10000;
 
776
                else
 
777
                    dolwcnt = 10000;
 
778
                c = DgetC(0); 
 
779
            }
 
780
 
 
781
            if (c == 's') {     /* [eichin:19910926.0755EST] */
 
782
                int delimcnt = 2;
 
783
                int delim = DgetC(0);
 
784
                dolmod[dolnmod++] = (Char) c;
 
785
                dolmod[dolnmod++] = (Char) delim;
 
786
                
 
787
                if (!delim || letter(delim)
 
788
                    || Isdigit(delim) || any(" \t\n", delim)) {
 
789
                    seterror(ERR_BADSUBST);
 
790
                    break;
 
791
                }       
 
792
                while ((c = DgetC(0)) != (-1)) {
 
793
                    dolmod[dolnmod++] = (Char) c;
 
794
                    if(c == delim) delimcnt--;
 
795
                    if(!delimcnt) break;
 
796
                }
 
797
                if(delimcnt) {
 
798
                    seterror(ERR_BADSUBST);
 
799
                    break;
 
800
                }
 
801
                continue;
 
802
            }
 
803
            if (!any("luhtrqxes", c))
 
804
                stderror(ERR_BADMOD, c);
 
805
#ifndef COMPAT
 
806
            dolmod[dolnmod++] = (Char) c;
 
807
#else
 
808
            dolmod = (Char) c;
 
809
#endif /* COMPAT */
 
810
            if (c == 'q')
 
811
                dolmcnt = 10000;
 
812
#ifndef COMPAT
 
813
        }
 
814
        while ((c = DgetC(0)) == ':');
 
815
        unDredc(c);
 
816
#endif /* COMPAT */
 
817
    }
 
818
    else
 
819
        unDredc(c);
 
820
}
 
821
 
 
822
static void
 
823
setDolp(cp)
 
824
    register Char *cp;
 
825
{
 
826
    register Char *dp;
 
827
#ifndef COMPAT
 
828
    int i;
 
829
#endif /* COMPAT */
 
830
 
 
831
#ifdef COMPAT
 
832
    if (dolmod == 0 || dolmcnt == 0) {
 
833
#else
 
834
    if (dolnmod == 0 || dolmcnt == 0) {
 
835
#endif /* COMPAT */
 
836
        dolp = cp;
 
837
        return;
 
838
    }
 
839
#ifdef COMPAT
 
840
    dp = domod(cp, dolmod);
 
841
#else
 
842
    dp = cp = Strsave(cp);
 
843
    for (i = 0; i < dolnmod; i++) {
 
844
        /* handle s// [eichin:19910926.0510EST] */
 
845
        if(dolmod[i] == 's') {
 
846
            int delim;
 
847
            Char *lhsub, *rhsub, *np;
 
848
            size_t lhlen = 0, rhlen = 0;
 
849
            int didmod = 0;
 
850
                
 
851
            delim = dolmod[++i];
 
852
            if (!delim || letter(delim)
 
853
                || Isdigit(delim) || any(" \t\n", delim)) {
 
854
                seterror(ERR_BADSUBST);
 
855
                break;
 
856
            }
 
857
            lhsub = &dolmod[++i];
 
858
            while(dolmod[i] != delim && dolmod[++i]) {
 
859
                lhlen++;
 
860
            }
 
861
            dolmod[i] = 0;
 
862
            rhsub = &dolmod[++i];
 
863
            while(dolmod[i] != delim && dolmod[++i]) {
 
864
                rhlen++;
 
865
            }
 
866
            dolmod[i] = 0;
 
867
 
 
868
            do {
 
869
                strip(lhsub);
 
870
                strip(cp);
 
871
                dp = Strstr(cp, lhsub);
 
872
                if (dp) {
 
873
                    np = (Char *) xmalloc((size_t)
 
874
                                          ((Strlen(cp) + 1 - lhlen + rhlen) *
 
875
                                          sizeof(Char)));
 
876
                    (void) Strncpy(np, cp, (size_t) (dp - cp));
 
877
                    (void) Strcpy(np + (dp - cp), rhsub);
 
878
                    (void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
 
879
 
 
880
                    xfree((ptr_t) cp);
 
881
                    dp = cp = np;
 
882
                    didmod = 1;
 
883
                } else {
 
884
                    /* should this do a seterror? */
 
885
                    break;
 
886
                }
 
887
            }
 
888
            while (dolwcnt == 10000);
 
889
            /*
 
890
             * restore dolmod for additional words
 
891
             */
 
892
            dolmod[i] = rhsub[-1] = (Char) delim;
 
893
            if (didmod)
 
894
                dolmcnt--;
 
895
#ifdef notdef
 
896
            else
 
897
                break;
 
898
#endif
 
899
        } else {
 
900
            int didmod = 0;
 
901
 
 
902
            do {
 
903
                if ((dp = domod(cp, dolmod[i])) != NULL) {
 
904
                    didmod = 1;
 
905
                    if (Strcmp(cp, dp) == 0) {
 
906
                        xfree((ptr_t) cp);
 
907
                        cp = dp;
 
908
                        break;
 
909
                    }
 
910
                    else {
 
911
                        xfree((ptr_t) cp);
 
912
                        cp = dp;
 
913
                    }
 
914
                }
 
915
                else
 
916
                    break;
 
917
            }
 
918
            while (dolwcnt == 10000);
 
919
            dp = cp;
 
920
            if (didmod)
 
921
                dolmcnt--;
 
922
#ifdef notdef
 
923
            else
 
924
                break;
 
925
#endif
 
926
        }
 
927
    }
 
928
#endif /* COMPAT */
 
929
 
 
930
    if (dp) {
 
931
#ifdef COMPAT
 
932
        dolmcnt--;
 
933
#endif /* COMPAT */
 
934
        addla(dp);
 
935
        xfree((ptr_t) dp);
 
936
    }
 
937
#ifndef COMPAT
 
938
    else
 
939
        addla(cp);
 
940
#endif /* COMPAT */
 
941
 
 
942
    dolp = STRNULL;
 
943
    if (seterr)
 
944
        stderror(ERR_OLD);
 
945
}
 
946
 
 
947
static void
 
948
unDredc(c)
 
949
    int     c;
 
950
{
 
951
 
 
952
    Dpeekrd = c;
 
953
}
 
954
 
 
955
static int
 
956
Dredc()
 
957
{
 
958
    register int c;
 
959
 
 
960
    if ((c = Dpeekrd) != 0) {
 
961
        Dpeekrd = 0;
 
962
        return (c);
 
963
    }
 
964
    if (Dcp && (c = *Dcp++))
 
965
        return (c & (QUOTE | TRIM));
 
966
    if (*Dvp == 0) {
 
967
        Dcp = 0;
 
968
        return (DEOF);
 
969
    }
 
970
    Dcp = *Dvp++;
 
971
    return (' ');
 
972
}
 
973
 
 
974
static void
 
975
Dtestq(c)
 
976
    register int c;
 
977
{
 
978
 
 
979
    if (cmap(c, QUOTES))
 
980
        gflag = 1;
 
981
}
 
982
 
 
983
/*
 
984
 * Form a shell temporary file (in unit 0) from the words
 
985
 * of the shell input up to EOF or a line the same as "term".
 
986
 * Unit 0 should have been closed before this call.
 
987
 */
 
988
void
 
989
heredoc(term)
 
990
    Char   *term;
 
991
{
 
992
    register int c;
 
993
    Char   *Dv[2];
 
994
    Char    obuf[BUFSIZE], lbuf[BUFSIZE], mbuf[BUFSIZE];
 
995
    int     ocnt, lcnt, mcnt;
 
996
    register Char *lbp, *obp, *mbp;
 
997
    Char  **vp;
 
998
    bool    quoted;
 
999
    char   *tmp;
 
1000
 
 
1001
    tmp = short2str(shtemp);
 
1002
#ifndef O_CREAT
 
1003
# define O_CREAT 0
 
1004
    if (creat(tmp, 0600) < 0)
 
1005
        stderror(ERR_SYSTEM, tmp, strerror(errno));
 
1006
#endif
 
1007
    (void) close(0);
 
1008
#ifndef O_TEMPORARY
 
1009
# define O_TEMPORARY 0
 
1010
#endif
 
1011
    if (open(tmp, O_RDWR|O_CREAT|O_TEMPORARY, 0600) < 0) {
 
1012
        int     oerrno = errno;
 
1013
 
 
1014
        (void) unlink(tmp);
 
1015
        errno = oerrno;
 
1016
        stderror(ERR_SYSTEM, tmp, strerror(errno));
 
1017
    }
 
1018
    (void) unlink(tmp);         /* 0 0 inode! */
 
1019
    Dv[0] = term;
 
1020
    Dv[1] = NULL;
 
1021
    gflag = 0;
 
1022
    trim(Dv);
 
1023
    rscan(Dv, Dtestq);
 
1024
    quoted = gflag;
 
1025
    ocnt = BUFSIZE;
 
1026
    obp = obuf;
 
1027
    inheredoc = 1;
 
1028
#ifdef WINNT
 
1029
    __dup_stdin = 1;
 
1030
#endif /* WINNT */
 
1031
    for (;;) {
 
1032
        /*
 
1033
         * Read up a line
 
1034
         */
 
1035
        lbp = lbuf;
 
1036
        lcnt = BUFSIZE - 4;
 
1037
        for (;;) {
 
1038
            c = readc(1);       /* 1 -> Want EOF returns */
 
1039
            if (c < 0 || c == '\n')
 
1040
                break;
 
1041
            if ((c &= TRIM) != 0) {
 
1042
                *lbp++ = (Char) c;
 
1043
                if (--lcnt < 0) {
 
1044
                    setname("<<");
 
1045
                    stderror(ERR_NAME | ERR_OVERFLOW);
 
1046
                }
 
1047
            }
 
1048
        }
 
1049
        *lbp = 0;
 
1050
 
 
1051
        /*
 
1052
         * Check for EOF or compare to terminator -- before expansion
 
1053
         */
 
1054
        if (c < 0 || eq(lbuf, term)) {
 
1055
            (void) write(0, short2str(obuf), (size_t) (BUFSIZE - ocnt));
 
1056
            (void) lseek(0, (off_t) 0, L_SET);
 
1057
            inheredoc = 0;
 
1058
            return;
 
1059
        }
 
1060
 
 
1061
        /*
 
1062
         * If term was quoted or -n just pass it on
 
1063
         */
 
1064
        if (quoted || noexec) {
 
1065
            *lbp++ = '\n';
 
1066
            *lbp = 0;
 
1067
            for (lbp = lbuf; (c = *lbp++) != 0;) {
 
1068
                *obp++ = (Char) c;
 
1069
                if (--ocnt == 0) {
 
1070
                    (void) write(0, short2str(obuf), BUFSIZE);
 
1071
                    obp = obuf;
 
1072
                    ocnt = BUFSIZE;
 
1073
                }
 
1074
            }
 
1075
            continue;
 
1076
        }
 
1077
 
 
1078
        /*
 
1079
         * Term wasn't quoted so variable and then command expand the input
 
1080
         * line
 
1081
         */
 
1082
        Dcp = lbuf;
 
1083
        Dvp = Dv + 1;
 
1084
        mbp = mbuf;
 
1085
        mcnt = BUFSIZE - 4;
 
1086
        for (;;) {
 
1087
            c = DgetC(DODOL);
 
1088
            if (c == DEOF)
 
1089
                break;
 
1090
            if ((c &= TRIM) == 0)
 
1091
                continue;
 
1092
            /* \ quotes \ $ ` here */
 
1093
            if (c == '\\') {
 
1094
                c = DgetC(0);
 
1095
                if (!any("$\\`", c))
 
1096
                    unDgetC(c | QUOTE), c = '\\';
 
1097
                else
 
1098
                    c |= QUOTE;
 
1099
            }
 
1100
            *mbp++ = (Char) c;
 
1101
            if (--mcnt == 0) {
 
1102
                setname("<<");
 
1103
                stderror(ERR_NAME | ERR_OVERFLOW);
 
1104
            }
 
1105
        }
 
1106
        *mbp++ = 0;
 
1107
 
 
1108
        /*
 
1109
         * If any ` in line do command substitution
 
1110
         */
 
1111
        mbp = mbuf;
 
1112
        if (Strchr(mbp, '`') != NULL) {
 
1113
            /*
 
1114
             * 1 arg to dobackp causes substitution to be literal. Words are
 
1115
             * broken only at newlines so that all blanks and tabs are
 
1116
             * preserved.  Blank lines (null words) are not discarded.
 
1117
             */
 
1118
            vp = dobackp(mbuf, 1);
 
1119
        }
 
1120
        else
 
1121
            /* Setup trivial vector similar to return of dobackp */
 
1122
            Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
 
1123
 
 
1124
        /*
 
1125
         * Resurrect the words from the command substitution each separated by
 
1126
         * a newline.  Note that the last newline of a command substitution
 
1127
         * will have been discarded, but we put a newline after the last word
 
1128
         * because this represents the newline after the last input line!
 
1129
         */
 
1130
        for (; *vp; vp++) {
 
1131
            for (mbp = *vp; *mbp; mbp++) {
 
1132
                *obp++ = *mbp & TRIM;
 
1133
                if (--ocnt == 0) {
 
1134
                    (void) write(0, short2str(obuf), BUFSIZE);
 
1135
                    obp = obuf;
 
1136
                    ocnt = BUFSIZE;
 
1137
                }
 
1138
            }
 
1139
            *obp++ = '\n';
 
1140
            if (--ocnt == 0) {
 
1141
                (void) write(0, short2str(obuf), BUFSIZE);
 
1142
                obp = obuf;
 
1143
                ocnt = BUFSIZE;
 
1144
            }
 
1145
        }
 
1146
        if (pargv)
 
1147
            blkfree(pargv), pargv = 0;
 
1148
    }
 
1149
}