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