home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Distributions / ucb / spencer_2bsd.tar.gz / 2bsd.tar / src / csh / sh.dol.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  12KB  |  669 lines

  1. /* Copyright (c) 1979 Regents of the University of California */
  2. #include "sh.h"
  3.  
  4. /*
  5.  * C shell
  6.  */
  7.  
  8. /*
  9.  * These routines perform variable substitution and quoting via ' and ".
  10.  * To this point these constructs have been preserved in the divided
  11.  * input words.  Here we expand variables and turn quoting via ' and " into
  12.  * QUOTE bits on characters (which prevent further interpretation).
  13.  * If the `:q' modifier was applied during history expansion, then
  14.  * some QUOTEing may have occurred already, so we dont "scan(,&trim)" here.
  15.  */
  16.  
  17. int    Dpeekc, Dpeekrd;        /* Peeks for DgetC and Dreadc */
  18. char    *Dcp, **Dvp;            /* Input vector for Dreadc */
  19.  
  20. #define    DEOF    -1
  21.  
  22. #define    unDgetC(c)    Dpeekc = c
  23.  
  24. char    *QUOTES = "\\'`\"";
  25.  
  26. /*
  27.  * The following variables give the information about the current
  28.  * $ expansion, recording the current word position, the remaining
  29.  * words within this expansion, the count of remaining words, and the
  30.  * information about any : modifier which is being applied.
  31.  */
  32. char    *dolp;            /* Remaining chars from this word */
  33. char    **dolnxt;        /* Further words */
  34. int    dolcnt;            /* Count of further words */
  35. char    dolmod;            /* : modifier character */
  36. int    dolmcnt;        /* :gx -> 10000, else 1 */
  37.  
  38. int    Dtest();        /* Test for \ " ` or ' */
  39.  
  40. /*
  41.  * Fix up the $ expansions and quotations in the
  42.  * argument list to command t.
  43.  */
  44. Dfix(t)
  45.     register struct command *t;
  46. {
  47.  
  48.     if (noexec)
  49.         return;
  50.     gflag = 0, rscan(t->t_dcom, Dtest);
  51.     if (gflag == 0)
  52.         return;
  53.     Dfix2(t->t_dcom);
  54.     blkfree(t->t_dcom), t->t_dcom = gargv, gargv = 0;
  55. }
  56.  
  57. /*
  58.  * $ substitute one word, for i/o redirection
  59.  */
  60. char *
  61. Dfix1(cp)
  62.     register char *cp;
  63. {
  64.     char *Dv[2];
  65.  
  66.     if (noexec)
  67.         return (0);
  68.     Dv[0] = cp; Dv[1] = NOSTR;
  69.     Dfix2(Dv);
  70.     if (gargc != 1) {
  71.         setname(cp);
  72.         bferr("Ambiguous");
  73.     }
  74.     cp = savestr(gargv[0]);
  75.     blkfree(gargv), gargv = 0;
  76.     return (cp);
  77. }
  78.  
  79. /*
  80.  * Subroutine to do actual fixing after state initialization.
  81.  */
  82. Dfix2(v)
  83.     char **v;
  84. {
  85.     char *agargv[GAVSIZ];
  86.  
  87.     ginit(agargv);            /* Initialize glob's area pointers */
  88.     Dvp = v; Dcp = "";        /* Setup input vector for Dreadc */
  89.     unDgetC(0); unDredc(0);        /* Clear out any old peeks (at error) */
  90.     dolp = 0; dolcnt = 0;        /* Clear out residual $ expands (...) */
  91.     while (Dword())
  92.         continue;
  93.     gargv = copyblk(gargv);
  94. }
  95.  
  96. /*
  97.  * Get a word.  This routine is analogous to the routine
  98.  * word() in sh.lex.c for the main lexical input.  One difference
  99.  * here is that we don't get a newline to terminate our expansion.
  100.  * Rather, DgetC will return a DEOF when we hit the end-of-input.
  101.  */
  102. Dword()
  103. {
  104.     register int c, c1;
  105.     char wbuf[BUFSIZ];
  106.     register char *wp = wbuf;
  107.     register int i = BUFSIZ - 4;
  108.     register bool dolflg;
  109.     bool sofar = 0;
  110.  
  111. loop:
  112.     c = DgetC(DODOL);
  113.     switch (c) {
  114.  
  115.     case DEOF:
  116. deof:
  117.         if (sofar == 0)
  118.             return (0);
  119.         /* finish this word and catch the code above the next time */
  120.         unDredc(c);
  121.         /* fall into ... */
  122.  
  123.     case '\n':
  124.         *wp = 0;
  125.         goto ret;
  126.  
  127.     case ' ':
  128.     case '\t':
  129.         goto loop;
  130.  
  131.     case '`':
  132.         /* We preserve ` quotations which are done yet later */
  133.         *wp++ = c, --i;
  134.     case '\'':
  135.     case '"':
  136.         /*
  137.          * Note that DgetC never returns a QUOTES character
  138.          * from an expansion, so only true input quotes will
  139.          * get us here or out.
  140.          */
  141.         c1 = c;
  142.         dolflg = c1 == '"' ? DODOL : 0;
  143.         for (;;) {
  144.             c = DgetC(dolflg);
  145.             if (c == c1)
  146.                 break;
  147.             if (c == '\n' || c == DEOF)
  148.                 error("Unmatched %c", c1);
  149.             if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
  150.                 --wp, ++i;
  151.             if (--i <= 0)
  152.                 goto toochars;
  153.             switch (c1) {
  154.  
  155.             case '"':
  156.                 /*
  157.                  * Leave any `s alone for later.
  158.                  * Other chars are all quoted, thus `...`
  159.                  * can tell it was within "...".
  160.                  */
  161.                 *wp++ = c == '`' ? '`' : c | QUOTE;
  162.                 break;
  163.  
  164.             case '\'':
  165.                 /* Prevent all further interpretation */
  166.                 *wp++ = c | QUOTE;
  167.                 break;
  168.  
  169.             case '`':
  170.                 /* Leave all text alone for later */
  171.                 *wp++ = c;
  172.                 break;
  173.             }
  174.         }
  175.         if (c1 == '`')
  176.             *wp++ = '`', --i;
  177.         goto pack;        /* continue the word */
  178.  
  179.     case '\\':
  180.         c = DgetC(0);        /* No $ subst! */
  181.         if (c == '\n' || c == DEOF)
  182.             goto loop;
  183.         c |= QUOTE;
  184.         break;
  185.     }
  186.     unDgetC(c);
  187. pack:
  188.     sofar = 1;
  189.     /* pack up more characters in this word */
  190.     for (;;) {
  191.         c = DgetC(DODOL);
  192.         if (c == '\\') {
  193.             c = DgetC(0);
  194.             if (c == DEOF)
  195.                 goto deof;
  196.             if (c == '\n')
  197.                 c = ' ';
  198.             else
  199.                 c |= QUOTE;
  200.         }
  201.         if (c == DEOF)
  202.             goto deof;
  203.         if (any(c, " '`\"\t\n")) {
  204.             unDgetC(c);
  205.             if (any(c, QUOTES))
  206.                 goto loop;
  207.             *wp++ = 0;
  208.             goto ret;
  209.         }
  210.         if (--i <= 0)
  211. toochars:
  212.             error("Word too long");
  213.         *wp++ = c;
  214.     }
  215. ret:
  216.     Gcat("", wbuf);
  217.     return (1);
  218. }
  219.  
  220. /*
  221.  * Get a character, performing $ substitution unless flag is 0.
  222.  * Any QUOTES character which is returned from a $ expansion is
  223.  * QUOTEd so that it will not be recognized above.
  224.  */
  225. DgetC(flag)
  226.     register int flag;
  227. {
  228.     register int c;
  229.  
  230. top:
  231.     if (c = Dpeekc) {
  232.         Dpeekc = 0;
  233.         return (c);
  234.     }
  235.     if (lap) {
  236.         c = *lap++;
  237.         if (c == 0) {
  238.             lap = 0;
  239.             goto top;
  240.         }
  241. quotspec:
  242.         if (any(c, QUOTES))
  243.             return (c | QUOTE);
  244.         return (c);
  245.     }
  246.     if (dolp) {
  247.         if (c = *dolp++)
  248.             goto quotspec;
  249.         if (dolcnt > 0) {
  250.             setDolp(*dolnxt++);
  251.             --dolcnt;
  252.             return (' ');
  253.         }
  254.         dolp = 0;
  255.     }
  256.     if (dolcnt > 0) {
  257.         setDolp(*dolnxt++);
  258.         --dolcnt;
  259.         goto top;
  260.     }
  261.     c = Dredc();
  262.     if (c == '$' && flag) {
  263.         Dgetdol();
  264.         goto top;
  265.     }
  266.     return (c);
  267. }
  268.  
  269. char    *nulvec[] = { 0 };
  270. struct    varent nulargv = { nulvec, "argv", 0 };
  271.  
  272. /*
  273.  * Handle the multitudinous $ expansion forms.
  274.  * Ugh.
  275.  */
  276. Dgetdol()
  277. {
  278.     register char *np;
  279.     register struct varent *vp;
  280.     char name[20];
  281.     int c, sc;
  282.     int subscr = 0, lwb = 1, upb = 0;
  283.     bool dimen = 0, isset = 0;
  284.  
  285.     dolmod = dolmcnt = 0;
  286.     c = sc = DgetC(0);
  287.     if (c == '{')
  288.         c = DgetC(0);        /* sc is { to take } later */
  289.     if ((c & TRIM) == '#')
  290.         dimen++, c = DgetC(0);        /* $# takes dimension */
  291.     else if (c == '?')
  292.         isset++, c = DgetC(0);        /* $? tests existence */
  293.     switch (c) {
  294.     
  295.     case '$':
  296.         if (dimen || isset)
  297.             goto syntax;        /* No $?$, $#$ */
  298.         setDolp(doldol);
  299.         goto eatbrac;
  300.  
  301.     case DEOF:
  302.     case '\n':
  303.         goto syntax;
  304.  
  305.     case '*':
  306.         strcpy(name, "argv");
  307.         vp = adrof("argv");
  308.         subscr = -1;            /* Prevent eating [...] */
  309.         break;
  310.  
  311.     default:
  312.         np = name;
  313.         if (digit(c)) {
  314.             if (dimen)
  315.                 goto syntax;    /* No $#1, e.g. */
  316.             subscr = 0;
  317.             do {
  318.                 subscr = subscr * 10 + c - '0';
  319.                 c = DgetC(0);
  320.             } while (digit(c));
  321.             unDredc(c);
  322.             if (subscr < 0)
  323.                 goto oob;
  324.             if (subscr == 0) {
  325.                 if (isset) {
  326.                     dolp = file ? "1" : "0";
  327.                     goto eatbrac;
  328.                 }
  329.                 if (file == 0)
  330.                     error("No file for $0");
  331.                 setDolp(file);
  332.                 goto eatbrac;
  333.             }
  334.             if (isset)
  335.                 goto syntax;
  336.             vp = adrof("argv");
  337.             if (vp == 0) {
  338.                 vp = &nulargv;
  339.                 goto eatmod;
  340.             }
  341.             break;
  342.         }
  343.         if (!letter(c))
  344.             goto syntax;
  345.         for (;;) {
  346.             *np++ = c;
  347.             c = DgetC(0);
  348.             if (!letter(c))
  349.                 break;
  350.             if (np >= &name[sizeof name - 2])
  351. syntax:
  352.                 error("Variable syntax");
  353.         }
  354.         *np++ = 0;
  355.         unDredc(c);
  356.         vp = adrof(name);
  357.     }
  358.     if (isset) {
  359.         dolp = vp ? "1" : "0";
  360.         goto eatbrac;
  361.     }
  362.     if (vp == 0)
  363.         udvar(name);
  364.     c = DgetC(0);
  365.     upb = blklen(vp->vec);
  366.     if (dimen == 0 && subscr == 0 && c == '[') {
  367.         np = name;
  368.         for (;;) {
  369.             c = DgetC(DODOL);    /* Allow $ expand within [ ] */
  370.             if (c == ']')
  371.                 break;
  372.             if (c == '\n' || c == DEOF)
  373.                 goto syntax;
  374.             if (np >= &name[sizeof name - 2])
  375.                 goto syntax;
  376.             *np++ = c;
  377.         }
  378.         *np = 0, np = name;
  379.         if (dolp || dolcnt)        /* $ exp must end before ] */
  380.             goto syntax;
  381.         if (!*np)
  382.             goto syntax;
  383.         if (digit(*np)) {
  384.             register int i = 0;
  385.  
  386.             while (digit(*np))
  387.                 i = i * 10 + *np++ - '0';
  388.             if ((i < 0 || i > upb) && !any(*np, "-*")) {
  389. oob:
  390.                 setname(vp->name);
  391.                 error("Subscript out of range");
  392.             }
  393.             lwb = i;
  394.             if (!*np)
  395.                 upb = lwb, np = "*";
  396.         }
  397.         if (*np == '*')
  398.             np++;
  399.         else if (*np != '-')
  400.             goto syntax;
  401.         else {
  402.             register int i = upb;
  403.  
  404.             np++;
  405.             if (digit(*np)) {
  406.                 i = 0;
  407.                 while (digit(*np))
  408.                     i = i * 10 + *np++ - '0';
  409.                 if (i < 0 || i > upb)
  410.                     goto oob;
  411.             }
  412.             if (i < lwb)
  413.                 upb = lwb - 1;
  414.             else
  415.                 upb = i;
  416.         }
  417.         if (lwb == 0) {
  418.             if (upb != 0)
  419.                 goto oob;
  420.             upb = -1;
  421.         }
  422.         if (*np)
  423.             goto syntax;
  424.     } else {
  425.         if (subscr > 0)
  426.             if (subscr > upb)
  427.                 lwb = 1, upb = 0;
  428.             else
  429.                 lwb = upb = subscr;
  430.         unDredc(c);
  431.     }
  432.     if (dimen) {
  433.         char *cp = putn(upb - lwb + 1);
  434.  
  435.         addla(cp);
  436.         xfree(cp);
  437.     } else {
  438. eatmod:
  439.         c = DgetC(0);
  440.         if (c == ':') {
  441.             c = DgetC(0), dolmcnt = 1;
  442.             if (c == 'g')
  443.                 c = DgetC(0), dolmcnt = 10000;
  444.             if (!any(c, "htrqx"))
  445.                 error("Bad : mod in $");
  446.             dolmod = c;
  447.             if (c == 'q')
  448.                 dolmcnt = 10000;
  449.         } else
  450.             unDredc(c);
  451.         dolnxt = &vp->vec[lwb - 1];
  452.         dolcnt = upb - lwb + 1;
  453.     }
  454. eatbrac:
  455.     if (sc == '{') {
  456.         c = Dredc();
  457.         if (c != '}')
  458.             goto syntax;
  459.     }
  460. }
  461.  
  462. setDolp(cp)
  463.     register char *cp;
  464. {
  465.     register char *dp;
  466.  
  467.     if (dolmod == 0 || dolmcnt == 0) {
  468.         dolp = cp;
  469.         return;
  470.     }
  471.     dp = domod(cp, dolmod);
  472.     if (dp) {
  473.         dolmcnt--;
  474.         addla(dp);
  475.         xfree(dp);
  476.     } else
  477.         addla(cp);
  478.     dolp = "";
  479. }
  480.  
  481. unDredc(c)
  482.     int c;
  483. {
  484.  
  485.     Dpeekrd = c;
  486. }
  487.  
  488. Dredc()
  489. {
  490.     register int c;
  491.  
  492.     if (c = Dpeekrd) {
  493.         Dpeekrd = 0;
  494.         return (c);
  495.     }
  496.     if (Dcp && (c = *Dcp++))
  497.         return (c);
  498.     if (*Dvp == 0) {
  499.         Dcp = 0;
  500.         return (DEOF);
  501.     }
  502.     Dcp = *Dvp++;
  503.     return (' ');
  504. }
  505.  
  506. Dtest(c)
  507.     register int c;
  508. {
  509.  
  510.     /* Note that c isn't trimmed thus !...:q's aren't lost */
  511.     if (any(c, "$\\'`\""))
  512.         gflag = 1;
  513. }
  514.  
  515. Dtestq(c)
  516.     register int c;
  517. {
  518.  
  519.     if (any(c, "\\'`\""))
  520.         gflag = 1;
  521. }
  522.  
  523. /*
  524.  * Form a shell temporary file (in unit 0) from the words
  525.  * of the shell input up to a line the same as "term".
  526.  * Unit 0 should have been closed before this call.
  527.  */
  528. heredoc(term)
  529.     char *term;
  530. {
  531.     register int c;
  532.     char *Dv[2];
  533.     char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
  534.     int ocnt, lcnt, mcnt;
  535.     register char *lbp, *obp, *mbp;
  536.     char **vp;
  537.     bool quoted;
  538.  
  539.     if (creat(shtemp, 0600) < 0)
  540.         Perror(shtemp);
  541.     close(0);
  542.     if (open(shtemp, 2) < 0) {
  543.         int oerrno = errno;
  544.  
  545.         unlink(shtemp);
  546.         errno = oerrno;
  547.         Perror(shtemp);
  548.     }
  549.     unlink(shtemp);            /* 0 0 inode! */
  550.     Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
  551.     scan(Dv, trim); rscan(Dv, Dtestq); quoted = gflag;
  552.     ocnt = BUFSIZ; obp = obuf;
  553.     for (;;) {
  554.         /*
  555.          * Read up a line
  556.          */
  557.         lbp = lbuf; lcnt = BUFSIZ - 4;
  558.         for (;;) {
  559.             c = readc(1);        /* 1 -> Want EOF returns */
  560.             if (c < 0) {
  561.                 setname(term);
  562.                 bferr("<< terminator not found");
  563.             }
  564.             if (c == '\n')
  565.                 break;
  566.             if (c &= TRIM) {
  567.                 *lbp++ = c;
  568.                 if (--lcnt < 0) {
  569.                     setname("<<");
  570.                     error("Line overflow");
  571.                 } 
  572.             }
  573.         }
  574.         *lbp = 0;
  575.  
  576.         /*
  577.          * Compare to terminator -- before expansion
  578.          */
  579.         if (eq(lbuf, term)) {
  580.             write(0, obuf, BUFSIZ - ocnt);
  581.             lseek(0, 0l, 0);
  582.             return;
  583.         }
  584.  
  585.         /*
  586.          * If term was quoted or -n just pass it on
  587.          */
  588.         if (quoted || noexec) {
  589.             *lbp++ = '\n'; *lbp = 0;
  590.             for (lbp = lbuf; c = *lbp++;) {
  591.                 *obp++ = c;
  592.                 if (--ocnt == 0) {
  593.                     write(0, obuf, BUFSIZ);
  594.                     obp = obuf; ocnt = BUFSIZ;
  595.                 }
  596.             }
  597.             continue;
  598.         }
  599.  
  600.         /*
  601.          * Term wasn't quoted so variable and then command
  602.          * expand the input line
  603.          */
  604.         Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
  605.         for (;;) {
  606.             c = DgetC(DODOL);
  607.             if (c == DEOF)
  608.                 break;
  609.             if ((c &= TRIM) == 0)
  610.                 continue;
  611.             /* \ quotes \ $ ` here */
  612.             if (c =='\\') {
  613.                 c = DgetC(0);
  614.                 if (!any(c, "$\\`"))
  615.                     unDgetC(c | QUOTE), c = '\\';
  616.                 else
  617.                     c |= QUOTE;
  618.             }
  619.             *mbp++ = c;
  620.             if (--mcnt == 0) {
  621.                 setname("<<");
  622.                 bferr("Line overflow");
  623.             }
  624.         }
  625.         *mbp++ = 0;
  626.  
  627.         /*
  628.          * If any ` in line do command substitution
  629.          */
  630.         mbp = mbuf;
  631.         if (any('`', mbp)) {
  632.             /*
  633.              * 1 arg to dobackp causes substitution to be literal.
  634.              * Words are broken only at newlines so that all blanks
  635.              * and tabs are preserved.  Blank lines (null words)
  636.              * are not discarded.
  637.              */
  638.             vp = dobackp(mbuf, 1);
  639.         } else
  640.             /* Setup trivial vector similar to return of dobackp */
  641.             Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
  642.  
  643.         /*
  644.          * Resurrect the words from the command substitution
  645.          * each separated by a newline.  Note that the last
  646.          * newline of a command substitution will have been
  647.          * discarded, but we put a newline after the last word
  648.          * because this represents the newline after the last
  649.          * input line!
  650.          */
  651.         for (; *vp; vp++) {
  652.             for (mbp = *vp; *mbp; mbp++) {
  653.                 *obp++ = *mbp & TRIM;
  654.                 if (--ocnt == 0) {
  655.                     write(0, obuf, BUFSIZ);
  656.                     obp = obuf; ocnt = BUFSIZ;
  657.                 }
  658.             }
  659.             *obp++ = '\n';
  660.             if (--ocnt == 0) {
  661.                 write(0, obuf, BUFSIZ);
  662.                 obp = obuf; ocnt = BUFSIZ;
  663.             }
  664.         }
  665.         if (pargv)
  666.             blkfree(pargv), pargv = 0;
  667.     }
  668. }
  669.