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

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