home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / csh / lex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-06  |  30.2 KB  |  1,640 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[] = "@(#)lex.c    5.26 (Berkeley) 11/6/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/types.h>
  39. #include <sys/ioctl.h>
  40. #include <termios.h>
  41. #include <errno.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45. #if __STDC__
  46. # include <stdarg.h>
  47. #else
  48. # include <varargs.h>
  49. #endif
  50.  
  51. #include "csh.h"
  52. #include "extern.h"
  53.  
  54. /*
  55.  * These lexical routines read input and form lists of words.
  56.  * There is some involved processing here, because of the complications
  57.  * of input buffering, and especially because of history substitution.
  58.  */
  59.  
  60. static Char    *word __P((void));
  61. static int     getC1 __P((int));
  62. static void     getdol __P((void));
  63. static void     getexcl __P((int));
  64. static struct Hist
  65.         *findev __P((Char *, bool));
  66. static void     setexclp __P((Char *));
  67. static int     bgetc __P((void));
  68. static void     bfree __P((void));
  69. static struct wordent
  70.         *gethent __P((int));
  71. static int     matchs __P((Char *, Char *));
  72. static int     getsel __P((int *, int *, int));
  73. static struct wordent
  74.         *getsub __P((struct wordent *));
  75. static Char    *subword __P((Char *, int, bool *));
  76. static struct wordent
  77.         *dosub __P((int, struct wordent *, bool));
  78.  
  79. /*
  80.  * Peekc is a peek character for getC, peekread for readc.
  81.  * There is a subtlety here in many places... history routines
  82.  * will read ahead and then insert stuff into the input stream.
  83.  * If they push back a character then they must push it behind
  84.  * the text substituted by the history substitution.  On the other
  85.  * hand in several places we need 2 peek characters.  To make this
  86.  * all work, the history routines read with getC, and make use both
  87.  * of ungetC and unreadc.  The key observation is that the state
  88.  * of getC at the call of a history reference is such that calls
  89.  * to getC from the history routines will always yield calls of
  90.  * readc, unless this peeking is involved.  That is to say that during
  91.  * getexcl the variables lap, exclp, and exclnxt are all zero.
  92.  *
  93.  * Getdol invokes history substitution, hence the extra peek, peekd,
  94.  * which it can ungetD to be before history substitutions.
  95.  */
  96. static Char peekc = 0, peekd = 0;
  97. static Char peekread = 0;
  98.  
  99. /* (Tail of) current word from ! subst */
  100. static Char *exclp = NULL;
  101.  
  102. /* The rest of the ! subst words */
  103. static struct wordent *exclnxt = NULL;
  104.  
  105. /* Count of remaining words in ! subst */
  106. static int exclc = 0;
  107.  
  108. /* "Globp" for alias resubstitution */
  109. Char *alvecp = NULL;
  110. int aret = F_SEEK;
  111.  
  112. /*
  113.  * Labuf implements a general buffer for lookahead during lexical operations.
  114.  * Text which is to be placed in the input stream can be stuck here.
  115.  * We stick parsed ahead $ constructs during initial input,
  116.  * process id's from `$$', and modified variable values (from qualifiers
  117.  * during expansion in sh.dol.c) here.
  118.  */
  119. static Char labuf[BUFSIZ];
  120.  
  121. /*
  122.  * Lex returns to its caller not only a wordlist (as a "var" parameter)
  123.  * but also whether a history substitution occurred.  This is used in
  124.  * the main (process) routine to determine whether to echo, and also
  125.  * when called by the alias routine to determine whether to keep the
  126.  * argument list.
  127.  */
  128. static bool hadhist = 0;
  129.  
  130. /*
  131.  * Avoid alias expansion recursion via \!#
  132.  */
  133. int     hleft;
  134.  
  135. static Char getCtmp;
  136.  
  137. #define getC(f)        ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
  138. #define    ungetC(c)    peekc = c
  139. #define    ungetD(c)    peekd = c
  140.  
  141. int
  142. lex(hp)
  143.     register struct wordent *hp;
  144. {
  145.     register struct wordent *wdp;
  146.     int     c;
  147.  
  148.     btell(&lineloc);
  149.     hp->next = hp->prev = hp;
  150.     hp->word = STRNULL;
  151.     hadhist = 0;
  152.     do
  153.     c = readc(0);
  154.     while (c == ' ' || c == '\t');
  155.     if (c == HISTSUB && intty)
  156.     /* ^lef^rit    from tty is short !:s^lef^rit */
  157.     getexcl(c);
  158.     else
  159.     unreadc(c);
  160.     wdp = hp;
  161.     /*
  162.      * The following loop is written so that the links needed by freelex will
  163.      * be ready and rarin to go even if it is interrupted.
  164.      */
  165.     do {
  166.     register struct wordent *new;
  167.  
  168.     new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
  169.     new->word = 0;
  170.     new->prev = wdp;
  171.     new->next = hp;
  172.     wdp->next = new;
  173.     wdp = new;
  174.     wdp->word = word();
  175.     } while (wdp->word[0] != '\n');
  176.     hp->prev = wdp;
  177.     return (hadhist);
  178. }
  179.  
  180. void
  181. prlex(fp, sp0)
  182.     FILE *fp;
  183.     struct wordent *sp0;
  184. {
  185.     register struct wordent *sp = sp0->next;
  186.  
  187.     for (;;) {
  188.     (void) fprintf(fp, "%s", vis_str(sp->word));
  189.     sp = sp->next;
  190.     if (sp == sp0)
  191.         break;
  192.     if (sp->word[0] != '\n')
  193.         (void) fputc(' ', fp);
  194.     }
  195. }
  196.  
  197. void
  198. copylex(hp, fp)
  199.     register struct wordent *hp;
  200.     register struct wordent *fp;
  201. {
  202.     register struct wordent *wdp;
  203.  
  204.     wdp = hp;
  205.     fp = fp->next;
  206.     do {
  207.     register struct wordent *new;
  208.  
  209.     new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
  210.     new->prev = wdp;
  211.     new->next = hp;
  212.     wdp->next = new;
  213.     wdp = new;
  214.     wdp->word = Strsave(fp->word);
  215.     fp = fp->next;
  216.     } while (wdp->word[0] != '\n');
  217.     hp->prev = wdp;
  218. }
  219.  
  220. void
  221. freelex(vp)
  222.     register struct wordent *vp;
  223. {
  224.     register struct wordent *fp;
  225.  
  226.     while (vp->next != vp) {
  227.     fp = vp->next;
  228.     vp->next = fp->next;
  229.     xfree((ptr_t) fp->word);
  230.     xfree((ptr_t) fp);
  231.     }
  232.     vp->prev = vp;
  233. }
  234.  
  235. static Char *
  236. word()
  237. {
  238.     register Char c, c1;
  239.     register Char *wp;
  240.     Char    wbuf[BUFSIZ];
  241.     register bool dolflg;
  242.     register int i;
  243.  
  244.     wp = wbuf;
  245.     i = BUFSIZ - 4;
  246. loop:
  247.     while ((c = getC(DOALL)) == ' ' || c == '\t')
  248.     continue;
  249.     if (cmap(c, _META | _ESC))
  250.     switch (c) {
  251.     case '&':
  252.     case '|':
  253.     case '<':
  254.     case '>':
  255.         *wp++ = c;
  256.         c1 = getC(DOALL);
  257.         if (c1 == c)
  258.         *wp++ = c1;
  259.         else
  260.         ungetC(c1);
  261.         goto ret;
  262.  
  263.     case '#':
  264.         if (intty)
  265.         break;
  266.         c = 0;
  267.         do {
  268.         c1 = c;
  269.         c = getC(0);
  270.         } while (c != '\n');
  271.         if (c1 == '\\')
  272.         goto loop;
  273.         /* fall into ... */
  274.  
  275.     case ';':
  276.     case '(':
  277.     case ')':
  278.     case '\n':
  279.         *wp++ = c;
  280.         goto ret;
  281.  
  282.     case '\\':
  283.         c = getC(0);
  284.         if (c == '\n') {
  285.         if (onelflg == 1)
  286.             onelflg = 2;
  287.         goto loop;
  288.         }
  289.         if (c != HIST)
  290.         *wp++ = '\\', --i;
  291.         c |= QUOTE;
  292.     }
  293.     c1 = 0;
  294.     dolflg = DOALL;
  295.     for (;;) {
  296.     if (c1) {
  297.         if (c == c1) {
  298.         c1 = 0;
  299.         dolflg = DOALL;
  300.         }
  301.         else if (c == '\\') {
  302.         c = getC(0);
  303.         if (c == HIST)
  304.             c |= QUOTE;
  305.         else {
  306.             if (c == '\n')
  307.             /*
  308.              * if (c1 == '`') c = ' '; else
  309.              */
  310.             c |= QUOTE;
  311.             ungetC(c);
  312.             c = '\\';
  313.         }
  314.         }
  315.         else if (c == '\n') {
  316.         seterror(ERR_UNMATCHED, c1);
  317.         ungetC(c);
  318.         break;
  319.         }
  320.     }
  321.     else if (cmap(c, _META | _Q | _Q1 | _ESC)) {
  322.         if (c == '\\') {
  323.         c = getC(0);
  324.         if (c == '\n') {
  325.             if (onelflg == 1)
  326.             onelflg = 2;
  327.             break;
  328.         }
  329.         if (c != HIST)
  330.             *wp++ = '\\', --i;
  331.         c |= QUOTE;
  332.         }
  333.         else if (cmap(c, _Q | _Q1)) {    /* '"` */
  334.         c1 = c;
  335.         dolflg = c == '"' ? DOALL : DOEXCL;
  336.         }
  337.         else if (c != '#' || !intty) {
  338.         ungetC(c);
  339.         break;
  340.         }
  341.     }
  342.     if (--i > 0) {
  343.         *wp++ = c;
  344.         c = getC(dolflg);
  345.     }
  346.     else {
  347.         seterror(ERR_WTOOLONG);
  348.         wp = &wbuf[1];
  349.         break;
  350.     }
  351.     }
  352. ret:
  353.     *wp = 0;
  354.     return (Strsave(wbuf));
  355. }
  356.  
  357. static int
  358. getC1(flag)
  359.     register int flag;
  360. {
  361.     register Char c;
  362.  
  363.     while (1) {
  364.     if (c = peekc) {
  365.         peekc = 0;
  366.         return (c);
  367.     }
  368.     if (lap) {
  369.         if ((c = *lap++) == 0)
  370.         lap = 0;
  371.         else {
  372.         if (cmap(c, _META | _Q | _Q1))
  373.             c |= QUOTE;
  374.         return (c);
  375.         }
  376.     }
  377.     if (c = peekd) {
  378.         peekd = 0;
  379.         return (c);
  380.     }
  381.     if (exclp) {
  382.         if (c = *exclp++)
  383.         return (c);
  384.         if (exclnxt && --exclc >= 0) {
  385.         exclnxt = exclnxt->next;
  386.         setexclp(exclnxt->word);
  387.         return (' ');
  388.         }
  389.         exclp = 0;
  390.         exclnxt = 0;
  391.     }
  392.     if (exclnxt) {
  393.         exclnxt = exclnxt->next;
  394.         if (--exclc < 0)
  395.         exclnxt = 0;
  396.         else
  397.         setexclp(exclnxt->word);
  398.         continue;
  399.     }
  400.     c = readc(0);
  401.     if (c == '$' && (flag & DODOL)) {
  402.         getdol();
  403.         continue;
  404.     }
  405.     if (c == HIST && (flag & DOEXCL)) {
  406.         getexcl(0);
  407.         continue;
  408.     }
  409.     break;
  410.     }
  411.     return (c);
  412. }
  413.  
  414. static void
  415. getdol()
  416. {
  417.     register Char *np, *ep;
  418.     Char    name[4 * MAXVARLEN + 1];
  419.     register int c;
  420.     int     sc;
  421.     bool    special = 0, toolong;
  422.  
  423.     np = name, *np++ = '$';
  424.     c = sc = getC(DOEXCL);
  425.     if (any("\t \n", c)) {
  426.     ungetD(c);
  427.     ungetC('$' | QUOTE);
  428.     return;
  429.     }
  430.     if (c == '{')
  431.     *np++ = c, c = getC(DOEXCL);
  432.     if (c == '#' || c == '?')
  433.     special++, *np++ = c, c = getC(DOEXCL);
  434.     *np++ = c;
  435.     switch (c) {
  436.  
  437.     case '<':
  438.     case '$':
  439.     case '!':
  440.     if (special)
  441.         seterror(ERR_SPDOLLT);
  442.     *np = 0;
  443.     addla(name);
  444.     return;
  445.  
  446.     case '\n':
  447.     ungetD(c);
  448.     np--;
  449.     seterror(ERR_NEWLINE);
  450.     *np = 0;
  451.     addla(name);
  452.     return;
  453.  
  454.     case '*':
  455.     if (special)
  456.         seterror(ERR_SPSTAR);
  457.     *np = 0;
  458.     addla(name);
  459.     return;
  460.  
  461.     default:
  462.     toolong = 0;
  463.     if (Isdigit(c)) {
  464. #ifdef notdef
  465.         /* let $?0 pass for now */
  466.         if (special) {
  467.         seterror(ERR_DIGIT);
  468.         *np = 0;
  469.         addla(name);
  470.         return;
  471.         }
  472. #endif
  473.         /* we know that np < &name[4] */
  474.         ep = &np[MAXVARLEN];
  475.         while (c = getC(DOEXCL)) {
  476.         if (!Isdigit(c))
  477.             break;
  478.         if (np < ep)
  479.             *np++ = c;
  480.         else
  481.             toolong = 1;
  482.         }
  483.     }
  484.     else if (letter(c)) {
  485.         /* we know that np < &name[4] */
  486.         ep = &np[MAXVARLEN];
  487.         toolong = 0;
  488.         while (c = getC(DOEXCL)) {
  489.         /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
  490.         if (!letter(c) && !Isdigit(c))
  491.             break;
  492.         if (np < ep)
  493.             *np++ = c;
  494.         else
  495.             toolong = 1;
  496.         }
  497.     }
  498.     else {
  499.         *np = 0;
  500.         seterror(ERR_VARILL);
  501.         addla(name);
  502.         return;
  503.     }
  504.     if (toolong) {
  505.         seterror(ERR_VARTOOLONG);
  506.         *np = 0;
  507.         addla(name);
  508.         return;
  509.     }
  510.     break;
  511.     }
  512.     if (c == '[') {
  513.     *np++ = c;
  514.     /*
  515.      * Name up to here is a max of MAXVARLEN + 8.
  516.      */
  517.     ep = &np[2 * MAXVARLEN + 8];
  518.     do {
  519.         /*
  520.          * Michael Greim: Allow $ expansion to take place in selector
  521.          * expressions. (limits the number of characters returned)
  522.          */
  523.         c = getC(DOEXCL | DODOL);
  524.         if (c == '\n') {
  525.         ungetD(c);
  526.         np--;
  527.         seterror(ERR_NLINDEX);
  528.         *np = 0;
  529.         addla(name);
  530.         return;
  531.         }
  532.         if (np < ep)
  533.         *np++ = c;
  534.     } while (c != ']');
  535.     *np = '\0';
  536.     if (np >= ep) {
  537.         seterror(ERR_SELOVFL);
  538.         addla(name);
  539.         return;
  540.     }
  541.     c = getC(DOEXCL);
  542.     }
  543.     /*
  544.      * Name up to here is a max of 2 * MAXVARLEN + 8.
  545.      */
  546.     if (c == ':') {
  547.     /*
  548.      * if the :g modifier is followed by a newline, then error right away!
  549.      * -strike
  550.      */
  551.  
  552.     int     gmodflag = 0, amodflag = 0;
  553.  
  554.     do {
  555.         *np++ = c, c = getC(DOEXCL);
  556.         if (c == 'g' || c == 'a') {
  557.         if (c == 'g')
  558.             gmodflag++;
  559.         else
  560.             amodflag++;
  561.         *np++ = c; c = getC(DOEXCL);
  562.         }
  563.         if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
  564.         if (c == 'g')
  565.             gmodflag++;
  566.         else
  567.             amodflag++;
  568.         *np++ = c; c = getC(DOEXCL);
  569.         }
  570.         *np++ = c;
  571.         /* scan s// [eichin:19910926.0512EST] */
  572.         if (c == 's') {
  573.         int delimcnt = 2;
  574.         int delim = getC(0);
  575.         *np++ = delim;
  576.         
  577.         if (!delim || letter(delim)
  578.             || Isdigit(delim) || any(" \t\n", delim)) {
  579.             seterror(ERR_BADSUBST);
  580.             break;
  581.         }    
  582.         while ((c = getC(0)) != (-1)) {
  583.             *np++ = c;
  584.             if(c == delim) delimcnt--;
  585.             if(!delimcnt) break;
  586.         }
  587.         if(delimcnt) {
  588.             seterror(ERR_BADSUBST);
  589.             break;
  590.         }
  591.         c = 's';
  592.         }
  593.         if (!any("htrqxes", c)) {
  594.         if ((amodflag || gmodflag) && c == '\n')
  595.             stderror(ERR_VARSYN);    /* strike */
  596.         seterror(ERR_VARMOD, c);
  597.         *np = 0;
  598.         addla(name);
  599.         return;
  600.         }
  601.     }
  602.     while ((c = getC(DOEXCL)) == ':');
  603.     ungetD(c);
  604.     }
  605.     else
  606.     ungetD(c);
  607.     if (sc == '{') {
  608.     c = getC(DOEXCL);
  609.     if (c != '}') {
  610.         ungetD(c);
  611.         seterror(ERR_MISSING, '}');
  612.         *np = 0;
  613.         addla(name);
  614.         return;
  615.     }
  616.     *np++ = c;
  617.     }
  618.     *np = 0;
  619.     addla(name);
  620.     return;
  621. }
  622.  
  623. void
  624. addla(cp)
  625.     Char   *cp;
  626. {
  627.     Char    buf[BUFSIZ];
  628.  
  629.     if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
  630.     (sizeof(labuf) - 4) / sizeof(Char)) {
  631.     seterror(ERR_EXPOVFL);
  632.     return;
  633.     }
  634.     if (lap)
  635.     (void) Strcpy(buf, lap);
  636.     (void) Strcpy(labuf, cp);
  637.     if (lap)
  638.     (void) Strcat(labuf, buf);
  639.     lap = labuf;
  640. }
  641.  
  642. static Char lhsb[32];
  643. static Char slhs[32];
  644. static Char rhsb[64];
  645. static int quesarg;
  646.  
  647. static void
  648. getexcl(sc)
  649.     int    sc;
  650. {
  651.     register struct wordent *hp, *ip;
  652.     int     left, right, dol;
  653.     register int c;
  654.  
  655.     if (sc == 0) {
  656.     sc = getC(0);
  657.     if (sc != '{') {
  658.         ungetC(sc);
  659.         sc = 0;
  660.     }
  661.     }
  662.     quesarg = -1;
  663.     lastev = eventno;
  664.     hp = gethent(sc);
  665.     if (hp == 0)
  666.     return;
  667.     hadhist = 1;
  668.     dol = 0;
  669.     if (hp == alhistp)
  670.     for (ip = hp->next->next; ip != alhistt; ip = ip->next)
  671.         dol++;
  672.     else
  673.     for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
  674.         dol++;
  675.     left = 0, right = dol;
  676.     if (sc == HISTSUB) {
  677.     ungetC('s'), unreadc(HISTSUB), c = ':';
  678.     goto subst;
  679.     }
  680.     c = getC(0);
  681.     if (!any(":^$*-%", c))
  682.     goto subst;
  683.     left = right = -1;
  684.     if (c == ':') {
  685.     c = getC(0);
  686.     unreadc(c);
  687.     if (letter(c) || c == '&') {
  688.         c = ':';
  689.         left = 0, right = dol;
  690.         goto subst;
  691.     }
  692.     }
  693.     else
  694.     ungetC(c);
  695.     if (!getsel(&left, &right, dol))
  696.     return;
  697.     c = getC(0);
  698.     if (c == '*')
  699.     ungetC(c), c = '-';
  700.     if (c == '-') {
  701.     if (!getsel(&left, &right, dol))
  702.         return;
  703.     c = getC(0);
  704.     }
  705. subst:
  706.     exclc = right - left + 1;
  707.     while (--left >= 0)
  708.     hp = hp->next;
  709.     if (sc == HISTSUB || c == ':') {
  710.     do {
  711.         hp = getsub(hp);
  712.         c = getC(0);
  713.     } while (c == ':');
  714.     }
  715.     unreadc(c);
  716.     if (sc == '{') {
  717.     c = getC(0);
  718.     if (c != '}')
  719.         seterror(ERR_BADBANG);
  720.     }
  721.     exclnxt = hp;
  722. }
  723.  
  724. static struct wordent *
  725. getsub(en)
  726.     struct wordent *en;
  727. {
  728.     register Char *cp;
  729.     int     delim;
  730.     register int c;
  731.     int     sc;
  732.     bool global;
  733.     Char    orhsb[sizeof(rhsb) / sizeof(Char)];
  734.  
  735.     do {
  736.     exclnxt = 0;
  737.     global = 0;
  738.     sc = c = getC(0);
  739.     if (c == 'g' || c == 'a') {
  740.         global |= (c == 'g') ? 1 : 2;
  741.         sc = c = getC(0);
  742.     }
  743.     if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
  744.         global |= (c == 'g') ? 1 : 2;
  745.         sc = c = getC(0);
  746.     }
  747.  
  748.     switch (c) {
  749.     case 'p':
  750.         justpr++;
  751.         return (en);
  752.  
  753.     case 'x':
  754.     case 'q':
  755.         global |= 1;
  756.  
  757.         /* fall into ... */
  758.  
  759.     case 'h':
  760.     case 'r':
  761.     case 't':
  762.     case 'e':
  763.         break;
  764.  
  765.     case '&':
  766.         if (slhs[0] == 0) {
  767.         seterror(ERR_NOSUBST);
  768.         return (en);
  769.         }
  770.         (void) Strcpy(lhsb, slhs);
  771.         break;
  772.  
  773. #ifdef notdef
  774.     case '~':
  775.         if (lhsb[0] == 0)
  776.         goto badlhs;
  777.         break;
  778. #endif
  779.  
  780.     case 's':
  781.         delim = getC(0);
  782.         if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
  783.         unreadc(delim);
  784.         lhsb[0] = 0;
  785.         seterror(ERR_BADSUBST);
  786.         return (en);
  787.         }
  788.         cp = lhsb;
  789.         for (;;) {
  790.         c = getC(0);
  791.         if (c == '\n') {
  792.             unreadc(c);
  793.             break;
  794.         }
  795.         if (c == delim)
  796.             break;
  797.         if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
  798.             lhsb[0] = 0;
  799.             seterror(ERR_BADSUBST);
  800.             return (en);
  801.         }
  802.         if (c == '\\') {
  803.             c = getC(0);
  804.             if (c != delim && c != '\\')
  805.             *cp++ = '\\';
  806.         }
  807.         *cp++ = c;
  808.         }
  809.         if (cp != lhsb)
  810.         *cp++ = 0;
  811.         else if (lhsb[0] == 0) {
  812.         seterror(ERR_LHS);
  813.         return (en);
  814.         }
  815.         cp = rhsb;
  816.         (void) Strcpy(orhsb, cp);
  817.         for (;;) {
  818.         c = getC(0);
  819.         if (c == '\n') {
  820.             unreadc(c);
  821.             break;
  822.         }
  823.         if (c == delim)
  824.             break;
  825. #ifdef notdef
  826.         if (c == '~') {
  827.             if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) /
  828.                            sizeof(Char) - 2])
  829.             goto toorhs;
  830.             (void) Strcpy(cp, orhsb);
  831.             cp = Strend(cp);
  832.             continue;
  833.         }
  834. #endif
  835.         if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
  836.             seterror(ERR_RHSLONG);
  837.             return (en);
  838.         }
  839.         if (c == '\\') {
  840.             c = getC(0);
  841.             if (c != delim /* && c != '~' */ )
  842.             *cp++ = '\\';
  843.         }
  844.         *cp++ = c;
  845.         }
  846.         *cp++ = 0;
  847.         break;
  848.  
  849.     default:
  850.         if (c == '\n')
  851.         unreadc(c);
  852.         seterror(ERR_BADBANGMOD, c);
  853.         return (en);
  854.     }
  855.     (void) Strcpy(slhs, lhsb);
  856.     if (exclc)
  857.         en = dosub(sc, en, global);
  858.     }
  859.     while ((c = getC(0)) == ':');
  860.     unreadc(c);
  861.     return (en);
  862. }
  863.  
  864. static struct wordent *
  865. dosub(sc, en, global)
  866.     int     sc;
  867.     struct wordent *en;
  868.     bool global;
  869. {
  870.     struct wordent lexi;
  871.     bool    didsub = 0, didone = 0;
  872.     struct wordent *hp = &lexi;
  873.     register struct wordent *wdp;
  874.     register int i = exclc;
  875.  
  876.     wdp = hp;
  877.     while (--i >= 0) {
  878.     register struct wordent *new = 
  879.         (struct wordent *) xcalloc(1, sizeof *wdp);
  880.  
  881.     new->word = 0;
  882.     new->prev = wdp;
  883.     new->next = hp;
  884.     wdp->next = new;
  885.     wdp = new;
  886.     en = en->next;
  887.     if (en->word) {
  888.         Char *tword, *otword;
  889.  
  890.         if ((global & 1) || didsub == 0) {
  891.         tword = subword(en->word, sc, &didone);
  892.         if (didone)
  893.             didsub = 1;
  894.         if (global & 2) {
  895.             while (didone && tword != STRNULL) {
  896.             otword = tword;
  897.             tword = subword(otword, sc, &didone);
  898.             if (Strcmp(tword, otword) == 0) {
  899.                 xfree((ptr_t) otword);
  900.                 break;
  901.             }
  902.             else
  903.                 xfree((ptr_t) otword);
  904.             }
  905.         }
  906.         }
  907.         else
  908.         tword = Strsave(en->word);
  909.         wdp->word = tword;
  910.     }
  911.     }
  912.     if (didsub == 0)
  913.     seterror(ERR_MODFAIL);
  914.     hp->prev = wdp;
  915.     return (&enthist(-1000, &lexi, 0)->Hlex);
  916. }
  917.  
  918. static Char *
  919. subword(cp, type, adid)
  920.     Char   *cp;
  921.     int     type;
  922.     bool   *adid;
  923. {
  924.     Char    wbuf[BUFSIZ];
  925.     register Char *wp, *mp, *np;
  926.     register int i;
  927.  
  928.     *adid = 0;
  929.     switch (type) {
  930.  
  931.     case 'r':
  932.     case 'e':
  933.     case 'h':
  934.     case 't':
  935.     case 'q':
  936.     case 'x':
  937.     wp = domod(cp, type);
  938.     if (wp == 0)
  939.         return (Strsave(cp));
  940.     *adid = 1;
  941.     return (wp);
  942.  
  943.     default:
  944.     wp = wbuf;
  945.     i = BUFSIZ - 4;
  946.     for (mp = cp; *mp; mp++)
  947.         if (matchs(mp, lhsb)) {
  948.         for (np = cp; np < mp;)
  949.             *wp++ = *np++, --i;
  950.         for (np = rhsb; *np; np++)
  951.             switch (*np) {
  952.  
  953.             case '\\':
  954.             if (np[1] == '&')
  955.                 np++;
  956.             /* fall into ... */
  957.  
  958.             default:
  959.             if (--i < 0) {
  960.                 seterror(ERR_SUBOVFL);
  961.                 return (STRNULL);
  962.             }
  963.             *wp++ = *np;
  964.             continue;
  965.  
  966.             case '&':
  967.             i -= Strlen(lhsb);
  968.             if (i < 0) {
  969.                 seterror(ERR_SUBOVFL);
  970.                 return (STRNULL);
  971.             }
  972.             *wp = 0;
  973.             (void) Strcat(wp, lhsb);
  974.             wp = Strend(wp);
  975.             continue;
  976.             }
  977.         mp += Strlen(lhsb);
  978.         i -= Strlen(mp);
  979.         if (i < 0) {
  980.             seterror(ERR_SUBOVFL);
  981.             return (STRNULL);
  982.         }
  983.         *wp = 0;
  984.         (void) Strcat(wp, mp);
  985.         *adid = 1;
  986.         return (Strsave(wbuf));
  987.         }
  988.     return (Strsave(cp));
  989.     }
  990. }
  991.  
  992. Char   *
  993. domod(cp, type)
  994.     Char   *cp;
  995.     int     type;
  996. {
  997.     register Char *wp, *xp;
  998.     register int c;
  999.  
  1000.     switch (type) {
  1001.  
  1002.     case 'x':
  1003.     case 'q':
  1004.     wp = Strsave(cp);
  1005.     for (xp = wp; c = *xp; xp++)
  1006.         if ((c != ' ' && c != '\t') || type == 'q')
  1007.         *xp |= QUOTE;
  1008.     return (wp);
  1009.  
  1010.     case 'h':
  1011.     case 't':
  1012.     if (!any(short2str(cp), '/'))
  1013.         return (type == 't' ? Strsave(cp) : 0);
  1014.     wp = Strend(cp);
  1015.     while (*--wp != '/')
  1016.         continue;
  1017.     if (type == 'h')
  1018.         xp = Strsave(cp), xp[wp - cp] = 0;
  1019.     else
  1020.         xp = Strsave(wp + 1);
  1021.     return (xp);
  1022.  
  1023.     case 'e':
  1024.     case 'r':
  1025.     wp = Strend(cp);
  1026.     for (wp--; wp >= cp && *wp != '/'; wp--)
  1027.         if (*wp == '.') {
  1028.         if (type == 'e')
  1029.             xp = Strsave(wp + 1);
  1030.         else
  1031.             xp = Strsave(cp), xp[wp - cp] = 0;
  1032.         return (xp);
  1033.         }
  1034.     return (Strsave(type == 'e' ? STRNULL : cp));
  1035.     default:
  1036.     break;
  1037.     }
  1038.     return (0);
  1039. }
  1040.  
  1041. static int
  1042. matchs(str, pat)
  1043.     register Char *str, *pat;
  1044. {
  1045.     while (*str && *pat && *str == *pat)
  1046.     str++, pat++;
  1047.     return (*pat == 0);
  1048. }
  1049.  
  1050. static int
  1051. getsel(al, ar, dol)
  1052.     register int *al, *ar;
  1053.     int     dol;
  1054. {
  1055.     register int c = getC(0);
  1056.     register int i;
  1057.     bool    first = *al < 0;
  1058.  
  1059.     switch (c) {
  1060.  
  1061.     case '%':
  1062.     if (quesarg == -1) {
  1063.         seterror(ERR_BADBANGARG);
  1064.         return (0);
  1065.     }
  1066.     if (*al < 0)
  1067.         *al = quesarg;
  1068.     *ar = quesarg;
  1069.     break;
  1070.  
  1071.     case '-':
  1072.     if (*al < 0) {
  1073.         *al = 0;
  1074.         *ar = dol - 1;
  1075.         unreadc(c);
  1076.     }
  1077.     return (1);
  1078.  
  1079.     case '^':
  1080.     if (*al < 0)
  1081.         *al = 1;
  1082.     *ar = 1;
  1083.     break;
  1084.  
  1085.     case '$':
  1086.     if (*al < 0)
  1087.         *al = dol;
  1088.     *ar = dol;
  1089.     break;
  1090.  
  1091.     case '*':
  1092.     if (*al < 0)
  1093.         *al = 1;
  1094.     *ar = dol;
  1095.     if (*ar < *al) {
  1096.         *ar = 0;
  1097.         *al = 1;
  1098.         return (1);
  1099.     }
  1100.     break;
  1101.  
  1102.     default:
  1103.     if (Isdigit(c)) {
  1104.         i = 0;
  1105.         while (Isdigit(c)) {
  1106.         i = i * 10 + c - '0';
  1107.         c = getC(0);
  1108.         }
  1109.         if (i < 0)
  1110.         i = dol + 1;
  1111.         if (*al < 0)
  1112.         *al = i;
  1113.         *ar = i;
  1114.     }
  1115.     else if (*al < 0)
  1116.         *al = 0, *ar = dol;
  1117.     else
  1118.         *ar = dol - 1;
  1119.     unreadc(c);
  1120.     break;
  1121.     }
  1122.     if (first) {
  1123.     c = getC(0);
  1124.     unreadc(c);
  1125.     if (any("-$*", c))
  1126.         return (1);
  1127.     }
  1128.     if (*al > *ar || *ar > dol) {
  1129.     seterror(ERR_BADBANGARG);
  1130.     return (0);
  1131.     }
  1132.     return (1);
  1133.  
  1134. }
  1135.  
  1136. static struct wordent *
  1137. gethent(sc)
  1138.     int     sc;
  1139. {
  1140.     register struct Hist *hp;
  1141.     register Char *np;
  1142.     register int c;
  1143.     int     event;
  1144.     bool    back = 0;
  1145.  
  1146.     c = sc == HISTSUB ? HIST : getC(0);
  1147.     if (c == HIST) {
  1148.     if (alhistp)
  1149.         return (alhistp);
  1150.     event = eventno;
  1151.     }
  1152.     else
  1153.     switch (c) {
  1154.  
  1155.     case ':':
  1156.     case '^':
  1157.     case '$':
  1158.     case '*':
  1159.     case '%':
  1160.         ungetC(c);
  1161.         if (lastev == eventno && alhistp)
  1162.         return (alhistp);
  1163.         event = lastev;
  1164.         break;
  1165.  
  1166.     case '#':        /* !# is command being typed in (mrh) */
  1167.         if (--hleft == 0) {
  1168.         seterror(ERR_HISTLOOP);
  1169.         return (0);
  1170.         }
  1171.         else
  1172.         return (¶ml);
  1173.         /* NOTREACHED */
  1174.  
  1175.     case '-':
  1176.         back = 1;
  1177.         c = getC(0);
  1178.         /* FALLSTHROUGH */
  1179.  
  1180.     default:
  1181.         if (any("(=~", c)) {
  1182.         unreadc(c);
  1183.         ungetC(HIST);
  1184.         return (0);
  1185.         }
  1186.         np = lhsb;
  1187.         event = 0;
  1188.         while (!cmap(c, _ESC | _META | _Q | _Q1) && !any("${}:", c)) {
  1189.         if (event != -1 && Isdigit(c))
  1190.             event = event * 10 + c - '0';
  1191.         else
  1192.             event = -1;
  1193.         if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
  1194.             *np++ = c;
  1195.         c = getC(0);
  1196.         }
  1197.         unreadc(c);
  1198.         if (np == lhsb) {
  1199.         ungetC(HIST);
  1200.         return (0);
  1201.         }
  1202.         *np++ = 0;
  1203.         if (event != -1) {
  1204.         /*
  1205.          * History had only digits
  1206.          */
  1207.         if (back)
  1208.             event = eventno + (alhistp == 0) - (event ? event : 0);
  1209.         break;
  1210.         }
  1211.         hp = findev(lhsb, 0);
  1212.         if (hp)
  1213.         lastev = hp->Hnum;
  1214.         return (&hp->Hlex);
  1215.  
  1216.     case '?':
  1217.         np = lhsb;
  1218.         for (;;) {
  1219.         c = getC(0);
  1220.         if (c == '\n') {
  1221.             unreadc(c);
  1222.             break;
  1223.         }
  1224.         if (c == '?')
  1225.             break;
  1226.         if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
  1227.             *np++ = c;
  1228.         }
  1229.         if (np == lhsb) {
  1230.         if (lhsb[0] == 0) {
  1231.             seterror(ERR_NOSEARCH);
  1232.             return (0);
  1233.         }
  1234.         }
  1235.         else
  1236.         *np++ = 0;
  1237.         hp = findev(lhsb, 1);
  1238.         if (hp)
  1239.         lastev = hp->Hnum;
  1240.         return (&hp->Hlex);
  1241.     }
  1242.  
  1243.     for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
  1244.     if (hp->Hnum == event) {
  1245.         hp->Href = eventno;
  1246.         lastev = hp->Hnum;
  1247.         return (&hp->Hlex);
  1248.     }
  1249.     np = putn(event);
  1250.     seterror(ERR_NOEVENT, vis_str(np));
  1251.     return (0);
  1252. }
  1253.  
  1254. static struct Hist *
  1255. findev(cp, anyarg)
  1256.     Char   *cp;
  1257.     bool    anyarg;
  1258. {
  1259.     register struct Hist *hp;
  1260.  
  1261.     for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
  1262.     Char   *dp;
  1263.     register Char *p, *q;
  1264.     register struct wordent *lp = hp->Hlex.next;
  1265.     int     argno = 0;
  1266.  
  1267.     /*
  1268.      * The entries added by alias substitution don't have a newline but do
  1269.      * have a negative event number. Savehist() trims off these entries,
  1270.      * but it happens before alias expansion, too early to delete those
  1271.      * from the previous command.
  1272.      */
  1273.     if (hp->Hnum < 0)
  1274.         continue;
  1275.     if (lp->word[0] == '\n')
  1276.         continue;
  1277.     if (!anyarg) {
  1278.         p = cp;
  1279.         q = lp->word;
  1280.         do
  1281.         if (!*p)
  1282.             return (hp);
  1283.         while (*p++ == *q++);
  1284.         continue;
  1285.     }
  1286.     do {
  1287.         for (dp = lp->word; *dp; dp++) {
  1288.         p = cp;
  1289.         q = dp;
  1290.         do
  1291.             if (!*p) {
  1292.             quesarg = argno;
  1293.             return (hp);
  1294.             }
  1295.         while (*p++ == *q++);
  1296.         }
  1297.         lp = lp->next;
  1298.         argno++;
  1299.     } while (lp->word[0] != '\n');
  1300.     }
  1301.     seterror(ERR_NOEVENT, vis_str(cp));
  1302.     return (0);
  1303. }
  1304.  
  1305.  
  1306. static void
  1307. setexclp(cp)
  1308.     register Char *cp;
  1309. {
  1310.     if (cp && cp[0] == '\n')
  1311.     return;
  1312.     exclp = cp;
  1313. }
  1314.  
  1315. void
  1316. unreadc(c)
  1317.     int    c;
  1318. {
  1319.     peekread = c;
  1320. }
  1321.  
  1322. int
  1323. readc(wanteof)
  1324.     bool    wanteof;
  1325. {
  1326.     register int c;
  1327.     static  sincereal;
  1328.  
  1329.     aret = F_SEEK;
  1330.     if (c = peekread) {
  1331.     peekread = 0;
  1332.     return (c);
  1333.     }
  1334. top:
  1335.     aret = F_SEEK;
  1336.     if (alvecp) {
  1337.     aret = A_SEEK;
  1338.     if (c = *alvecp++)
  1339.         return (c);
  1340.     if (alvec && *alvec) {
  1341.         alvecp = *alvec++;
  1342.         return (' ');
  1343.     }
  1344.     else {
  1345.         aret = F_SEEK;
  1346.         alvecp = NULL;
  1347.         return('\n');
  1348.     }
  1349.     }
  1350.     if (alvec) {
  1351.     if (alvecp = *alvec) {
  1352.         alvec++;
  1353.         goto top;
  1354.     }
  1355.     /* Infinite source! */
  1356.     return ('\n');
  1357.     }
  1358.     if (evalp) {
  1359.     aret = E_SEEK;
  1360.     if (c = *evalp++)
  1361.         return (c);
  1362.     if (evalvec && *evalvec) {
  1363.         evalp = *evalvec++;
  1364.         return (' ');
  1365.     }
  1366.     aret = F_SEEK;
  1367.     evalp = 0;
  1368.     }
  1369.     if (evalvec) {
  1370.     if (evalvec == (Char **) 1) {
  1371.         doneinp = 1;
  1372.         reset();
  1373.     }
  1374.     if (evalp = *evalvec) {
  1375.         evalvec++;
  1376.         goto top;
  1377.     }
  1378.     evalvec = (Char **) 1;
  1379.     return ('\n');
  1380.     }
  1381.     do {
  1382.     if (arginp == (Char *) 1 || onelflg == 1) {
  1383.         if (wanteof)
  1384.         return (-1);
  1385.         exitstat();
  1386.     }
  1387.     if (arginp) {
  1388.         if ((c = *arginp++) == 0) {
  1389.         arginp = (Char *) 1;
  1390.         return ('\n');
  1391.         }
  1392.         return (c);
  1393.     }
  1394. reread:
  1395.     c = bgetc();
  1396.     if (c < 0) {
  1397.         struct termios tty;
  1398.         if (wanteof)
  1399.         return (-1);
  1400.         /* was isatty but raw with ignoreeof yields problems */
  1401.         if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON))
  1402.         {
  1403.         /* was 'short' for FILEC */
  1404.         int     ctpgrp;
  1405.  
  1406.         if (++sincereal > 25)
  1407.             goto oops;
  1408.         if (tpgrp != -1 &&
  1409.             (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
  1410.             tpgrp != ctpgrp) {
  1411.             (void) tcsetpgrp(FSHTTY, tpgrp);
  1412.             (void) killpg((pid_t) ctpgrp, SIGHUP);
  1413.             (void) fprintf(csherr, "Reset tty pgrp from %d to %d\n",
  1414.                    ctpgrp, tpgrp);
  1415.             goto reread;
  1416.         }
  1417.         if (adrof(STRignoreeof)) {
  1418.             if (loginsh)
  1419.             (void) fprintf(csherr,"\nUse \"logout\" to logout.\n");
  1420.             else
  1421.             (void) fprintf(csherr,"\nUse \"exit\" to leave csh.\n");
  1422.             reset();
  1423.         }
  1424.         if (chkstop == 0)
  1425.             panystop(1);
  1426.         }
  1427.     oops:
  1428.         doneinp = 1;
  1429.         reset();
  1430.     }
  1431.     sincereal = 0;
  1432.     if (c == '\n' && onelflg)
  1433.         onelflg--;
  1434.     } while (c == 0);
  1435.     return (c);
  1436. }
  1437.  
  1438. static int
  1439. bgetc()
  1440. {
  1441.     register int buf, off, c;
  1442.  
  1443. #ifdef FILEC
  1444.     register int numleft = 0, roomleft;
  1445.     Char    ttyline[BUFSIZ];
  1446. #endif
  1447.     char    tbuf[BUFSIZ + 1];
  1448.  
  1449.     if (cantell) {
  1450.     if (fseekp < fbobp || fseekp > feobp) {
  1451.         fbobp = feobp = fseekp;
  1452.         (void) lseek(SHIN, fseekp, L_SET);
  1453.     }
  1454.     if (fseekp == feobp) {
  1455.         int     i;
  1456.  
  1457.         fbobp = feobp;
  1458.         do
  1459.         c = read(SHIN, tbuf, BUFSIZ);
  1460.         while (c < 0 && errno == EINTR);
  1461.         if (c <= 0)
  1462.         return (-1);
  1463.         for (i = 0; i < c; i++)
  1464.         fbuf[0][i] = (unsigned char) tbuf[i];
  1465.         feobp += c;
  1466.     }
  1467.     c = fbuf[0][fseekp - fbobp];
  1468.     fseekp++;
  1469.     return (c);
  1470.     }
  1471.  
  1472. again:
  1473.     buf = (int) fseekp / BUFSIZ;
  1474.     if (buf >= fblocks) {
  1475.     register Char **nfbuf =
  1476.     (Char **) xcalloc((size_t) (fblocks + 2),
  1477.               sizeof(Char **));
  1478.  
  1479.     if (fbuf) {
  1480.         (void) blkcpy(nfbuf, fbuf);
  1481.         xfree((ptr_t) fbuf);
  1482.     }
  1483.     fbuf = nfbuf;
  1484.     fbuf[fblocks] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
  1485.     fblocks++;
  1486.     if (!intty)
  1487.         goto again;
  1488.     }
  1489.     if (fseekp >= feobp) {
  1490.     buf = (int) feobp / BUFSIZ;
  1491.     off = (int) feobp % BUFSIZ;
  1492.     roomleft = BUFSIZ - off;
  1493.  
  1494. #ifdef FILEC
  1495.     roomleft = BUFSIZ - off;
  1496.     for (;;) {
  1497.         if (filec && intty) {
  1498.         c = numleft ? numleft : tenex(ttyline, BUFSIZ);
  1499.         if (c > roomleft) {
  1500.             /* start with fresh buffer */
  1501.             feobp = fseekp = fblocks * BUFSIZ;
  1502.             numleft = c;
  1503.             goto again;
  1504.         }
  1505.         if (c > 0)
  1506.             bcopy(ttyline, fbuf[buf] + off, c * sizeof(Char));
  1507.         numleft = 0;
  1508.         }
  1509.         else {
  1510. #endif
  1511.         c = read(SHIN, tbuf, roomleft);
  1512.         if (c > 0) {
  1513.             int     i;
  1514.             Char   *ptr = fbuf[buf] + off;
  1515.  
  1516.             for (i = 0; i < c; i++)
  1517.             ptr[i] = (unsigned char) tbuf[i];
  1518.         }
  1519. #ifdef FILEC
  1520.         }
  1521. #endif
  1522.         if (c >= 0)
  1523.         break;
  1524.         if (errno == EWOULDBLOCK) {
  1525.         int     off = 0;
  1526.  
  1527.         (void) ioctl(SHIN, FIONBIO, (ioctl_t) & off);
  1528.         }
  1529.         else if (errno != EINTR)
  1530.         break;
  1531.     }
  1532.     if (c <= 0)
  1533.         return (-1);
  1534.     feobp += c;
  1535. #ifndef FILEC
  1536.     goto again;
  1537. #else
  1538.     if (filec && !intty)
  1539.         goto again;
  1540. #endif
  1541.     }
  1542.     c = fbuf[buf][(int) fseekp % BUFSIZ];
  1543.     fseekp++;
  1544.     return (c);
  1545. }
  1546.  
  1547. static void
  1548. bfree()
  1549. {
  1550.     register int sb, i;
  1551.  
  1552.     if (cantell)
  1553.     return;
  1554.     if (whyles)
  1555.     return;
  1556.     sb = (int) (fseekp - 1) / BUFSIZ;
  1557.     if (sb > 0) {
  1558.     for (i = 0; i < sb; i++)
  1559.         xfree((ptr_t) fbuf[i]);
  1560.     (void) blkcpy(fbuf, &fbuf[sb]);
  1561.     fseekp -= BUFSIZ * sb;
  1562.     feobp -= BUFSIZ * sb;
  1563.     fblocks -= sb;
  1564.     }
  1565. }
  1566.  
  1567. void
  1568. bseek(l)
  1569.     struct Ain   *l;
  1570. {
  1571.     switch (aret = l->type) {
  1572.     case E_SEEK:
  1573.     evalvec = l->a_seek;
  1574.     evalp = (Char *) l->f_seek;
  1575.     return;
  1576.     case A_SEEK:
  1577.     alvec = l->a_seek;
  1578.     alvecp = (Char *) l->f_seek;
  1579.     return;
  1580.     case F_SEEK:
  1581.     fseekp = l->f_seek;
  1582.     return;
  1583.     default:
  1584.     (void) fprintf(csherr, "Bad seek type %d\n", aret);
  1585.     abort();
  1586.     }
  1587. }
  1588.  
  1589. void
  1590. btell(l)
  1591.     struct Ain *l;
  1592. {
  1593.     switch (l->type = aret) {
  1594.     case E_SEEK:
  1595.     l->a_seek = evalvec;
  1596.     l->f_seek = (off_t) evalp;
  1597.     return;
  1598.     case A_SEEK:
  1599.     l->a_seek = alvec;
  1600.     l->f_seek = (off_t) alvecp;
  1601.     return;
  1602.     case F_SEEK:
  1603.     l->f_seek = fseekp;
  1604.     l->a_seek = NULL;
  1605.     return;
  1606.     default:
  1607.     (void) fprintf(csherr, "Bad seek type %d\n", aret);
  1608.     abort();
  1609.     }
  1610. }
  1611.  
  1612. void
  1613. btoeof()
  1614. {
  1615.     (void) lseek(SHIN, (off_t) 0, L_XTND);
  1616.     aret = F_SEEK;
  1617.     fseekp = feobp;
  1618.     alvec = NULL;
  1619.     alvecp = NULL;
  1620.     evalvec = NULL;
  1621.     evalp = NULL;
  1622.     wfree();
  1623.     bfree();
  1624. }
  1625.  
  1626. void
  1627. settell()
  1628. {
  1629.     cantell = 0;
  1630.     if (arginp || onelflg || intty)
  1631.     return;
  1632.     if (lseek(SHIN, (off_t) 0, L_INCR) < 0 || errno == ESPIPE)
  1633.     return;
  1634.     fbuf = (Char **) xcalloc(2, sizeof(Char **));
  1635.     fblocks = 1;
  1636.     fbuf[0] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
  1637.     fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, L_INCR);
  1638.     cantell = 1;
  1639. }
  1640.