home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / csh / dol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-06  |  20.2 KB  |  986 lines

  1. /*-
  2.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. 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.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)dol.c    5.18 (Berkeley) 11/6/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/types.h>
  39. #include <fcntl.h>
  40. #include <errno.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <unistd.h>
  44. #if __STDC__
  45. # include <stdarg.h>
  46. #else
  47. # include <varargs.h>
  48. #endif
  49.  
  50. #include "csh.h"
  51. #include "extern.h"
  52.  
  53. /*
  54.  * These routines perform variable substitution and quoting via ' and ".
  55.  * To this point these constructs have been preserved in the divided
  56.  * input words.  Here we expand variables and turn quoting via ' and " into
  57.  * QUOTE bits on characters (which prevent further interpretation).
  58.  * If the `:q' modifier was applied during history expansion, then
  59.  * some QUOTEing may have occurred already, so we dont "trim()" here.
  60.  */
  61.  
  62. static int Dpeekc, Dpeekrd;    /* Peeks for DgetC and Dreadc */
  63. static Char *Dcp, **Dvp;    /* Input vector for Dreadc */
  64.  
  65. #define    DEOF    -1
  66.  
  67. #define    unDgetC(c)    Dpeekc = c
  68.  
  69. #define QUOTES        (_Q|_Q1|_ESC)    /* \ ' " ` */
  70.  
  71. /*
  72.  * The following variables give the information about the current
  73.  * $ expansion, recording the current word position, the remaining
  74.  * words within this expansion, the count of remaining words, and the
  75.  * information about any : modifier which is being applied.
  76.  */
  77. #define MAXWLEN (BUFSIZ - 4)
  78. #define MAXMOD MAXWLEN        /* This cannot overflow    */
  79. static Char *dolp;        /* Remaining chars from this word */
  80. static Char **dolnxt;        /* Further words */
  81. static int dolcnt;        /* Count of further words */
  82. static Char dolmod[MAXMOD];    /* : modifier character */
  83. static int dolnmod;        /* Number of modifiers */
  84. static int dolmcnt;        /* :gx -> 10000, else 1 */
  85. static int dolwcnt;        /* :wx -> 10000, else 1 */
  86.  
  87. static void     Dfix2 __P((Char **));
  88. static Char    *Dpack __P((Char *, Char *));
  89. static int     Dword __P((void));
  90. static void     dolerror __P((Char *));
  91. static int     DgetC __P((int));
  92. static void     Dgetdol __P((void));
  93. static void     fixDolMod __P((void));
  94. static void     setDolp __P((Char *));
  95. static void     unDredc __P((int));
  96. static int     Dredc __P((void));
  97. static void     Dtestq __P((int));
  98.  
  99.  
  100. /*
  101.  * Fix up the $ expansions and quotations in the
  102.  * argument list to command t.
  103.  */
  104. void
  105. Dfix(t)
  106.     register struct command *t;
  107. {
  108.     register Char **pp;
  109.     register Char *p;
  110.  
  111.     if (noexec)
  112.     return;
  113.     /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
  114.     for (pp = t->t_dcom; p = *pp++;)
  115.     for (; *p; p++) {
  116.         if (cmap(*p, _DOL | QUOTES)) {    /* $, \, ', ", ` */
  117.         Dfix2(t->t_dcom);    /* found one */
  118.         blkfree(t->t_dcom);
  119.         t->t_dcom = gargv;
  120.         gargv = 0;
  121.         return;
  122.         }
  123.     }
  124. }
  125.  
  126. /*
  127.  * $ substitute one word, for i/o redirection
  128.  */
  129. Char   *
  130. Dfix1(cp)
  131.     register Char *cp;
  132. {
  133.     Char   *Dv[2];
  134.  
  135.     if (noexec)
  136.     return (0);
  137.     Dv[0] = cp;
  138.     Dv[1] = NULL;
  139.     Dfix2(Dv);
  140.     if (gargc != 1) {
  141.     setname(vis_str(cp));
  142.     stderror(ERR_NAME | ERR_AMBIG);
  143.     }
  144.     cp = Strsave(gargv[0]);
  145.     blkfree(gargv), gargv = 0;
  146.     return (cp);
  147. }
  148.  
  149. /*
  150.  * Subroutine to do actual fixing after state initialization.
  151.  */
  152. static void
  153. Dfix2(v)
  154.     Char  **v;
  155. {
  156.     ginit();            /* Initialize glob's area pointers */
  157.     Dvp = v;
  158.     Dcp = STRNULL;        /* Setup input vector for Dreadc */
  159.     unDgetC(0);
  160.     unDredc(0);            /* Clear out any old peeks (at error) */
  161.     dolp = 0;
  162.     dolcnt = 0;            /* Clear out residual $ expands (...) */
  163.     while (Dword())
  164.     continue;
  165. }
  166.  
  167. /*
  168.  * Pack up more characters in this word
  169.  */
  170. static Char *
  171. Dpack(wbuf, wp)
  172.     Char   *wbuf, *wp;
  173. {
  174.     register int c;
  175.     register int i = MAXWLEN - (wp - wbuf);
  176.  
  177.     for (;;) {
  178.     c = DgetC(DODOL);
  179.     if (c == '\\') {
  180.         c = DgetC(0);
  181.         if (c == DEOF) {
  182.         unDredc(c);
  183.         *wp = 0;
  184.         Gcat(STRNULL, wbuf);
  185.         return (NULL);
  186.         }
  187.         if (c == '\n')
  188.         c = ' ';
  189.         else
  190.         c |= QUOTE;
  191.     }
  192.     if (c == DEOF) {
  193.         unDredc(c);
  194.         *wp = 0;
  195.         Gcat(STRNULL, wbuf);
  196.         return (NULL);
  197.     }
  198.     if (cmap(c, _SP | _NL | _Q | _Q1)) {    /* sp \t\n'"` */
  199.         unDgetC(c);
  200.         if (cmap(c, QUOTES))
  201.         return (wp);
  202.         *wp++ = 0;
  203.         Gcat(STRNULL, wbuf);
  204.         return (NULL);
  205.     }
  206.     if (--i <= 0)
  207.         stderror(ERR_WTOOLONG);
  208.     *wp++ = c;
  209.     }
  210. }
  211.  
  212. /*
  213.  * Get a word.  This routine is analogous to the routine
  214.  * word() in sh.lex.c for the main lexical input.  One difference
  215.  * here is that we don't get a newline to terminate our expansion.
  216.  * Rather, DgetC will return a DEOF when we hit the end-of-input.
  217.  */
  218. static int
  219. Dword()
  220. {
  221.     register int c, c1;
  222.     Char    wbuf[BUFSIZ];
  223.     register Char *wp = wbuf;
  224.     register int i = MAXWLEN;
  225.     register bool dolflg;
  226.     bool    sofar = 0, done = 0;
  227.  
  228.     while (!done) {
  229.     done = 1;
  230.     c = DgetC(DODOL);
  231.     switch (c) {
  232.  
  233.     case DEOF:
  234.         if (sofar == 0)
  235.         return (0);
  236.         /* finish this word and catch the code above the next time */
  237.         unDredc(c);
  238.         /* fall into ... */
  239.  
  240.     case '\n':
  241.         *wp = 0;
  242.         Gcat(STRNULL, wbuf);
  243.         return (1);
  244.  
  245.     case ' ':
  246.     case '\t':
  247.         done = 0;
  248.         break;
  249.  
  250.     case '`':
  251.         /* We preserve ` quotations which are done yet later */
  252.         *wp++ = c, --i;
  253.     case '\'':
  254.     case '"':
  255.         /*
  256.          * Note that DgetC never returns a QUOTES character from an
  257.          * expansion, so only true input quotes will get us here or out.
  258.          */
  259.         c1 = c;
  260.         dolflg = c1 == '"' ? DODOL : 0;
  261.         for (;;) {
  262.         c = DgetC(dolflg);
  263.         if (c == c1)
  264.             break;
  265.         if (c == '\n' || c == DEOF)
  266.             stderror(ERR_UNMATCHED, c1);
  267.         if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
  268.             --wp, ++i;
  269.         if (--i <= 0)
  270.             stderror(ERR_WTOOLONG);
  271.         switch (c1) {
  272.  
  273.         case '"':
  274.             /*
  275.              * Leave any `s alone for later. Other chars are all
  276.              * quoted, thus `...` can tell it was within "...".
  277.              */
  278.             *wp++ = c == '`' ? '`' : c | QUOTE;
  279.             break;
  280.  
  281.         case '\'':
  282.             /* Prevent all further interpretation */
  283.             *wp++ = c | QUOTE;
  284.             break;
  285.  
  286.         case '`':
  287.             /* Leave all text alone for later */
  288.             *wp++ = c;
  289.             break;
  290.  
  291.         default:
  292.             break;
  293.         }
  294.         }
  295.         if (c1 == '`')
  296.         *wp++ = '`' /* i--; eliminated */;
  297.         sofar = 1;
  298.         if ((wp = Dpack(wbuf, wp)) == NULL)
  299.         return (1);
  300.         else {
  301.         i = MAXWLEN - (wp - wbuf);
  302.         done = 0;
  303.         }
  304.         break;
  305.  
  306.     case '\\':
  307.         c = DgetC(0);    /* No $ subst! */
  308.         if (c == '\n' || c == DEOF) {
  309.         done = 0;
  310.         break;
  311.         }
  312.         c |= QUOTE;
  313.         break;
  314.  
  315.     default:
  316.         break;
  317.     }
  318.     if (done) {
  319.         unDgetC(c);
  320.         sofar = 1;
  321.         if ((wp = Dpack(wbuf, wp)) == NULL)
  322.         return (1);
  323.         else {
  324.         i = MAXWLEN - (wp - wbuf);
  325.         done = 0;
  326.         }
  327.     }
  328.     }
  329.     /* Really NOTREACHED */
  330.     return (0);
  331. }
  332.  
  333.  
  334. /*
  335.  * Get a character, performing $ substitution unless flag is 0.
  336.  * Any QUOTES character which is returned from a $ expansion is
  337.  * QUOTEd so that it will not be recognized above.
  338.  */
  339. static int
  340. DgetC(flag)
  341.     register int flag;
  342. {
  343.     register int c;
  344.  
  345. top:
  346.     if (c = Dpeekc) {
  347.     Dpeekc = 0;
  348.     return (c);
  349.     }
  350.     if (lap) {
  351.     c = *lap++ & (QUOTE | TRIM);
  352.     if (c == 0) {
  353.         lap = 0;
  354.         goto top;
  355.     }
  356. quotspec:
  357.     if (cmap(c, QUOTES))
  358.         return (c | QUOTE);
  359.     return (c);
  360.     }
  361.     if (dolp) {
  362.     if (c = *dolp++ & (QUOTE | TRIM))
  363.         goto quotspec;
  364.     if (dolcnt > 0) {
  365.         setDolp(*dolnxt++);
  366.         --dolcnt;
  367.         return (' ');
  368.     }
  369.     dolp = 0;
  370.     }
  371.     if (dolcnt > 0) {
  372.     setDolp(*dolnxt++);
  373.     --dolcnt;
  374.     goto top;
  375.     }
  376.     c = Dredc();
  377.     if (c == '$' && flag) {
  378.     Dgetdol();
  379.     goto top;
  380.     }
  381.     return (c);
  382. }
  383.  
  384. static Char *nulvec[] = {0};
  385. static struct varent nulargv = {nulvec, STRargv, 0};
  386.  
  387. static void
  388. dolerror(s)
  389.     Char   *s;
  390. {
  391.     setname(vis_str(s));
  392.     stderror(ERR_NAME | ERR_RANGE);
  393. }
  394.  
  395. /*
  396.  * Handle the multitudinous $ expansion forms.
  397.  * Ugh.
  398.  */
  399. static void
  400. Dgetdol()
  401. {
  402.     register Char *np;
  403.     register struct varent *vp = NULL;
  404.     Char    name[4 * MAXVARLEN + 1];
  405.     int     c, sc;
  406.     int     subscr = 0, lwb = 1, upb = 0;
  407.     bool    dimen = 0, bitset = 0;
  408.     char    tnp;
  409.     Char    wbuf[BUFSIZ];
  410.     static Char *dolbang = NULL;
  411.  
  412.     dolnmod = dolmcnt = dolwcnt = 0;
  413.     c = sc = DgetC(0);
  414.     if (c == '{')
  415.     c = DgetC(0);        /* sc is { to take } later */
  416.     if ((c & TRIM) == '#')
  417.     dimen++, c = DgetC(0);    /* $# takes dimension */
  418.     else if (c == '?')
  419.     bitset++, c = DgetC(0);    /* $? tests existence */
  420.     switch (c) {
  421.  
  422.     case '!':
  423.     if (dimen || bitset)
  424.         stderror(ERR_SYNTAX);
  425.     if (backpid != 0) {
  426.         if (dolbang) 
  427.         xfree((ptr_t) dolbang);
  428.         setDolp(dolbang = putn(backpid));
  429.     }
  430.     goto eatbrac;
  431.  
  432.     case '$':
  433.     if (dimen || bitset)
  434.         stderror(ERR_SYNTAX);
  435.     setDolp(doldol);
  436.     goto eatbrac;
  437.  
  438.     case '<' | QUOTE:
  439.     if (bitset)
  440.         stderror(ERR_NOTALLOWED, "$?<");
  441.     if (dimen)
  442.         stderror(ERR_NOTALLOWED, "$?#");
  443.     for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
  444.         *np = tnp;
  445.         if (np >= &wbuf[BUFSIZ - 1])
  446.         stderror(ERR_LTOOLONG);
  447.         if (SIGN_EXTEND_CHAR(tnp) <= 0 || tnp == '\n')
  448.         break;
  449.     }
  450.     *np = 0;
  451.     /*
  452.      * KLUDGE: dolmod is set here because it will cause setDolp to call
  453.      * domod and thus to copy wbuf. Otherwise setDolp would use it
  454.      * directly. If we saved it ourselves, no one would know when to free
  455.      * it. The actual function of the 'q' causes filename expansion not to
  456.      * be done on the interpolated value.
  457.      */
  458.     dolmod[dolnmod++] = 'q';
  459.     dolmcnt = 10000;
  460.     setDolp(wbuf);
  461.     goto eatbrac;
  462.  
  463.     case DEOF:
  464.     case '\n':
  465.     stderror(ERR_SYNTAX);
  466.     /* NOTREACHED */
  467.     break;
  468.  
  469.     case '*':
  470.     (void) Strcpy(name, STRargv);
  471.     vp = adrof(STRargv);
  472.     subscr = -1;        /* Prevent eating [...] */
  473.     break;
  474.  
  475.     default:
  476.     np = name;
  477.     if (Isdigit(c)) {
  478.         if (dimen)
  479.         stderror(ERR_NOTALLOWED, "$#<num>");
  480.         subscr = 0;
  481.         do {
  482.         subscr = subscr * 10 + c - '0';
  483.         c = DgetC(0);
  484.         } while (Isdigit(c));
  485.         unDredc(c);
  486.         if (subscr < 0) {
  487.         dolerror(vp->v_name);
  488.         return;
  489.         }
  490.         if (subscr == 0) {
  491.         if (bitset) {
  492.             dolp = ffile ? STR1 : STR0;
  493.             goto eatbrac;
  494.         }
  495.         if (ffile == 0)
  496.             stderror(ERR_DOLZERO);
  497.         fixDolMod();
  498.         setDolp(ffile);
  499.         goto eatbrac;
  500.         }
  501.         if (bitset)
  502.         stderror(ERR_DOLQUEST);
  503.         vp = adrof(STRargv);
  504.         if (vp == 0) {
  505.         vp = &nulargv;
  506.         goto eatmod;
  507.         }
  508.         break;
  509.     }
  510.     if (!alnum(c))
  511.         stderror(ERR_VARALNUM);
  512.     for (;;) {
  513.         *np++ = c;
  514.         c = DgetC(0);
  515.         if (!alnum(c))
  516.         break;
  517.         if (np >= &name[MAXVARLEN])
  518.         stderror(ERR_VARTOOLONG);
  519.     }
  520.     *np++ = 0;
  521.     unDredc(c);
  522.     vp = adrof(name);
  523.     }
  524.     if (bitset) {
  525.     dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
  526.     goto eatbrac;
  527.     }
  528.     if (vp == 0) {
  529.     np = str2short(getenv(short2str(name)));
  530.     if (np) {
  531.         fixDolMod();
  532.         setDolp(np);
  533.         goto eatbrac;
  534.     }
  535.     udvar(name);
  536.     /* NOTREACHED */
  537.     }
  538.     c = DgetC(0);
  539.     upb = blklen(vp->vec);
  540.     if (dimen == 0 && subscr == 0 && c == '[') {
  541.     np = name;
  542.     for (;;) {
  543.         c = DgetC(DODOL);    /* Allow $ expand within [ ] */
  544.         if (c == ']')
  545.         break;
  546.         if (c == '\n' || c == DEOF)
  547.         stderror(ERR_INCBR);
  548.         if (np >= &name[sizeof(name) / sizeof(Char) - 2])
  549.         stderror(ERR_VARTOOLONG);
  550.         *np++ = c;
  551.     }
  552.     *np = 0, np = name;
  553.     if (dolp || dolcnt)    /* $ exp must end before ] */
  554.         stderror(ERR_EXPORD);
  555.     if (!*np)
  556.         stderror(ERR_SYNTAX);
  557.     if (Isdigit(*np)) {
  558.         int     i;
  559.  
  560.         for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
  561.         continue;
  562.         if ((i < 0 || i > upb) && !any("-*", *np)) {
  563.         dolerror(vp->v_name);
  564.         return;
  565.         }
  566.         lwb = i;
  567.         if (!*np)
  568.         upb = lwb, np = STRstar;
  569.     }
  570.     if (*np == '*')
  571.         np++;
  572.     else if (*np != '-')
  573.         stderror(ERR_MISSING, '-');
  574.     else {
  575.         register int i = upb;
  576.  
  577.         np++;
  578.         if (Isdigit(*np)) {
  579.         i = 0;
  580.         while (Isdigit(*np))
  581.             i = i * 10 + *np++ - '0';
  582.         if (i < 0 || i > upb) {
  583.             dolerror(vp->v_name);
  584.             return;
  585.         }
  586.         }
  587.         if (i < lwb)
  588.         upb = lwb - 1;
  589.         else
  590.         upb = i;
  591.     }
  592.     if (lwb == 0) {
  593.         if (upb != 0) {
  594.         dolerror(vp->v_name);
  595.         return;
  596.         }
  597.         upb = -1;
  598.     }
  599.     if (*np)
  600.         stderror(ERR_SYNTAX);
  601.     }
  602.     else {
  603.     if (subscr > 0)
  604.         if (subscr > upb)
  605.         lwb = 1, upb = 0;
  606.         else
  607.         lwb = upb = subscr;
  608.     unDredc(c);
  609.     }
  610.     if (dimen) {
  611.     Char   *cp = putn(upb - lwb + 1);
  612.  
  613.     addla(cp);
  614.     xfree((ptr_t) cp);
  615.     }
  616.     else {
  617. eatmod:
  618.     fixDolMod();
  619.     dolnxt = &vp->vec[lwb - 1];
  620.     dolcnt = upb - lwb + 1;
  621.     }
  622. eatbrac:
  623.     if (sc == '{') {
  624.     c = Dredc();
  625.     if (c != '}')
  626.         stderror(ERR_MISSING, '}');
  627.     }
  628. }
  629.  
  630. static void
  631. fixDolMod()
  632. {
  633.     register int c;
  634.  
  635.     c = DgetC(0);
  636.     if (c == ':') {
  637.     do {
  638.         c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
  639.         if (c == 'g' || c == 'a') {
  640.         if (c == 'g')
  641.             dolmcnt = 10000;
  642.         else
  643.             dolwcnt = 10000;
  644.         c = DgetC(0);
  645.         }
  646.         if ((c == 'g' && dolmcnt != 10000) || 
  647.         (c == 'a' && dolwcnt != 10000)) {
  648.         if (c == 'g')
  649.             dolmcnt = 10000;
  650.         else
  651.             dolwcnt = 10000;
  652.         c = DgetC(0); 
  653.         }
  654.  
  655.         if (c == 's') {    /* [eichin:19910926.0755EST] */
  656.         int delimcnt = 2;
  657.         int delim = DgetC(0);
  658.         dolmod[dolnmod++] = c;
  659.         dolmod[dolnmod++] = delim;
  660.         
  661.         if (!delim || letter(delim)
  662.             || Isdigit(delim) || any(" \t\n", delim)) {
  663.             seterror(ERR_BADSUBST);
  664.             break;
  665.         }    
  666.         while ((c = DgetC(0)) != (-1)) {
  667.             dolmod[dolnmod++] = c;
  668.             if(c == delim) delimcnt--;
  669.             if(!delimcnt) break;
  670.         }
  671.         if(delimcnt) {
  672.             seterror(ERR_BADSUBST);
  673.             break;
  674.         }
  675.         continue;
  676.         }
  677.         if (!any("htrqxes", c))
  678.         stderror(ERR_BADMOD, c);
  679.         dolmod[dolnmod++] = c;
  680.         if (c == 'q')
  681.         dolmcnt = 10000;
  682.     }
  683.     while ((c = DgetC(0)) == ':');
  684.     unDredc(c);
  685.     }
  686.     else
  687.     unDredc(c);
  688. }
  689.  
  690. static void
  691. setDolp(cp)
  692.     register Char *cp;
  693. {
  694.     register Char *dp;
  695.     int i;
  696.  
  697.     if (dolnmod == 0 || dolmcnt == 0) {
  698.     dolp = cp;
  699.     return;
  700.     }
  701.     dp = cp = Strsave(cp);
  702.     for (i = 0; i < dolnmod; i++) {
  703.     /* handle s// [eichin:19910926.0510EST] */
  704.     if(dolmod[i] == 's') {
  705.         int delim;
  706.         Char *lhsub, *rhsub, *np;
  707.         size_t lhlen = 0, rhlen = 0;
  708.         int didmod = 0;
  709.         
  710.         delim = dolmod[++i];
  711.         if (!delim || letter(delim)
  712.         || Isdigit(delim) || any(" \t\n", delim)) {
  713.         seterror(ERR_BADSUBST);
  714.         break;
  715.         }
  716.         lhsub = &dolmod[++i];
  717.         while(dolmod[i] != delim && dolmod[++i]) {
  718.         lhlen++;
  719.         }
  720.         dolmod[i] = 0;
  721.         rhsub = &dolmod[++i];
  722.         while(dolmod[i] != delim && dolmod[++i]) {
  723.         rhlen++;
  724.         }
  725.         dolmod[i] = 0;
  726.  
  727.         do {
  728.         dp = Strstr(cp, lhsub);
  729.         if (dp) {
  730.             np = (Char *) xmalloc((size_t)
  731.                       ((Strlen(cp) + 1 - lhlen + rhlen) *
  732.                       sizeof(Char)));
  733.             (void) Strncpy(np, cp, dp - cp);
  734.             (void) Strcpy(np + (dp - cp), rhsub);
  735.             (void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
  736.  
  737.             xfree((ptr_t) cp);
  738.             dp = cp = np;
  739.             didmod = 1;
  740.         } else {
  741.             /* should this do a seterror? */
  742.             break;
  743.         }
  744.         }
  745.         while (dolwcnt == 10000);
  746.         /*
  747.          * restore dolmod for additional words
  748.          */
  749.         dolmod[i] = rhsub[-1] = delim;
  750.         if (didmod)
  751.         dolmcnt--;
  752.         else
  753.         break;
  754.         } else {
  755.         int didmod = 0;
  756.  
  757.         do {
  758.         if ((dp = domod(cp, dolmod[i]))) {
  759.             didmod = 1;
  760.             if (Strcmp(cp, dp) == 0) {
  761.             xfree((ptr_t) cp);
  762.             cp = dp;
  763.             break;
  764.             }
  765.             else {
  766.             xfree((ptr_t) cp);
  767.             cp = dp;
  768.             }
  769.         }
  770.         else
  771.             break;
  772.         }
  773.         while (dolwcnt == 10000);
  774.         dp = cp;
  775.         if (didmod)
  776.         dolmcnt--;
  777.         else
  778.         break;
  779.     }
  780.     }
  781.  
  782.     if (dp) {
  783.     addla(dp);
  784.     xfree((ptr_t) dp);
  785.     }
  786.     else
  787.     addla(cp);
  788.  
  789.     dolp = STRNULL;
  790.     if (seterr)
  791.     stderror(ERR_OLD);
  792. }
  793.  
  794. static void
  795. unDredc(c)
  796.     int     c;
  797. {
  798.  
  799.     Dpeekrd = c;
  800. }
  801.  
  802. static int
  803. Dredc()
  804. {
  805.     register int c;
  806.  
  807.     if (c = Dpeekrd) {
  808.     Dpeekrd = 0;
  809.     return (c);
  810.     }
  811.     if (Dcp && (c = *Dcp++))
  812.     return (c & (QUOTE | TRIM));
  813.     if (*Dvp == 0) {
  814.     Dcp = 0;
  815.     return (DEOF);
  816.     }
  817.     Dcp = *Dvp++;
  818.     return (' ');
  819. }
  820.  
  821. static void
  822. Dtestq(c)
  823.     register int c;
  824. {
  825.  
  826.     if (cmap(c, QUOTES))
  827.     gflag = 1;
  828. }
  829.  
  830. /*
  831.  * Form a shell temporary file (in unit 0) from the words
  832.  * of the shell input up to EOF or a line the same as "term".
  833.  * Unit 0 should have been closed before this call.
  834.  */
  835. void
  836. /*ARGSUSED*/
  837. heredoc(term)
  838.     Char *term;
  839. {
  840.     register int c;
  841.     Char   *Dv[2];
  842.     Char    obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
  843.     int     ocnt, lcnt, mcnt;
  844.     register Char *lbp, *obp, *mbp;
  845.     Char  **vp;
  846.     bool    quoted;
  847.     char   *tmp;
  848.  
  849.     if (creat(tmp = short2str(shtemp), 0600) < 0)
  850.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  851.     (void) close(0);
  852.     if (open(tmp, O_RDWR) < 0) {
  853.     int     oerrno = errno;
  854.  
  855.     (void) unlink(tmp);
  856.     errno = oerrno;
  857.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  858.     }
  859.     (void) unlink(tmp);        /* 0 0 inode! */
  860.     Dv[0] = term;
  861.     Dv[1] = NULL;
  862.     gflag = 0;
  863.     trim(Dv);
  864.     rscan(Dv, Dtestq);
  865.     quoted = gflag;
  866.     ocnt = BUFSIZ;
  867.     obp = obuf;
  868.     for (;;) {
  869.     /*
  870.      * Read up a line
  871.      */
  872.     lbp = lbuf;
  873.     lcnt = BUFSIZ - 4;
  874.     for (;;) {
  875.         c = readc(1);    /* 1 -> Want EOF returns */
  876.         if (c < 0 || c == '\n')
  877.         break;
  878.         if (c &= TRIM) {
  879.         *lbp++ = c;
  880.         if (--lcnt < 0) {
  881.             setname("<<");
  882.             stderror(ERR_NAME | ERR_OVERFLOW);
  883.         }
  884.         }
  885.     }
  886.     *lbp = 0;
  887.  
  888.     /*
  889.      * Check for EOF or compare to terminator -- before expansion
  890.      */
  891.     if (c < 0 || eq(lbuf, term)) {
  892.         (void) write(0, short2str(obuf), (size_t) (BUFSIZ - ocnt));
  893.         (void) lseek(0, 0l, L_SET);
  894.         return;
  895.     }
  896.  
  897.     /*
  898.      * If term was quoted or -n just pass it on
  899.      */
  900.     if (quoted || noexec) {
  901.         *lbp++ = '\n';
  902.         *lbp = 0;
  903.         for (lbp = lbuf; c = *lbp++;) {
  904.         *obp++ = c;
  905.         if (--ocnt == 0) {
  906.             (void) write(0, short2str(obuf), BUFSIZ);
  907.             obp = obuf;
  908.             ocnt = BUFSIZ;
  909.         }
  910.         }
  911.         continue;
  912.     }
  913.  
  914.     /*
  915.      * Term wasn't quoted so variable and then command expand the input
  916.      * line
  917.      */
  918.     Dcp = lbuf;
  919.     Dvp = Dv + 1;
  920.     mbp = mbuf;
  921.     mcnt = BUFSIZ - 4;
  922.     for (;;) {
  923.         c = DgetC(DODOL);
  924.         if (c == DEOF)
  925.         break;
  926.         if ((c &= TRIM) == 0)
  927.         continue;
  928.         /* \ quotes \ $ ` here */
  929.         if (c == '\\') {
  930.         c = DgetC(0);
  931.         if (!any("$\\`", c))
  932.             unDgetC(c | QUOTE), c = '\\';
  933.         else
  934.             c |= QUOTE;
  935.         }
  936.         *mbp++ = c;
  937.         if (--mcnt == 0) {
  938.         setname("<<");
  939.         stderror(ERR_NAME | ERR_OVERFLOW);
  940.         }
  941.     }
  942.     *mbp++ = 0;
  943.  
  944.     /*
  945.      * If any ` in line do command substitution
  946.      */
  947.     mbp = mbuf;
  948.     if (any(short2str(mbp), '`')) {
  949.         /*
  950.          * 1 arg to dobackp causes substitution to be literal. Words are
  951.          * broken only at newlines so that all blanks and tabs are
  952.          * preserved.  Blank lines (null words) are not discarded.
  953.          */
  954.         vp = dobackp(mbuf, 1);
  955.     }
  956.     else
  957.         /* Setup trivial vector similar to return of dobackp */
  958.         Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
  959.  
  960.     /*
  961.      * Resurrect the words from the command substitution each separated by
  962.      * a newline.  Note that the last newline of a command substitution
  963.      * will have been discarded, but we put a newline after the last word
  964.      * because this represents the newline after the last input line!
  965.      */
  966.     for (; *vp; vp++) {
  967.         for (mbp = *vp; *mbp; mbp++) {
  968.         *obp++ = *mbp & TRIM;
  969.         if (--ocnt == 0) {
  970.             (void) write(0, short2str(obuf), BUFSIZ);
  971.             obp = obuf;
  972.             ocnt = BUFSIZ;
  973.         }
  974.         }
  975.         *obp++ = '\n';
  976.         if (--ocnt == 0) {
  977.         (void) write(0, short2str(obuf), BUFSIZ);
  978.         obp = obuf;
  979.         ocnt = BUFSIZ;
  980.         }
  981.     }
  982.     if (pargv)
  983.         blkfree(pargv), pargv = 0;
  984.     }
  985. }
  986.