Home | History | Annotate | Line # | Download | only in csh
lex.c revision 1.1.1.2
      1 /*-
      2  * Copyright (c) 1980, 1991, 1993
      3  *	The Regents of the University of California.  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	8.1 (Berkeley) 5/31/93";
     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 | _QF | _QB | _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, _QF | _QB)) {	/* '"` */
    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) != '\0') {
    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 | _QF | _QB))
    373 		    c |= QUOTE;
    374 		return (c);
    375 	    }
    376 	}
    377 	if ((c = peekd) != '\0') {
    378 	    peekd = 0;
    379 	    return (c);
    380 	}
    381 	if (exclp) {
    382 	    if ((c = *exclp++) != '\0')
    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)) != '\0'){
    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)) != '\0') {
    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) != '\0'; 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 (&paraml);
   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 | _QF | _QB) && !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) != '\0') {
   1331 	peekread = 0;
   1332 	return (c);
   1333     }
   1334 top:
   1335     aret = F_SEEK;
   1336     if (alvecp) {
   1337 	aret = A_SEEK;
   1338 	if ((c = *alvecp++) != '\0')
   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) != '\0') {
   1352 	    alvec++;
   1353 	    goto top;
   1354 	}
   1355 	/* Infinite source! */
   1356 	return ('\n');
   1357     }
   1358     if (evalp) {
   1359 	aret = E_SEEK;
   1360 	if ((c = *evalp++) != '\0')
   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) != '\0') {
   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 = l->c_seek;
   1575 	return;
   1576     case A_SEEK:
   1577 	alvec = l->a_seek;
   1578 	alvecp = l->c_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->c_seek = evalp;
   1597 	return;
   1598     case A_SEEK:
   1599 	l->a_seek = alvec;
   1600 	l->c_seek = 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