home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / sh.dol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  22.7 KB  |  1,082 lines

  1. /* $Header: /u/christos/src/tcsh-6.03/RCS/sh.dol.c,v 3.18 1992/10/14 20:19:19 christos 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.  
  39. RCSID("$Id: sh.dol.c,v 3.18 1992/10/14 20:19:19 christos 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.  
  54. static int Dpeekc, Dpeekrd;    /* Peeks for DgetC and Dreadc */
  55. static Char *Dcp, **Dvp;    /* Input vector for Dreadc */
  56.  
  57. #define    DEOF    -1
  58.  
  59. #define    unDgetC(c)    Dpeekc = c
  60.  
  61. #define QUOTES        (_Q|_Q1|_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 */
  73. static Char *dolp;        /* Remaining chars from this word */
  74. static Char **dolnxt;        /* Further words */
  75. static int dolcnt;        /* Count of further words */
  76. #ifdef COMPAT
  77. static Char dolmod;        /* : modifier character */
  78. #else
  79. static Char dolmod[MAXMOD];    /* : modifier character */
  80. static int dolnmod;        /* Number of modifiers */
  81. #endif /* COMPAT */
  82. static int dolmcnt;        /* :gx -> 10000, else 1 */
  83. static int dolwcnt;        /* :ax -> 10000, else 1 */
  84.  
  85. static    void     Dfix2        __P((Char **));
  86. static    Char     *Dpack        __P((Char *, Char *));
  87. static    int     Dword        __P((void));
  88. static    void     dolerror    __P((Char *));
  89. static    int     DgetC        __P((int));
  90. static    void     Dgetdol    __P((void));
  91. static    void     fixDolMod    __P((void));
  92. static    void     setDolp    __P((Char *));
  93. static    void     unDredc    __P((int));
  94. static    int     Dredc        __P((void));
  95. static    void     Dtestq        __P((int));
  96.  
  97. /*
  98.  * Fix up the $ expansions and quotations in the
  99.  * argument list to command t.
  100.  */
  101. void
  102. Dfix(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.  */
  127. Char   *
  128. Dfix1(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.  */
  150. static void
  151. Dfix2(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.  */
  168. static Char *
  169. Dpack(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 | _Q | _Q1)) {    /* 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.  */
  216. static int
  217. Dword()
  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.             --wp, ++i;
  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 -= (wp - wbuf);
  309. #else /* !masscomp */
  310.         i = MAXWLEN - (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 -= (wp - wbuf);
  343. #else /* !masscomp */
  344.         i = MAXWLEN - (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.  */
  360. static int
  361. DgetC(flag)
  362.     register int flag;
  363. {
  364.     register int c;
  365.  
  366. top:
  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.     }
  377. quotspec:
  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.  
  405. static Char *nulvec[] = {0};
  406. static struct varent nulargv = {nulvec, STRargv, 0};
  407.  
  408. static void
  409. dolerror(s)
  410.     Char   *s;
  411. {
  412.     setname(short2str(s));
  413.     stderror(ERR_NAME | ERR_RANGE);
  414. }
  415.  
  416. /*
  417.  * Handle the multitudinous $ expansion forms.
  418.  * Ugh.
  419.  */
  420. static void
  421. Dgetdol()
  422. {
  423.     register Char *np;
  424.     register struct varent *vp = NULL;
  425.     Char    name[4 * MAXVARLEN + 1];
  426.     int     c, sc;
  427.     int     subscr = 0, lwb = 1, upb = 0;
  428.     bool    dimen = 0, bitset = 0, length = 0;
  429.     char    tnp;
  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 SHORT_STRINGS
  469.     case 0100074:
  470. #else /* !SHORT_STRINGS */
  471.     case 0274:
  472. #endif
  473. #else /* !COHERENT */
  474.     case '<'|QUOTE:
  475. #endif
  476.     if (bitset)
  477.         stderror(ERR_NOTALLOWED, "$?<");
  478.     if (dimen)
  479.         stderror(ERR_NOTALLOWED, "$#<");
  480.     if (length)
  481.         stderror(ERR_NOTALLOWED, "$%<");
  482.     for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
  483.         *np = (unsigned char) tnp;
  484.         if (np >= &wbuf[BUFSIZE - 1])
  485.         stderror(ERR_LTOOLONG);
  486.         if (tnp == '\n')
  487.         break;
  488.     }
  489.     *np = 0;
  490.     /*
  491.      * KLUDGE: dolmod is set here because it will cause setDolp to call
  492.      * domod and thus to copy wbuf. Otherwise setDolp would use it
  493.      * directly. If we saved it ourselves, no one would know when to free
  494.      * it. The actual function of the 'q' causes filename expansion not to
  495.      * be done on the interpolated value.
  496.      */
  497. #ifdef COMPAT
  498.     dolmod = 'q';
  499. #else
  500.     dolmod[dolnmod++] = 'q';
  501. #endif /* COMPAT */
  502.     dolmcnt = 10000;
  503.     setDolp(wbuf);
  504.     goto eatbrac;
  505.  
  506.     case '*':
  507.     (void) Strcpy(name, STRargv);
  508.     vp = adrof(STRargv);
  509.     subscr = -1;        /* Prevent eating [...] */
  510.     break;
  511.  
  512.     case DEOF:
  513.     case '\n':
  514.     np = dimen ? STRargv : (bitset ? STRstatus : NULL);
  515.     if (np) {
  516.         bitset = 0;
  517.         (void) Strcpy(name, np);
  518.         vp = adrof(np);
  519.         subscr = -1;        /* Prevent eating [...] */
  520.         unDredc(c);
  521.         break;
  522.     }
  523.     else
  524.         stderror(ERR_SYNTAX);
  525.     /*NOTREACHED*/
  526.  
  527.     default:
  528.     np = name;
  529.     if (Isdigit(c)) {
  530.         if (dimen)
  531.         stderror(ERR_NOTALLOWED, "$#<num>");
  532.         subscr = 0;
  533.         do {
  534.         subscr = subscr * 10 + c - '0';
  535.         c = DgetC(0);
  536.         } while (Isdigit(c));
  537.         unDredc(c);
  538.         if (subscr < 0) {
  539.         dolerror(vp->v_name);
  540.         return;
  541.         }
  542.         if (subscr == 0) {
  543.         if (bitset) {
  544.             dolp = ffile ? STR1 : STR0;
  545.             goto eatbrac;
  546.         }
  547.         if (ffile == 0)
  548.             stderror(ERR_DOLZERO);
  549.         fixDolMod();
  550.         setDolp(ffile);
  551.         goto eatbrac;
  552.         }
  553.         if (bitset)
  554.         stderror(ERR_NOTALLOWED, "$?<num>");
  555.         if (length)
  556.         stderror(ERR_NOTALLOWED, "$%<num>");
  557.         vp = adrof(STRargv);
  558.         if (vp == 0) {
  559.         vp = &nulargv;
  560.         goto eatmod;
  561.         }
  562.         break;
  563.     }
  564.     if (!alnum(c)) {
  565.         np = dimen ? STRargv : (bitset ? STRstatus : NULL);
  566.         if (np) {
  567.         bitset = 0;
  568.         (void) Strcpy(name, np);
  569.         vp = adrof(np);
  570.         subscr = -1;        /* Prevent eating [...] */
  571.         unDredc(c);
  572.         break;
  573.         }
  574.         else
  575.         stderror(ERR_VARALNUM);
  576.     }
  577.     for (;;) {
  578.         *np++ = c;
  579.         c = DgetC(0);
  580.         if (!alnum(c))
  581.         break;
  582.         if (np >= &name[MAXVARLEN])
  583.         stderror(ERR_VARTOOLONG);
  584.     }
  585.     *np++ = 0;
  586.     unDredc(c);
  587.     vp = adrof(name);
  588.     }
  589.     if (bitset) {
  590.     dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
  591.     goto eatbrac;
  592.     }
  593.     if (vp == 0) {
  594.     np = str2short(getenv(short2str(name)));
  595.     if (np) {
  596.         fixDolMod();
  597.         setDolp(np);
  598.         goto eatbrac;
  599.     }
  600.     udvar(name);
  601.     /* NOTREACHED */
  602.     }
  603.     c = DgetC(0);
  604.     upb = blklen(vp->vec);
  605.     if (dimen == 0 && subscr == 0 && c == '[') {
  606.     np = name;
  607.     for (;;) {
  608.         c = DgetC(DODOL);    /* Allow $ expand within [ ] */
  609.         if (c == ']')
  610.         break;
  611.         if (c == '\n' || c == DEOF)
  612.         stderror(ERR_INCBR);
  613.         if (np >= &name[sizeof(name) / sizeof(Char) - 2])
  614.         stderror(ERR_VARTOOLONG);
  615.         *np++ = c;
  616.     }
  617.     *np = 0, np = name;
  618.     if (dolp || dolcnt)    /* $ exp must end before ] */
  619.         stderror(ERR_EXPORD);
  620.     if (!*np)
  621.         stderror(ERR_SYNTAX);
  622.     if (Isdigit(*np)) {
  623.         int     i;
  624.  
  625.         for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
  626.         continue;
  627.         if ((i < 0 || i > upb) && !any("-*", *np)) {
  628.         dolerror(vp->v_name);
  629.         return;
  630.         }
  631.         lwb = i;
  632.         if (!*np)
  633.         upb = lwb, np = STRstar;
  634.     }
  635.     if (*np == '*')
  636.         np++;
  637.     else if (*np != '-')
  638.         stderror(ERR_MISSING, '-');
  639.     else {
  640.         register int i = upb;
  641.  
  642.         np++;
  643.         if (Isdigit(*np)) {
  644.         i = 0;
  645.         while (Isdigit(*np))
  646.             i = i * 10 + *np++ - '0';
  647.         if (i < 0 || i > upb) {
  648.             dolerror(vp->v_name);
  649.             return;
  650.         }
  651.         }
  652.         if (i < lwb)
  653.         upb = lwb - 1;
  654.         else
  655.         upb = i;
  656.     }
  657.     if (lwb == 0) {
  658.         if (upb != 0) {
  659.         dolerror(vp->v_name);
  660.         return;
  661.         }
  662.         upb = -1;
  663.     }
  664.     if (*np)
  665.         stderror(ERR_SYNTAX);
  666.     }
  667.     else {
  668.     if (subscr > 0)
  669.         if (subscr > upb)
  670.         lwb = 1, upb = 0;
  671.         else
  672.         lwb = upb = subscr;
  673.     unDredc(c);
  674.     }
  675.     if (dimen) {
  676.     Char   *cp = putn(upb - lwb + 1);
  677.  
  678.     addla(cp);
  679.     xfree((ptr_t) cp);
  680.     }
  681.     else if (length) {
  682.     int i;
  683.     Char   *cp;
  684.     for (i = lwb - 1, length = 0; i < upb; i++)
  685.         length += Strlen(vp->vec[i]);
  686.     cp = putn(length);
  687.     addla(cp);
  688.     xfree((ptr_t) cp);
  689.     }
  690.     else {
  691. eatmod:
  692.     fixDolMod();
  693.     dolnxt = &vp->vec[lwb - 1];
  694.     dolcnt = upb - lwb + 1;
  695.     }
  696. eatbrac:
  697.     if (sc == '{') {
  698.     c = Dredc();
  699.     if (c != '}')
  700.         stderror(ERR_MISSING, '}');
  701.     }
  702. }
  703.  
  704. static void
  705. fixDolMod()
  706. {
  707.     register int c;
  708.  
  709.     c = DgetC(0);
  710.     if (c == ':') {
  711. #ifndef COMPAT
  712.     do {
  713. #endif /* COMPAT */
  714.         c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
  715.         if (c == 'g' || c == 'a') {
  716.         if (c == 'g')
  717.             dolmcnt = 10000;
  718.         else
  719.             dolwcnt = 10000;
  720.         c = DgetC(0);
  721.         }
  722.         if ((c == 'g' && dolmcnt != 10000) || 
  723.         (c == 'a' && dolwcnt != 10000)) {
  724.         if (c == 'g')
  725.             dolmcnt = 10000;
  726.         else
  727.             dolwcnt = 10000;
  728.         c = DgetC(0); 
  729.         }
  730.  
  731.         if (c == 's') {    /* [eichin:19910926.0755EST] */
  732.         int delimcnt = 2;
  733.         int delim = DgetC(0);
  734.         dolmod[dolnmod++] = (Char) c;
  735.         dolmod[dolnmod++] = delim;
  736.         
  737.         if (!delim || letter(delim)
  738.             || Isdigit(delim) || any(" \t\n", delim)) {
  739.             seterror(ERR_BADSUBST);
  740.             break;
  741.         }    
  742.         while ((c = DgetC(0)) != (-1)) {
  743.             dolmod[dolnmod++] = (Char) c;
  744.             if(c == delim) delimcnt--;
  745.             if(!delimcnt) break;
  746.         }
  747.         if(delimcnt) {
  748.             seterror(ERR_BADSUBST);
  749.             break;
  750.         }
  751.         continue;
  752.         }
  753.         if (!any("luhtrqxes", c))
  754.         stderror(ERR_BADMOD, c);
  755. #ifndef COMPAT
  756.         dolmod[dolnmod++] = (Char) c;
  757. #else
  758.         dolmod = (Char) c;
  759. #endif /* COMPAT */
  760.         if (c == 'q')
  761.         dolmcnt = 10000;
  762. #ifndef COMPAT
  763.     }
  764.     while ((c = DgetC(0)) == ':');
  765.     unDredc(c);
  766. #endif /* COMPAT */
  767.     }
  768.     else
  769.     unDredc(c);
  770. }
  771.  
  772. static void
  773. setDolp(cp)
  774.     register Char *cp;
  775. {
  776.     register Char *dp;
  777. #ifndef COMPAT
  778.     int i;
  779. #endif /* COMPAT */
  780.  
  781. #ifdef COMPAT
  782.     if (dolmod == 0 || dolmcnt == 0) {
  783. #else
  784.     if (dolnmod == 0 || dolmcnt == 0) {
  785. #endif /* COMPAT */
  786.     dolp = cp;
  787.     return;
  788.     }
  789. #ifdef COMPAT
  790.     dp = domod(cp, dolmod);
  791. #else
  792.     dp = cp = Strsave(cp);
  793.     for (i = 0; i < dolnmod; i++) {
  794.     /* handle s// [eichin:19910926.0510EST] */
  795.     if(dolmod[i] == 's') {
  796.         int delim;
  797.         Char *lhsub, *rhsub, *np;
  798.         size_t lhlen = 0, rhlen = 0;
  799.         int didmod = 0;
  800.         
  801.         delim = dolmod[++i];
  802.         if (!delim || letter(delim)
  803.         || Isdigit(delim) || any(" \t\n", delim)) {
  804.         seterror(ERR_BADSUBST);
  805.         break;
  806.         }
  807.         lhsub = &dolmod[++i];
  808.         while(dolmod[i] != delim && dolmod[++i]) {
  809.         lhlen++;
  810.         }
  811.         dolmod[i] = 0;
  812.         rhsub = &dolmod[++i];
  813.         while(dolmod[i] != delim && dolmod[++i]) {
  814.         rhlen++;
  815.         }
  816.         dolmod[i] = 0;
  817.  
  818.         do {
  819.         dp = Strstr(cp, lhsub);
  820.         if (dp) {
  821.             np = (Char *) xmalloc((size_t)
  822.                       ((Strlen(cp) + 1 - lhlen + rhlen) *
  823.                       sizeof(Char)));
  824.             (void) Strncpy(np, cp, dp - cp);
  825.             (void) Strcpy(np + (dp - cp), rhsub);
  826.             (void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
  827.  
  828.             xfree((ptr_t) cp);
  829.             dp = cp = np;
  830.             didmod = 1;
  831.         } else {
  832.             /* should this do a seterror? */
  833.             break;
  834.         }
  835.         }
  836.         while (dolwcnt == 10000);
  837.         /*
  838.          * restore dolmod for additional words
  839.          */
  840.         dolmod[i] = rhsub[-1] = delim;
  841.         if (didmod)
  842.         dolmcnt--;
  843.         else
  844.         break;
  845.         } else {
  846.         int didmod = 0;
  847.  
  848.         do {
  849.         if ((dp = domod(cp, dolmod[i])) != NULL) {
  850.             didmod = 1;
  851.             if (Strcmp(cp, dp) == 0) {
  852.             xfree((ptr_t) cp);
  853.             cp = dp;
  854.             break;
  855.             }
  856.             else {
  857.             xfree((ptr_t) cp);
  858.             cp = dp;
  859.             }
  860.         }
  861.         else
  862.             break;
  863.         }
  864.         while (dolwcnt == 10000);
  865.         dp = cp;
  866.         if (didmod)
  867.         dolmcnt--;
  868.         else
  869.         break;
  870.     }
  871.     }
  872. #endif /* COMPAT */
  873.  
  874.     if (dp) {
  875. #ifdef COMPAT
  876.     dolmcnt--;
  877. #endif /* COMPAT */
  878.     addla(dp);
  879.     xfree((ptr_t) dp);
  880.     }
  881. #ifndef COMPAT
  882.     else
  883.     addla(cp);
  884. #endif /* COMPAT */
  885.  
  886.     dolp = STRNULL;
  887.     if (seterr)
  888.     stderror(ERR_OLD);
  889. }
  890.  
  891. static void
  892. unDredc(c)
  893.     int     c;
  894. {
  895.  
  896.     Dpeekrd = c;
  897. }
  898.  
  899. static int
  900. Dredc()
  901. {
  902.     register int c;
  903.  
  904.     if ((c = Dpeekrd) != 0) {
  905.     Dpeekrd = 0;
  906.     return (c);
  907.     }
  908.     if (Dcp && (c = *Dcp++))
  909.     return (c & (QUOTE | TRIM));
  910.     if (*Dvp == 0) {
  911.     Dcp = 0;
  912.     return (DEOF);
  913.     }
  914.     Dcp = *Dvp++;
  915.     return (' ');
  916. }
  917.  
  918. static void
  919. Dtestq(c)
  920.     register int c;
  921. {
  922.  
  923.     if (cmap(c, QUOTES))
  924.     gflag = 1;
  925. }
  926.  
  927. /*
  928.  * Form a shell temporary file (in unit 0) from the words
  929.  * of the shell input up to EOF or a line the same as "term".
  930.  * Unit 0 should have been closed before this call.
  931.  */
  932. void
  933. heredoc(term)
  934.     Char   *term;
  935. {
  936.     register int c;
  937.     Char   *Dv[2];
  938.     Char    obuf[BUFSIZE], lbuf[BUFSIZE], mbuf[BUFSIZE];
  939.     int     ocnt, lcnt, mcnt;
  940.     register Char *lbp, *obp, *mbp;
  941.     Char  **vp;
  942.     bool    quoted;
  943.     char   *tmp;
  944.  
  945.     if (creat(tmp = short2str(shtemp), 0600) < 0)
  946.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  947.     (void) close(0);
  948.     if (open(tmp, O_RDWR) < 0) {
  949.     int     oerrno = errno;
  950.  
  951.     (void) unlink(tmp);
  952.     errno = oerrno;
  953.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  954.     }
  955.     (void) unlink(tmp);        /* 0 0 inode! */
  956.     Dv[0] = term;
  957.     Dv[1] = NULL;
  958.     gflag = 0;
  959.     trim(Dv);
  960.     rscan(Dv, Dtestq);
  961.     quoted = gflag;
  962.     ocnt = BUFSIZE;
  963.     obp = obuf;
  964.     for (;;) {
  965.     /*
  966.      * Read up a line
  967.      */
  968.     lbp = lbuf;
  969.     lcnt = BUFSIZE - 4;
  970.     for (;;) {
  971.         c = readc(1);    /* 1 -> Want EOF returns */
  972.         if (c < 0 || c == '\n')
  973.         break;
  974.         if (c &= TRIM) {
  975.         *lbp++ = (Char) c;
  976.         if (--lcnt < 0) {
  977.             setname("<<");
  978.             stderror(ERR_NAME | ERR_OVERFLOW);
  979.         }
  980.         }
  981.     }
  982.     *lbp = 0;
  983.  
  984.     /*
  985.      * Check for EOF or compare to terminator -- before expansion
  986.      */
  987.     if (c < 0 || eq(lbuf, term)) {
  988.         (void) write(0, short2str(obuf), (size_t) (BUFSIZE - ocnt));
  989.         (void) lseek(0, 0l, L_SET);
  990.         return;
  991.     }
  992.  
  993.     /*
  994.      * If term was quoted or -n just pass it on
  995.      */
  996.     if (quoted || noexec) {
  997.         *lbp++ = '\n';
  998.         *lbp = 0;
  999.         for (lbp = lbuf; (c = *lbp++) != 0;) {
  1000.         *obp++ = (Char) c;
  1001.         if (--ocnt == 0) {
  1002.             (void) write(0, short2str(obuf), BUFSIZE);
  1003.             obp = obuf;
  1004.             ocnt = BUFSIZE;
  1005.         }
  1006.         }
  1007.         continue;
  1008.     }
  1009.  
  1010.     /*
  1011.      * Term wasn't quoted so variable and then command expand the input
  1012.      * line
  1013.      */
  1014.     Dcp = lbuf;
  1015.     Dvp = Dv + 1;
  1016.     mbp = mbuf;
  1017.     mcnt = BUFSIZE - 4;
  1018.     for (;;) {
  1019.         c = DgetC(DODOL);
  1020.         if (c == DEOF)
  1021.         break;
  1022.         if ((c &= TRIM) == 0)
  1023.         continue;
  1024.         /* \ quotes \ $ ` here */
  1025.         if (c == '\\') {
  1026.         c = DgetC(0);
  1027.         if (!any("$\\`", c))
  1028.             unDgetC(c | QUOTE), c = '\\';
  1029.         else
  1030.             c |= QUOTE;
  1031.         }
  1032.         *mbp++ = (Char) c;
  1033.         if (--mcnt == 0) {
  1034.         setname("<<");
  1035.         stderror(ERR_NAME | ERR_OVERFLOW);
  1036.         }
  1037.     }
  1038.     *mbp++ = 0;
  1039.  
  1040.     /*
  1041.      * If any ` in line do command substitution
  1042.      */
  1043.     mbp = mbuf;
  1044.     if (any(short2str(mbp), '`')) {
  1045.         /*
  1046.          * 1 arg to dobackp causes substitution to be literal. Words are
  1047.          * broken only at newlines so that all blanks and tabs are
  1048.          * preserved.  Blank lines (null words) are not discarded.
  1049.          */
  1050.         vp = dobackp(mbuf, 1);
  1051.     }
  1052.     else
  1053.         /* Setup trivial vector similar to return of dobackp */
  1054.         Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
  1055.  
  1056.     /*
  1057.      * Resurrect the words from the command substitution each separated by
  1058.      * a newline.  Note that the last newline of a command substitution
  1059.      * will have been discarded, but we put a newline after the last word
  1060.      * because this represents the newline after the last input line!
  1061.      */
  1062.     for (; *vp; vp++) {
  1063.         for (mbp = *vp; *mbp; mbp++) {
  1064.         *obp++ = *mbp & TRIM;
  1065.         if (--ocnt == 0) {
  1066.             (void) write(0, short2str(obuf), BUFSIZE);
  1067.             obp = obuf;
  1068.             ocnt = BUFSIZE;
  1069.         }
  1070.         }
  1071.         *obp++ = '\n';
  1072.         if (--ocnt == 0) {
  1073.         (void) write(0, short2str(obuf), BUFSIZE);
  1074.         obp = obuf;
  1075.         ocnt = BUFSIZE;
  1076.         }
  1077.     }
  1078.     if (pargv)
  1079.         blkfree(pargv), pargv = 0;
  1080.     }
  1081. }
  1082.