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

Revision 12039, 24.2 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12038, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.dol.c,v 1.1.1.2 1998-10-03 21:09:58 danw 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.1.1.2 1998-10-03 21:09:58 danw 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    register 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
1002    tmp = short2str(shtemp);
1003#ifndef O_CREAT
1004# define O_CREAT 0
1005    if (creat(tmp, 0600) < 0)
1006        stderror(ERR_SYSTEM, tmp, strerror(errno));
1007#endif
1008    (void) close(0);
1009#ifndef O_TEMPORARY
1010# define O_TEMPORARY 0
1011#endif
1012    if (open(tmp, O_RDWR|O_CREAT|O_TEMPORARY) < 0) {
1013        int     oerrno = errno;
1014
1015        (void) unlink(tmp);
1016        errno = oerrno;
1017        stderror(ERR_SYSTEM, tmp, strerror(errno));
1018    }
1019    (void) unlink(tmp);         /* 0 0 inode! */
1020    Dv[0] = term;
1021    Dv[1] = NULL;
1022    gflag = 0;
1023    trim(Dv);
1024    rscan(Dv, Dtestq);
1025    quoted = gflag;
1026    ocnt = BUFSIZE;
1027    obp = obuf;
1028    inheredoc = 1;
1029#ifdef WINNT
1030    __dup_stdin = 1;
1031#endif /* WINNT */
1032    for (;;) {
1033        /*
1034         * Read up a line
1035         */
1036        lbp = lbuf;
1037        lcnt = BUFSIZE - 4;
1038        for (;;) {
1039            c = readc(1);       /* 1 -> Want EOF returns */
1040            if (c < 0 || c == '\n')
1041                break;
1042            if ((c &= TRIM) != 0) {
1043                *lbp++ = (Char) c;
1044                if (--lcnt < 0) {
1045                    setname("<<");
1046                    stderror(ERR_NAME | ERR_OVERFLOW);
1047                }
1048            }
1049        }
1050        *lbp = 0;
1051
1052        /*
1053         * Check for EOF or compare to terminator -- before expansion
1054         */
1055        if (c < 0 || eq(lbuf, term)) {
1056            (void) write(0, short2str(obuf), (size_t) (BUFSIZE - ocnt));
1057            (void) lseek(0, 0l, L_SET);
1058            inheredoc = 0;
1059            return;
1060        }
1061
1062        /*
1063         * If term was quoted or -n just pass it on
1064         */
1065        if (quoted || noexec) {
1066            *lbp++ = '\n';
1067            *lbp = 0;
1068            for (lbp = lbuf; (c = *lbp++) != 0;) {
1069                *obp++ = (Char) c;
1070                if (--ocnt == 0) {
1071                    (void) write(0, short2str(obuf), BUFSIZE);
1072                    obp = obuf;
1073                    ocnt = BUFSIZE;
1074                }
1075            }
1076            continue;
1077        }
1078
1079        /*
1080         * Term wasn't quoted so variable and then command expand the input
1081         * line
1082         */
1083        Dcp = lbuf;
1084        Dvp = Dv + 1;
1085        mbp = mbuf;
1086        mcnt = BUFSIZE - 4;
1087        for (;;) {
1088            c = DgetC(DODOL);
1089            if (c == DEOF)
1090                break;
1091            if ((c &= TRIM) == 0)
1092                continue;
1093            /* \ quotes \ $ ` here */
1094            if (c == '\\') {
1095                c = DgetC(0);
1096                if (!any("$\\`", c))
1097                    unDgetC(c | QUOTE), c = '\\';
1098                else
1099                    c |= QUOTE;
1100            }
1101            *mbp++ = (Char) c;
1102            if (--mcnt == 0) {
1103                setname("<<");
1104                stderror(ERR_NAME | ERR_OVERFLOW);
1105            }
1106        }
1107        *mbp++ = 0;
1108
1109        /*
1110         * If any ` in line do command substitution
1111         */
1112        mbp = mbuf;
1113        if (Strchr(mbp, '`') != NULL) {
1114            /*
1115             * 1 arg to dobackp causes substitution to be literal. Words are
1116             * broken only at newlines so that all blanks and tabs are
1117             * preserved.  Blank lines (null words) are not discarded.
1118             */
1119            vp = dobackp(mbuf, 1);
1120        }
1121        else
1122            /* Setup trivial vector similar to return of dobackp */
1123            Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
1124
1125        /*
1126         * Resurrect the words from the command substitution each separated by
1127         * a newline.  Note that the last newline of a command substitution
1128         * will have been discarded, but we put a newline after the last word
1129         * because this represents the newline after the last input line!
1130         */
1131        for (; *vp; vp++) {
1132            for (mbp = *vp; *mbp; mbp++) {
1133                *obp++ = *mbp & TRIM;
1134                if (--ocnt == 0) {
1135                    (void) write(0, short2str(obuf), BUFSIZE);
1136                    obp = obuf;
1137                    ocnt = BUFSIZE;
1138                }
1139            }
1140            *obp++ = '\n';
1141            if (--ocnt == 0) {
1142                (void) write(0, short2str(obuf), BUFSIZE);
1143                obp = obuf;
1144                ocnt = BUFSIZE;
1145            }
1146        }
1147        if (pargv)
1148            blkfree(pargv), pargv = 0;
1149    }
1150}
Note: See TracBrowser for help on using the repository browser.