source: trunk/third/tcsh/sh.dol.c @ 15292

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