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.lex.c < prev    next >
C/C++ Source or Header  |  1980-02-17  |  20KB  |  1,241 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 lexical routines read input and form lists of words.
  10.  * There is some involved processing here, because of the complications
  11.  * of input buffering, and especially because of history substitution.
  12.  */
  13.  
  14. char    *word();
  15.  
  16. /*
  17.  * Peekc is a peek characer for getC, peekread for readc.
  18.  * There is a subtlety here in many places... history routines
  19.  * will read ahead and then insert stuff into the input stream.
  20.  * If they push back a character then they must push it behind
  21.  * the text substituted by the history substitution.  On the other
  22.  * hand in several places we need 2 peek characters.  To make this
  23.  * all work, the history routines read with getC, and make use both
  24.  * of ungetC and unreadc.  The key observation is that the state
  25.  * of getC at the call of a history reference is such that calls
  26.  * to getC from the history routines will always yield calls of
  27.  * readc, unless this peeking is involved.  That is to say that during
  28.  * getexcl the variables lap, exclp, and exclnxt are all zero.
  29.  *
  30.  * Getdol invokes history substitution, hence the extra peek, peekd,
  31.  * which it can ungetD to be before history substitutions.
  32.  */
  33. char    peekc, peekd;
  34. char    peekread;
  35.  
  36. char    *exclp;            /* (Tail of) current word from ! subst */
  37. struct    wordent *exclnxt;    /* The rest of the ! subst words */
  38. int    exclc;            /* Count of remainig words in ! subst */
  39. char    *alvecp;        /* "Globp" for alias resubstitution */
  40.  
  41. /*
  42.  * Lex returns to its caller not only a wordlist (as a "var" parameter)
  43.  * but also whether a history substitution occurred.  This is used in
  44.  * the main (process) routine to determine whether to echo, and also
  45.  * when called by the alias routine to determine whether to keep the
  46.  * argument list.
  47.  */
  48. bool    hadhist;
  49.  
  50. #define    ungetC(c)    peekc = c
  51. #define    ungetD(c)    peekd = c
  52.  
  53. lex(hp)
  54.     register struct wordent *hp;
  55. {
  56.     register struct wordent *wdp;
  57.     int c;
  58.  
  59.     lineloc = btell();
  60.     hp->next = hp->prev = hp;
  61.     hp->word = "";
  62.     alvecp = 0, hadhist = 0;
  63.     do
  64.         c = readc(0);
  65.     while (c == ' ' || c == '\t');
  66.     if (c == '^' && intty)
  67.         /* ^lef^rit    from tty is short !:s^lef^rit */
  68.         getexcl(c);
  69.     else
  70.         unreadc(c);
  71.     wdp = hp;
  72.     /*
  73.      * The following loop is written so that the links needed
  74.      * by freelex will be ready and rarin to go even if it is
  75.      * interrupted.
  76.      */
  77.     do {
  78.         register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
  79.  
  80.         new->prev = wdp;
  81.         new->next = hp;
  82.         wdp->next = new;
  83.         wdp = new;
  84.         wdp->word = word();
  85.     } while (wdp->word[0] != '\n');
  86.     hp->prev = wdp;
  87.     return (hadhist);
  88. }
  89.  
  90. prlex(sp0)
  91.     struct wordent *sp0;
  92. {
  93.     register struct wordent *sp = sp0->next;
  94.  
  95.     for (;;) {
  96.         printf("%s", sp->word);
  97.         sp = sp->next;
  98.         if (sp == sp0)
  99.             break;
  100.         printf(" ");
  101.     }
  102. }
  103.  
  104. copylex(hp, fp)
  105.     register struct wordent *hp;
  106.     struct wordent *fp;
  107. {
  108.     register struct wordent *wdp;
  109.  
  110.     wdp = hp;
  111.     fp = fp->next;
  112.     do {
  113.         register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
  114.  
  115.         new->prev = wdp;
  116.         new->next = hp;
  117.         wdp->next = new;
  118.         wdp = new;
  119.         wdp->word = savestr(fp->word);
  120.         fp = fp->next;
  121.     } while (wdp->word[0] != '\n');
  122.     hp->prev = wdp;
  123. }
  124.  
  125. freelex(vp)
  126.     register struct wordent *vp;
  127. {
  128.     register struct wordent *fp;
  129.  
  130.     while (vp->next != vp) {
  131.         fp = vp->next;
  132.         vp->next = fp->next;
  133.         xfree(fp->word);
  134.         xfree(fp);
  135.     }
  136.     vp->prev = vp;
  137. }
  138.  
  139. char    *WORDMETA =    "# '`\"\t;&<>()|\n";
  140.  
  141. char *
  142. word()
  143. {
  144.     register char c, c1;
  145.     register char *wp;
  146.     char wbuf[BUFSIZ];
  147.     register bool dolflg;
  148.     register int i;
  149.  
  150.     wp = wbuf;
  151.     i = BUFSIZ - 4;
  152. loop:
  153.     c = getC(DOALL);
  154.     switch (c) {
  155.  
  156.     case ' ':
  157.     case '\t':
  158.         goto loop;
  159.  
  160.     case '`':
  161.     case '\'':
  162.     case '"':
  163.         *wp++ = c, --i, c1 = c;
  164.         dolflg = c == '"' ? DOALL : DOEXCL;
  165.         for (;;) {
  166.             c = getC(dolflg);
  167.             if (c == c1)
  168.                 break;
  169.             if (c == '\n') {
  170.                 seterrc("Unmatched ", c1);
  171.                 ungetC(c);
  172.                 goto ret;
  173.             }
  174.             if (c == '\\') {
  175.                 c = getC(0);
  176.                 if (c == '!')
  177.                     c |= QUOTE;
  178.                 else {
  179.                     if (c == '\n' && c1 != '`')
  180.                         c |= QUOTE;
  181.                     ungetC(c), c = '\\';
  182.                 }
  183.             }
  184.             if (--i <= 0)
  185.                 goto toochars;
  186.             *wp++ = c;
  187.         }
  188.         *wp++ = c, --i;
  189.         goto pack;
  190.  
  191.     case '&':
  192.     case '|':
  193.     case '<':
  194.     case '>':
  195.         *wp++ = c;
  196.         c1 = getC(DOALL);
  197.         if (c1 == c)
  198.             *wp++ = c1;
  199.         else
  200.             ungetC(c1);
  201.         goto ret;
  202.  
  203.     case '#':
  204.         if (intty)
  205.             break;
  206.         if (wp != wbuf) {
  207.             ungetC(c);
  208.             goto ret;
  209.         }
  210.         c = 0;
  211.         do {
  212.             c1 = c;
  213.             c = getC(0);
  214.         } while (c != '\n');
  215.         if (c1 == '\\')
  216.             goto loop;
  217.         /* fall into ... */
  218.  
  219.     case ';':
  220.     case '(':
  221.     case ')':
  222.     case '\n':
  223.         *wp++ = c;
  224.         goto ret;
  225.  
  226. casebksl:
  227.     case '\\':
  228.         c = getC(0);
  229.         if (c == '\n') {
  230.             if (onelflg == 1)
  231.                 onelflg = 2;
  232.             goto loop;
  233.         }
  234.         if (c != '!')
  235.             *wp++ = '\\', --i;
  236.         c |= QUOTE;
  237.         break;
  238.     }
  239.     ungetC(c);
  240. pack:
  241.     for (;;) {
  242.         c = getC(DOALL);
  243.         if (c == '\\') {
  244.             c = getC(0);
  245.             if (c == '\n') {
  246.                 if (onelflg == 1)
  247.                     onelflg = 2;
  248.                 goto ret;
  249.             }
  250.             if (c != '!')
  251.                 *wp++ = '\\', --i;
  252.             c |= QUOTE;
  253.         }
  254.         if (any(c, WORDMETA + intty)) {
  255.             ungetC(c);
  256.             if (any(c, "\"'`"))
  257.                 goto loop;
  258.             goto ret;
  259.         }
  260.         if (--i <= 0)
  261.             goto toochars;
  262.         *wp++ = c;
  263.     }
  264. toochars:
  265.     seterr("Word too long");
  266.     wp = &wbuf[1];
  267. ret:
  268.     *wp = 0;
  269.     return (savestr(wbuf));
  270. }
  271.  
  272. getC(flag)
  273.     register int flag;
  274. {
  275.     register char c;
  276.  
  277. top:
  278.     if (c = peekc) {
  279.         peekc = 0;
  280.         return (c);
  281.     }
  282.     if (lap) {
  283.         c = *lap++;
  284.         if (c == 0) {
  285.             lap = 0;
  286.             goto top;
  287.         }
  288.         if (any(c, WORDMETA + intty))
  289.             c |= QUOTE;
  290.         return (c);
  291.     }
  292.     if (c = peekd) {
  293.         peekd = 0;
  294.         return (c);
  295.     }
  296.     if (exclp) {
  297.         if (c = *exclp++)
  298.             return (c);
  299.         if (exclnxt && --exclc >= 0) {
  300.             exclnxt = exclnxt->next;
  301.             setexclp(exclnxt->word);
  302.             return (' ');
  303.         }
  304.         exclp = 0;
  305.         exclnxt = 0;
  306.     }
  307.     if (exclnxt) {
  308.         exclnxt = exclnxt->next;
  309.         if (--exclc < 0)
  310.             exclnxt = 0;
  311.         else
  312.             setexclp(exclnxt->word);
  313.         goto top;
  314.     }
  315.     c = readc(0);
  316.     if (c == '$' && (flag & DODOL)) {
  317.         getdol();
  318.         goto top;
  319.     }
  320.     if (c == '!' && (flag & DOEXCL)) {
  321.         getexcl(0);
  322.         goto top;
  323.     }
  324.     return (c);
  325. }
  326.  
  327. getdol()
  328. {
  329.     register char *np;
  330.     char name[40];
  331.     register int c;
  332.     int sc;
  333.     bool special = 0;
  334.  
  335.     np = name, *np++ = '$';
  336.     c = sc = getC(DOEXCL);
  337.     if (any(c, "\t \n")) {
  338.         ungetD(c);
  339.         ungetC('$' | QUOTE);
  340.         return;
  341.     }
  342.     if (c == '{')
  343.         *np++ = c, c = getC(DOEXCL);
  344.     if (c == '#' || c == '?')
  345.         special++, *np++ = c, c = getC(DOEXCL);
  346.     *np++ = c;
  347.     switch (c) {
  348.     
  349.     case '$':
  350.         if (special)
  351.             goto vsyn;
  352.         goto ret;
  353.  
  354.     case '\n':
  355.         ungetD(c);
  356.         np--;
  357.         goto vsyn;
  358.  
  359.     case '*':
  360.         if (special)
  361.             goto vsyn;
  362.         goto ret;
  363.  
  364.     default:
  365.         if (digit(c)) {
  366. /*
  367.  * let $?0 pass for now
  368.             if (special)
  369.                 goto vsyn;
  370. */
  371.             while (digit(c = getC(DOEXCL))) {
  372.                 if (np < &name[sizeof name / 2])
  373.                     *np++ = c;
  374.             }
  375.         } else if (letter(c))
  376.             while (letter(c = getC(DOEXCL))) {
  377.                 if (np < &name[sizeof name / 2])
  378.                     *np++ = c;
  379.             }
  380.         else
  381.             goto vsyn;
  382.     }
  383.     if (c == '[') {
  384.         *np++ = c;
  385.         do {
  386.             c = getC(DOEXCL);
  387.             if (c == '\n') {
  388.                 ungetD(c);
  389.                 np--;
  390.                 goto vsyn;
  391.             }
  392.             if (np >= &name[sizeof name - 8])
  393.                 goto vsyn;
  394.             *np++ = c;
  395.         } while (c != ']');
  396.         c = getC(DOEXCL);
  397.     }
  398.     if (c == ':') {
  399.         *np++ = c, c = getC(DOEXCL);
  400.         if (c == 'g')
  401.             *np++ = c, c = getC(DOEXCL);
  402.         *np++ = c;
  403.         if (!any(c, "htrqx"))
  404.             goto vsyn;
  405.     } else
  406.         ungetD(c);
  407.     if (sc == '{') {
  408.         c = getC(DOEXCL);
  409.         if (c != '}') {
  410.             ungetC(c);
  411.             goto vsyn;
  412.         }
  413.         *np++ = c;
  414.     }
  415. ret:
  416.     *np = 0;
  417.     addla(name);
  418.     return;
  419.  
  420. vsyn:
  421.     seterr("Variable syntax");
  422.     goto ret;
  423. }
  424.  
  425. addla(cp)
  426.     char *cp;
  427. {
  428.     char buf[BUFSIZ];
  429.  
  430.     if (lap != 0 && strlen(cp) + strlen(lap) >= BUFSIZ - 4) {
  431.         seterr("Expansion buf ovflo");
  432.         return;
  433.     }
  434.     if (lap)
  435.         strcpy(buf, lap);
  436.     strcpy(labuf, cp);
  437.     if (lap)
  438.         strcat(labuf, buf);
  439.     lap = labuf;
  440. }
  441.  
  442. char    lhsb[32];
  443. char    slhs[32];
  444. char    rhsb[64];
  445. int    quesarg;
  446.  
  447. getexcl(sc)
  448.     char sc;
  449. {
  450.     register struct wordent *hp, *ip;
  451.     int left, right, dol;
  452.     register int c;
  453.  
  454.     if (sc == 0) {
  455.         sc = getC(0);
  456.         if (sc != '{') {
  457.             ungetC(sc);
  458.             sc = 0;
  459.         }
  460.     }
  461.     quesarg = -1;
  462.     lastev = eventno;
  463.     hp = gethent(sc);
  464.     if (hp == 0)
  465.         return;
  466.     hadhist = 1;
  467.     dol = 0;
  468.     if (hp == alhistp)
  469.         for (ip = hp->next->next; ip != alhistt; ip = ip->next)
  470.             dol++;
  471.     else
  472.         for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
  473.             dol++;
  474.     left = 0, right = dol;
  475.     if (sc == '^') {
  476.         ungetC('s'), unreadc('^'), c = ':';
  477.         goto subst;
  478.     }
  479.     c = getC(0);
  480.     if (!any(c, ":^$*-%"))
  481.         goto subst;
  482.     left = right = -1;
  483.     if (c == ':') {
  484.         c = getC(0);
  485.         unreadc(c);
  486.         if (letter(c) || c == '&') {
  487.             c = ':';
  488.             left = 0, right = dol;
  489.             goto subst;
  490.         }
  491.     } else
  492.         ungetC(c);
  493.     if (!getsel(&left, &right, dol))
  494.         return;
  495.     c = getC(0);
  496.     if (c == '*')
  497.         ungetC(c), c = '-';
  498.     if (c == '-') {
  499.         if (!getsel(&left, &right, dol))
  500.             return;
  501.         c = getC(0);
  502.     }
  503. subst:
  504.     exclc = right - left + 1;
  505.     while (--left >= 0)
  506.         hp = hp->next;
  507.     if (sc == '^' || c == ':') {
  508.         do {
  509.             hp = getsub(hp);
  510.             c = getC(0);
  511.         } while (c == ':');
  512.     }
  513.     unreadc(c);
  514.     if (sc == '{') {
  515.         c = getC(0);
  516.         if (c != '}')
  517.             seterr("Bad ! form");
  518.     }
  519.     exclnxt = hp;
  520. }
  521.  
  522. struct wordent *
  523. getsub(en)
  524.     struct wordent *en;
  525. {
  526.     register char *cp;
  527.     int delim;
  528.     register int c;
  529.     int sc;
  530.     bool global = 0;
  531.     char orhsb[sizeof rhsb];
  532.  
  533.     exclnxt = 0;
  534.     sc = c = getC(0);
  535.     if (c == 'g')
  536.         global++, c = getC(0);
  537.     switch (c) {
  538.  
  539.     case 'p':
  540.         justpr++;
  541.         goto ret;
  542.  
  543.     case 'x':
  544.     case 'q':
  545.         global++;
  546.         /* fall into ... */
  547.  
  548.     case 'h':
  549.     case 'r':
  550.     case 't':
  551.         break;
  552.  
  553.     case '&':
  554.         if (slhs[0] == 0) {
  555.             seterr("No prev sub");
  556.             goto ret;
  557.         }
  558.         strcpy(lhsb, slhs);
  559.         break;
  560.  
  561. /*
  562.     case '~':
  563.         if (lhsb[0] == 0)
  564.             goto badlhs;
  565.         break;
  566. */
  567.  
  568.     case 's':
  569.         delim = getC(0);
  570.         if (letter(delim) || digit(delim) || any(delim, " \t\n")) {
  571.             unreadc(delim);
  572. bads:
  573.             lhsb[0] = 0;
  574.             seterr("Bad substitute");
  575.             goto ret;
  576.         }
  577.         cp = lhsb;
  578.         for (;;) {
  579.             c = getC(0);
  580.             if (c == '\n') {
  581.                 unreadc(c);
  582.                 goto bads;
  583.             }
  584.             if (c == delim)
  585.                 break;
  586.             if (cp > &lhsb[sizeof lhsb - 2])
  587.                 goto bads;
  588.             if (c == '\\') {
  589.                 c = getC(0);
  590.                 if (c != delim && c != '\\')
  591.                     *cp++ = '\\';
  592.             }
  593.             *cp++ = c;
  594.         }
  595.         if (cp != lhsb)
  596.             *cp++ = 0;
  597.         else if (lhsb[0] == 0) {
  598. badlhs:
  599.             seterr("No prev lhs");
  600.             goto ret;
  601.         }
  602.         cp = rhsb;
  603.         strcpy(orhsb, cp);
  604.         for (;;) {
  605.             c = getC(0);
  606.             if (c == '\n') {
  607.                 unreadc(c);
  608.                 break;
  609.             }
  610.             if (c == delim)
  611.                 break;
  612. /*
  613.             if (c == '~') {
  614.                 if (&cp[strlen(orhsb)] > &rhsb[sizeof rhsb - 2])
  615.                     goto toorhs;
  616.                 cp = strend(strcpy(cp, orhsb));
  617.                 continue;
  618.             }
  619. */
  620.             if (cp > &rhsb[sizeof rhsb - 2]) {
  621. toorhs:
  622.                 seterr("Rhs too long");
  623.                 goto ret;
  624.             }
  625.             if (c == '\\') {
  626.                 c = getC(0);
  627.                 if (c != delim /* && c != '~' */)
  628.                     *cp++ = '\\';
  629.             }
  630.             *cp++ = c;
  631.         }
  632.         *cp++ = 0;
  633.         break;
  634.  
  635.     default:
  636.         if (c == '\n')
  637.             unreadc(c);
  638.         seterrc("Bad ! modifier: ", c);
  639.         goto ret;
  640.     }
  641.     strcpy(slhs, lhsb);
  642.     if (exclc)
  643.         en = dosub(sc, en, global);
  644. ret:
  645.     return (en);
  646. }
  647.  
  648. struct wordent *
  649. dosub(sc, en, global)
  650.     int sc;
  651.     struct wordent *en;
  652.     bool global;
  653. {
  654.     struct wordent lex;
  655.     bool didsub = 0;
  656.     struct wordent *hp = &lex;
  657.     register struct wordent *wdp;
  658.     register int i = exclc;
  659.  
  660.     wdp = hp;
  661.     while (--i >= 0) {
  662.         register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
  663.  
  664.         new->prev = wdp;
  665.         new->next = hp;
  666.         wdp->next = new;
  667.         wdp = new;
  668.         en = en->next;
  669.         wdp->word = global || didsub == 0 ?
  670.             subword(en->word, sc, &didsub) : savestr(en->word);
  671.     }
  672.     if (didsub == 0)
  673.         seterr("Modifier failed");
  674.     hp->prev = wdp;
  675.     return (&enthist(-1000, &lex, 0)->Hlex);
  676. }
  677.  
  678. char *
  679. subword(cp, type, adid)
  680.     char *cp;
  681.     int type;
  682.     bool *adid;
  683. {
  684.     char wbuf[BUFSIZ];
  685.     register char *wp, *mp, *np;
  686.     register int i;
  687.  
  688.     switch (type) {
  689.  
  690.     case 'r':
  691.     case 'h':
  692.     case 't':
  693.     case 'q':
  694.     case 'x':
  695.         wp = domod(cp, type);
  696.         if (wp == 0)
  697.             return (savestr(cp));
  698.         *adid = 1;
  699.         return (wp);
  700.  
  701.     default:
  702.         wp = wbuf;
  703.         i = BUFSIZ - 4;
  704.         for (mp = cp; *mp; mp++)
  705.             if (matchs(mp, lhsb)) {
  706.                 for (np = cp; np < mp;)
  707.                     *wp++ = *np++, --i;
  708.                 for (np = rhsb; *np; np++) switch (*np) {
  709.  
  710.                 case '\\':
  711.                     if (np[1] == '&')
  712.                         np++;
  713.                     /* fall into ... */
  714.  
  715.                 default:
  716.                     if (--i < 0)
  717.                         goto ovflo;
  718.                     *wp++ = *np;
  719.                     continue;
  720.  
  721.                 case '&':
  722.                     i -= strlen(lhsb);
  723.                     if (i < 0)
  724.                         goto ovflo;
  725.                     *wp = 0;
  726.                     strcat(wp, lhsb);
  727.                     wp = strend(wp);
  728.                     continue;
  729.                 }
  730.                 mp += strlen(lhsb);
  731.                 i -= strlen(mp);
  732.                 if (i < 0) {
  733. ovflo:
  734.                     seterr("Subst buf ovflo");
  735.                     return ("");
  736.                 }
  737.                 *wp = 0;
  738.                 strcat(wp, mp);
  739.                 *adid = 1;
  740.                 return (savestr(wbuf));
  741.             }
  742.         return (savestr(cp));
  743.     }
  744. }
  745.  
  746. char *
  747. domod(cp, type)
  748.     char *cp;
  749.     int type;
  750. {
  751.     register char *wp, *xp;
  752.     register int c;
  753.  
  754.     switch (type) {
  755.  
  756.     case 'x':
  757.     case 'q':
  758.         wp = savestr(cp);
  759.         for (xp = wp; c = *xp; xp++)
  760.             if ((c != ' ' && c != '\t') || type == 'q')
  761.                 *xp |= QUOTE;
  762.         return (wp);
  763.  
  764.     case 'h':
  765.     case 't':
  766.         if (!any('/', cp))
  767.             return (0);
  768.         wp = strend(cp);
  769.         while (*--wp != '/')
  770.             continue;
  771.         if (type == 'h')
  772. take:
  773.             xp = savestr(cp), xp[wp - cp] = 0;
  774.         else
  775.             xp = savestr(wp + 1);
  776.         return (xp);
  777.  
  778.     case 'r':
  779.         wp = strend(cp);
  780.         for (wp--; wp >= cp && *wp != '.'; wp--)
  781.             if (*wp == '/')
  782.                 return (0);
  783.         if (wp < cp)
  784.             return (0);
  785.         goto take;
  786.     }
  787.     return (0);
  788. }
  789.  
  790. matchs(str, pat)
  791.     register char *str, *pat;
  792. {
  793.  
  794.     while (*str && *pat && *str == *pat)
  795.         str++, pat++;
  796.     return (*pat == 0);
  797. }
  798.  
  799. getsel(al, ar, dol)
  800.     register int *al, *ar;
  801.     int dol;
  802. {
  803.     register int c = getC(0);
  804.     register int i;
  805.     bool first = *al < 0;
  806.  
  807.     switch (c) {
  808.  
  809.     case '%':
  810.         if (quesarg == -1)
  811.             goto bad;
  812.         if (*al < 0)
  813.             *al = quesarg;
  814.         *ar = quesarg;
  815.         break;
  816.  
  817.     case '-':
  818.         if (*al < 0) {
  819.             *al = 0;
  820.             *ar = dol - 1;
  821.             unreadc(c);
  822.         }
  823.         return (1);
  824.  
  825.     case '^':
  826.         if (*al < 0)
  827.             *al = 1;
  828.         *ar = 1;
  829.         break;
  830.  
  831.     case '$':
  832.         if (*al < 0)
  833.             *al = dol;
  834.         *ar = dol;
  835.         break;
  836.  
  837.     case '*':
  838.         if (*al < 0)
  839.             *al = 1;
  840.         *ar = dol;
  841.         if (*ar < *al) {
  842.             *ar = 0;
  843.             *al = 1;
  844.             return (1);
  845.         }
  846.         break;
  847.  
  848.     default:
  849.         if (digit(c)) {
  850.             i = 0;
  851.             while (digit(c)) {
  852.                 i = i * 10 + c - '0';
  853.                 c = getC(0);
  854.             }
  855.             if (i < 0)
  856.                 i = dol + 1;
  857.             if (*al < 0)
  858.                 *al = i;
  859.             *ar = i;
  860.         } else
  861.             if (*al < 0)
  862.                 *al = 0, *ar = dol;
  863.             else
  864.                 *ar = dol - 1;
  865.         unreadc(c);
  866.         break;
  867.     }
  868.     if (first) {
  869.         c = getC(0);
  870.         unreadc(c);
  871.         if (any(c, "-$*"))
  872.             return (1);
  873.     }
  874.     if (*al > *ar || *ar > dol) {
  875. bad:
  876.         seterr("Bad ! arg selector");
  877.         return (0);
  878.     }
  879.     return (1);
  880. }
  881.  
  882. struct wordent *
  883. gethent(sc)
  884.     int sc;
  885. {
  886.     register struct Hist *hp;
  887.     register char *np;
  888.     register int c;
  889.     int event;
  890.     bool back = 0;
  891.  
  892.     c = sc == '^' ? '!' : getC(0);
  893.     switch (c) {
  894.  
  895.     case ':':
  896.     case '^':
  897.     case '$':
  898.     case '*':
  899.     case '%':
  900.         ungetC(c);
  901.         if (lastev == eventno && alhistp)
  902.             return (alhistp);
  903.         event = lastev;
  904.         break;
  905.  
  906.     case '!':
  907.         event = eventno;
  908.         break;
  909.  
  910.     case '-':
  911.         back = 1;
  912.         c = getC(0);
  913.         goto number;
  914.  
  915.     default:
  916.         if (any(c, "(=")) {
  917.             unreadc(c);
  918.             ungetC('!');
  919.             return (0);
  920.         }
  921.         if (digit(c))
  922.             goto number;
  923.         np = lhsb;
  924.         while (!any(c, ": \t\\\n}")) {
  925.             if (np < &lhsb[sizeof lhsb - 2])
  926.                 *np++ = c;
  927.             c = getC(0);
  928.         }
  929.         unreadc(c);
  930.         if (np == lhsb) {
  931.             ungetC('!');
  932.             return (0);
  933.         }
  934.         *np++ = 0;
  935.         hp = findev(lhsb, 0);
  936.         if (hp)
  937.             lastev = hp->Hnum;
  938.         return (&hp->Hlex);
  939.  
  940.     case '?':
  941.         np = lhsb;
  942.         for (;;) {
  943.             c = getC(0);
  944.             if (c == '\n') {
  945.                 unreadc(c);
  946.                 break;
  947.             }
  948.             if (c == '?')
  949.                 break;
  950.             if (np < &lhsb[sizeof lhsb - 2])
  951.                 *np++ = c;
  952.         }
  953.         if (np == lhsb) {
  954.             if (lhsb[0] == 0) {
  955.                 seterr("No prev search");
  956.                 return (0);
  957.             }
  958.         } else
  959.             *np++ = 0;
  960.         hp = findev(lhsb, 1);
  961.         if (hp)
  962.             lastev = hp->Hnum;
  963.         return (&hp->Hlex);
  964.  
  965.     number:
  966.         event = 0;
  967.         while (digit(c)) {
  968.             event = event * 10 + c - '0';
  969.             c = getC(0);
  970.         }
  971.         if (back)
  972.             event = eventno + (alhistp == 0) - (event ? event : 0);
  973.         unreadc(c);
  974.         break;
  975.     }
  976.     for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
  977.         if (hp->Hnum == event) {
  978.             hp->Href = eventno;
  979.             lastev = hp->Hnum;
  980.             return (&hp->Hlex);
  981.         }
  982.     np = putn(event);
  983.     noev(np);
  984.     return (0);
  985. }
  986.  
  987. struct Hist *
  988. findev(cp, anyarg)
  989.     char *cp;
  990.     bool anyarg;
  991. {
  992.     register struct Hist *hp;
  993.  
  994.     for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
  995.         if (matchev(hp, cp, anyarg))
  996.             return (hp);
  997.     noev(cp);
  998.     return (0);
  999. }
  1000.  
  1001. noev(cp)
  1002.     char *cp;
  1003. {
  1004.  
  1005.     seterr2(cp, ": Event not found");
  1006. }
  1007.  
  1008. matchev(hp, cp, anyarg)
  1009.     register struct Hist *hp;
  1010.     char *cp;
  1011.     bool anyarg;
  1012. {
  1013.     register char *dp;
  1014.     struct wordent *lp = &hp->Hlex;
  1015.     int argno = 0;
  1016.     
  1017.     for (;;) {
  1018.         lp = lp->next;
  1019.         if (lp->word[0] == '\n')
  1020.             return (0);
  1021.         for (dp = lp->word; *dp; dp++) {
  1022.             if (matchs(dp, cp)) {
  1023.                 if (anyarg)
  1024.                     quesarg = argno;
  1025.                 return (1);
  1026.             }
  1027.             if (!anyarg)
  1028.                 return (0);
  1029.         }
  1030.         argno++;
  1031.     }
  1032. }
  1033.  
  1034. setexclp(cp)
  1035.     register char *cp;
  1036. {
  1037.  
  1038.     if (cp[0] == '\n')
  1039.         return;
  1040.     exclp = cp;
  1041. }
  1042.  
  1043. unreadc(c)
  1044.     char c;
  1045. {
  1046.  
  1047.     peekread = c;
  1048. }
  1049.  
  1050. readc(wanteof)
  1051.     bool wanteof;
  1052. {
  1053.     register int c;
  1054.  
  1055.     if (c = peekread) {
  1056.         peekread = 0;
  1057.         return (c);
  1058.     }
  1059. top:
  1060.     if (alvecp) {
  1061.         if (c = *alvecp++)
  1062.             return (c);
  1063.         if (*alvec) {
  1064.             alvecp = *alvec++;
  1065.             return (' ');
  1066.         }
  1067.     }
  1068.     if (alvec) {
  1069.         if (alvecp = *alvec) {
  1070.             alvec++;
  1071.             goto top;
  1072.         }
  1073.         /* Infinite source! */
  1074.         return ('\n');
  1075.     }
  1076.     do {
  1077.         if (arginp == (char *) 1 || onelflg == 1) {
  1078.             if (wanteof)
  1079.                 return (-1);
  1080.             exitstat();
  1081.         }
  1082.         if (arginp) {
  1083.             if ((c = *arginp++) == 0) {
  1084.                 arginp = (char *) 1;
  1085.                 return ('\n');
  1086.             }
  1087.             return (c);
  1088.         }
  1089.         c = bgetc();
  1090.         if (c < 0) {
  1091. #include <sgtty.h>
  1092.             struct sgttyb tty;
  1093.  
  1094.             if (wanteof)
  1095.                 return (-1);
  1096.             /* was isatty but raw with ignoreeof yields problems */
  1097.             if (adrof("ignoreeof") && gtty(SHIN, &tty)==0 && (tty.sg_flags & RAW) == 0) {
  1098.                 if (loginsh)
  1099.                     printf("\nUse \"logout\" to logout.\n");
  1100.                 else
  1101.                     printf("\nUse \"exit\" to leave csh.\n");
  1102.                 reset();
  1103.             }
  1104.             doneinp = 1;
  1105.             reset();
  1106.         }
  1107.         if (c == '\n' && onelflg)
  1108.             onelflg--;
  1109.     } while (c == 0);
  1110.     return (c);
  1111. }
  1112.  
  1113. bgetc()
  1114. {
  1115.     register int buf, off, c;
  1116.  
  1117. #ifdef TELL
  1118.     if (cantell) {
  1119.         if (fseekp < fbobp || fseekp > feobp) {
  1120.             fbobp = feobp = fseekp;
  1121.             lseek(SHIN, fseekp, 0);
  1122.         }
  1123.         if (fseekp == feobp) {
  1124.             fbobp = feobp;
  1125.             do
  1126.                 c = read(SHIN, fbuf[0], BUFSIZ);
  1127.             while (c < 0 && errno == EINTR);
  1128.             if (c <= 0)
  1129.                 return (-1);
  1130.             feobp += c;
  1131.         }
  1132.         c = fbuf[0][fseekp - fbobp];
  1133.         fseekp++;
  1134.         return (c);
  1135.     }
  1136. #endif
  1137. again:
  1138.     buf = (int) fseekp / BUFSIZ;
  1139.     if (buf >= fblocks) {
  1140.         register char **nfbuf = (char **) calloc(fblocks+2, sizeof (char **));
  1141.  
  1142.         if (fbuf) {
  1143.             blkcpy(nfbuf, fbuf);
  1144.             xfree(fbuf);
  1145.         }
  1146.         fbuf = nfbuf;
  1147.         fbuf[fblocks] = calloc(BUFSIZ, sizeof (char));
  1148.         fblocks++;
  1149.         goto again;
  1150.     }
  1151.     if (fseekp >= feobp) {
  1152.         buf = (int) feobp / BUFSIZ;
  1153.         off = (int) feobp % BUFSIZ;
  1154.         do
  1155.             c = read(SHIN, fbuf[buf] + off, BUFSIZ - off);
  1156.         while (c < 0 && errno == EINTR);
  1157.         if (c <= 0)
  1158.             return (-1);
  1159.         feobp += c;
  1160.         goto again;
  1161.     }
  1162.     c = fbuf[buf][(int) fseekp % BUFSIZ];
  1163.     fseekp++;
  1164.     return (c);
  1165. }
  1166.  
  1167. bfree()
  1168. {
  1169.     register int sb, i;
  1170.  
  1171. #ifdef TELL
  1172.     if (cantell)
  1173.         return;
  1174. #endif
  1175.     if (whyles)
  1176.         return;
  1177.     sb = (int) (fseekp - 1) / BUFSIZ;
  1178.     if (sb > 0) {
  1179.         for (i = 0; i < sb; i++)
  1180.             xfree(fbuf[i]);
  1181.         blkcpy(fbuf, &fbuf[sb]);
  1182.         fseekp -= BUFSIZ * sb;
  1183.         feobp -= BUFSIZ * sb;
  1184.         fblocks -= sb;
  1185.     }
  1186. }
  1187.  
  1188. bseek(l)
  1189.     long l;
  1190. {
  1191.     register struct whyle *wp;
  1192.  
  1193.     fseekp = l;
  1194. #ifdef TELL
  1195.     if (!cantell) {
  1196. #endif
  1197.         if (!whyles)
  1198.             return;
  1199.         for (wp = whyles; wp->w_next; wp = wp->w_next)
  1200.             continue;
  1201.         if (wp->w_start > l)
  1202.             l = wp->w_start;
  1203. #ifdef TELL
  1204.     }
  1205. #endif
  1206. }
  1207.  
  1208. /* any similarity to bell telephone is purely accidental */
  1209. long
  1210. btell()
  1211. {
  1212.  
  1213.     return (fseekp);
  1214. }
  1215.  
  1216. btoeof()
  1217. {
  1218.  
  1219.     lseek(SHIN, 0l, 2);
  1220.     fseekp = feobp;
  1221.     wfree();
  1222.     bfree();
  1223. }
  1224.  
  1225. #ifdef TELL
  1226. settell()
  1227. {
  1228.  
  1229.     cantell = 0;
  1230.     if (arginp || onelflg || intty)
  1231.         return;
  1232.     if (lseek(SHIN, 0l, 1) < 0 || errno == ESPIPE)
  1233.         return;
  1234.     fbuf = (char **) calloc(2, sizeof (char **));
  1235.     fblocks = 1;
  1236.     fbuf[0] = calloc(BUFSIZ, sizeof (char));
  1237.     fseekp = fbobp = feobp = tell(SHIN);
  1238.     cantell = 1;
  1239. }
  1240. #endif
  1241.