xref: /csrg-svn/bin/csh/lex.c (revision 69126)
147823Sbostic /*-
260765Sbostic  * Copyright (c) 1980, 1991, 1993
360765Sbostic  *	The Regents of the University of California.  All rights reserved.
447823Sbostic  *
547823Sbostic  * %sccs.include.redist.c%
621937Sdist  */
721937Sdist 
817148Ssam #ifndef lint
9*69126Schristos static char sccsid[] = "@(#)lex.c	8.2 (Berkeley) 04/29/95";
1050028Sbostic #endif /* not lint */
111299Sbill 
1250028Sbostic #include <sys/types.h>
1350028Sbostic #include <sys/ioctl.h>
1450028Sbostic #include <termios.h>
1550028Sbostic #include <errno.h>
1650028Sbostic #include <stdlib.h>
1750028Sbostic #include <string.h>
1850028Sbostic #include <unistd.h>
1950033Schristos #if __STDC__
2050033Schristos # include <stdarg.h>
2150033Schristos #else
2250033Schristos # include <varargs.h>
2350033Schristos #endif
2450033Schristos 
2550023Sbostic #include "csh.h"
2650023Sbostic #include "extern.h"
271299Sbill 
281299Sbill /*
291299Sbill  * These lexical routines read input and form lists of words.
301299Sbill  * There is some involved processing here, because of the complications
311299Sbill  * of input buffering, and especially because of history substitution.
321299Sbill  */
331299Sbill 
3450024Schristos static Char	*word __P((void));
3550024Schristos static int	 getC1 __P((int));
3650024Schristos static void	 getdol __P((void));
3750024Schristos static void	 getexcl __P((int));
3851437Sleres static struct Hist
3950024Schristos 		*findev __P((Char *, bool));
4050024Schristos static void	 setexclp __P((Char *));
4150024Schristos static int	 bgetc __P((void));
4250024Schristos static void	 bfree __P((void));
4351437Sleres static struct wordent
4450024Schristos 		*gethent __P((int));
4550024Schristos static int	 matchs __P((Char *, Char *));
4650024Schristos static int	 getsel __P((int *, int *, int));
4751437Sleres static struct wordent
4850024Schristos 		*getsub __P((struct wordent *));
4951437Sleres static Char	*subword __P((Char *, int, bool *));
5051437Sleres static struct wordent
5150024Schristos 		*dosub __P((int, struct wordent *, bool));
521299Sbill 
531299Sbill /*
5449992Sbostic  * Peekc is a peek character for getC, peekread for readc.
551299Sbill  * There is a subtlety here in many places... history routines
561299Sbill  * will read ahead and then insert stuff into the input stream.
571299Sbill  * If they push back a character then they must push it behind
581299Sbill  * the text substituted by the history substitution.  On the other
591299Sbill  * hand in several places we need 2 peek characters.  To make this
601299Sbill  * all work, the history routines read with getC, and make use both
611299Sbill  * of ungetC and unreadc.  The key observation is that the state
621299Sbill  * of getC at the call of a history reference is such that calls
631299Sbill  * to getC from the history routines will always yield calls of
641299Sbill  * readc, unless this peeking is involved.  That is to say that during
651299Sbill  * getexcl the variables lap, exclp, and exclnxt are all zero.
661299Sbill  *
671299Sbill  * Getdol invokes history substitution, hence the extra peek, peekd,
681299Sbill  * which it can ungetD to be before history substitutions.
691299Sbill  */
7049992Sbostic static Char peekc = 0, peekd = 0;
7149992Sbostic static Char peekread = 0;
721299Sbill 
7349992Sbostic /* (Tail of) current word from ! subst */
7450028Sbostic static Char *exclp = NULL;
751299Sbill 
7649992Sbostic /* The rest of the ! subst words */
7750028Sbostic static struct wordent *exclnxt = NULL;
7849992Sbostic 
7949992Sbostic /* Count of remaining words in ! subst */
8049992Sbostic static int exclc = 0;
8149992Sbostic 
8249992Sbostic /* "Globp" for alias resubstitution */
8351526Schristos Char *alvecp = NULL;
8450944Schristos int aret = F_SEEK;
8549992Sbostic 
861299Sbill /*
8749992Sbostic  * Labuf implements a general buffer for lookahead during lexical operations.
8849992Sbostic  * Text which is to be placed in the input stream can be stuck here.
8949992Sbostic  * We stick parsed ahead $ constructs during initial input,
9049992Sbostic  * process id's from `$$', and modified variable values (from qualifiers
9149992Sbostic  * during expansion in sh.dol.c) here.
9249992Sbostic  */
9349992Sbostic static Char labuf[BUFSIZ];
9449992Sbostic 
9549992Sbostic /*
961299Sbill  * Lex returns to its caller not only a wordlist (as a "var" parameter)
971299Sbill  * but also whether a history substitution occurred.  This is used in
981299Sbill  * the main (process) routine to determine whether to echo, and also
991299Sbill  * when called by the alias routine to determine whether to keep the
1001299Sbill  * argument list.
1011299Sbill  */
10249992Sbostic static bool hadhist = 0;
1031299Sbill 
10449992Sbostic /*
10549992Sbostic  * Avoid alias expansion recursion via \!#
10649992Sbostic  */
10749992Sbostic int     hleft;
10849992Sbostic 
10949992Sbostic static Char getCtmp;
11049992Sbostic 
11117517Sedward #define getC(f)		((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
1121299Sbill #define	ungetC(c)	peekc = c
1131299Sbill #define	ungetD(c)	peekd = c
1141299Sbill 
11549992Sbostic int
lex(hp)1161299Sbill lex(hp)
11749992Sbostic     register struct wordent *hp;
1181299Sbill {
11949992Sbostic     register struct wordent *wdp;
12049992Sbostic     int     c;
1211299Sbill 
12250944Schristos     btell(&lineloc);
12349992Sbostic     hp->next = hp->prev = hp;
12449992Sbostic     hp->word = STRNULL;
12550944Schristos     hadhist = 0;
12649992Sbostic     do
12749992Sbostic 	c = readc(0);
12849992Sbostic     while (c == ' ' || c == '\t');
12949992Sbostic     if (c == HISTSUB && intty)
13049992Sbostic 	/* ^lef^rit	from tty is short !:s^lef^rit */
13149992Sbostic 	getexcl(c);
13249992Sbostic     else
13349992Sbostic 	unreadc(c);
13449992Sbostic     wdp = hp;
13549992Sbostic     /*
13649992Sbostic      * The following loop is written so that the links needed by freelex will
13749992Sbostic      * be ready and rarin to go even if it is interrupted.
13849992Sbostic      */
13949992Sbostic     do {
14049992Sbostic 	register struct wordent *new;
1411299Sbill 
14249992Sbostic 	new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
14349992Sbostic 	new->word = 0;
14449992Sbostic 	new->prev = wdp;
14549992Sbostic 	new->next = hp;
14649992Sbostic 	wdp->next = new;
14749992Sbostic 	wdp = new;
14849992Sbostic 	wdp->word = word();
14949992Sbostic     } while (wdp->word[0] != '\n');
15049992Sbostic     hp->prev = wdp;
15149992Sbostic     return (hadhist);
1521299Sbill }
1531299Sbill 
15449992Sbostic void
prlex(fp,sp0)15550439Schristos prlex(fp, sp0)
15650439Schristos     FILE *fp;
15749992Sbostic     struct wordent *sp0;
1581299Sbill {
15949992Sbostic     register struct wordent *sp = sp0->next;
1601299Sbill 
16149992Sbostic     for (;;) {
16251589Schristos 	(void) fprintf(fp, "%s", vis_str(sp->word));
16349992Sbostic 	sp = sp->next;
16449992Sbostic 	if (sp == sp0)
16549992Sbostic 	    break;
16649992Sbostic 	if (sp->word[0] != '\n')
16750439Schristos 	    (void) fputc(' ', fp);
16849992Sbostic     }
1691299Sbill }
1701299Sbill 
17149992Sbostic void
copylex(hp,fp)1721299Sbill copylex(hp, fp)
17349992Sbostic     register struct wordent *hp;
17449992Sbostic     register struct wordent *fp;
1751299Sbill {
17649992Sbostic     register struct wordent *wdp;
1771299Sbill 
17849992Sbostic     wdp = hp;
17949992Sbostic     fp = fp->next;
18049992Sbostic     do {
18149992Sbostic 	register struct wordent *new;
18249992Sbostic 
18349992Sbostic 	new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
18449992Sbostic 	new->prev = wdp;
18549992Sbostic 	new->next = hp;
18649992Sbostic 	wdp->next = new;
18749992Sbostic 	wdp = new;
18849992Sbostic 	wdp->word = Strsave(fp->word);
1891299Sbill 	fp = fp->next;
19049992Sbostic     } while (wdp->word[0] != '\n');
19149992Sbostic     hp->prev = wdp;
1921299Sbill }
1931299Sbill 
19449992Sbostic void
freelex(vp)1951299Sbill freelex(vp)
19649992Sbostic     register struct wordent *vp;
1971299Sbill {
19849992Sbostic     register struct wordent *fp;
1991299Sbill 
20049992Sbostic     while (vp->next != vp) {
20149992Sbostic 	fp = vp->next;
20249992Sbostic 	vp->next = fp->next;
20349992Sbostic 	xfree((ptr_t) fp->word);
20449992Sbostic 	xfree((ptr_t) fp);
20549992Sbostic     }
20649992Sbostic     vp->prev = vp;
2071299Sbill }
2081299Sbill 
20949992Sbostic static Char *
word()2101299Sbill word()
2111299Sbill {
21249992Sbostic     register Char c, c1;
21349992Sbostic     register Char *wp;
21449992Sbostic     Char    wbuf[BUFSIZ];
21549992Sbostic     register bool dolflg;
21649992Sbostic     register int i;
2171299Sbill 
21849992Sbostic     wp = wbuf;
21949992Sbostic     i = BUFSIZ - 4;
2201299Sbill loop:
22151437Sleres     while ((c = getC(DOALL)) == ' ' || c == '\t')
22251437Sleres 	continue;
22349992Sbostic     if (cmap(c, _META | _ESC))
22449992Sbostic 	switch (c) {
22549992Sbostic 	case '&':
22649992Sbostic 	case '|':
22749992Sbostic 	case '<':
22849992Sbostic 	case '>':
22949992Sbostic 	    *wp++ = c;
23049992Sbostic 	    c1 = getC(DOALL);
23149992Sbostic 	    if (c1 == c)
23249992Sbostic 		*wp++ = c1;
23349992Sbostic 	    else
23449992Sbostic 		ungetC(c1);
23549992Sbostic 	    goto ret;
2361299Sbill 
23749992Sbostic 	case '#':
23849992Sbostic 	    if (intty)
23949992Sbostic 		break;
24049992Sbostic 	    c = 0;
24149992Sbostic 	    do {
24249992Sbostic 		c1 = c;
24349992Sbostic 		c = getC(0);
24449992Sbostic 	    } while (c != '\n');
24549992Sbostic 	    if (c1 == '\\')
24649992Sbostic 		goto loop;
24749992Sbostic 	    /* fall into ... */
24817517Sedward 
24949992Sbostic 	case ';':
25049992Sbostic 	case '(':
25149992Sbostic 	case ')':
25249992Sbostic 	case '\n':
25349992Sbostic 	    *wp++ = c;
25449992Sbostic 	    goto ret;
2551299Sbill 
25649992Sbostic 	case '\\':
25749992Sbostic 	    c = getC(0);
25849992Sbostic 	    if (c == '\n') {
25949992Sbostic 		if (onelflg == 1)
26049992Sbostic 		    onelflg = 2;
26149992Sbostic 		goto loop;
26249992Sbostic 	    }
26349992Sbostic 	    if (c != HIST)
26449992Sbostic 		*wp++ = '\\', --i;
26549992Sbostic 	    c |= QUOTE;
26649992Sbostic 	}
26749992Sbostic     c1 = 0;
26849992Sbostic     dolflg = DOALL;
26949992Sbostic     for (;;) {
27049992Sbostic 	if (c1) {
27149992Sbostic 	    if (c == c1) {
27249992Sbostic 		c1 = 0;
27349992Sbostic 		dolflg = DOALL;
27449992Sbostic 	    }
27549992Sbostic 	    else if (c == '\\') {
27649992Sbostic 		c = getC(0);
27749992Sbostic 		if (c == HIST)
27849992Sbostic 		    c |= QUOTE;
27949992Sbostic 		else {
28049992Sbostic 		    if (c == '\n')
28149992Sbostic 			/*
28249992Sbostic 			 * if (c1 == '`') c = ' '; else
28349992Sbostic 			 */
2841299Sbill 			c |= QUOTE;
28549992Sbostic 		    ungetC(c);
28649992Sbostic 		    c = '\\';
2871299Sbill 		}
28849992Sbostic 	    }
28949992Sbostic 	    else if (c == '\n') {
29049992Sbostic 		seterror(ERR_UNMATCHED, c1);
29149992Sbostic 		ungetC(c);
29249992Sbostic 		break;
29349992Sbostic 	    }
29449992Sbostic 	}
29560488Schristos 	else if (cmap(c, _META | _QF | _QB | _ESC)) {
29649992Sbostic 	    if (c == '\\') {
29749992Sbostic 		c = getC(0);
29849992Sbostic 		if (c == '\n') {
29949992Sbostic 		    if (onelflg == 1)
30049992Sbostic 			onelflg = 2;
30149992Sbostic 		    break;
3021299Sbill 		}
30349992Sbostic 		if (c != HIST)
30449992Sbostic 		    *wp++ = '\\', --i;
30549992Sbostic 		c |= QUOTE;
30649992Sbostic 	    }
30760488Schristos 	    else if (cmap(c, _QF | _QB)) {	/* '"` */
30849992Sbostic 		c1 = c;
30949992Sbostic 		dolflg = c == '"' ? DOALL : DOEXCL;
31049992Sbostic 	    }
31149992Sbostic 	    else if (c != '#' || !intty) {
31249992Sbostic 		ungetC(c);
31349992Sbostic 		break;
31449992Sbostic 	    }
3151299Sbill 	}
31649992Sbostic 	if (--i > 0) {
31749992Sbostic 	    *wp++ = c;
31849992Sbostic 	    c = getC(dolflg);
31949992Sbostic 	}
32049992Sbostic 	else {
32149992Sbostic 	    seterror(ERR_WTOOLONG);
32249992Sbostic 	    wp = &wbuf[1];
32349992Sbostic 	    break;
32449992Sbostic 	}
32549992Sbostic     }
3261299Sbill ret:
32749992Sbostic     *wp = 0;
32849992Sbostic     return (Strsave(wbuf));
3291299Sbill }
3301299Sbill 
33149992Sbostic static int
getC1(flag)33217517Sedward getC1(flag)
33349992Sbostic     register int flag;
3341299Sbill {
33549992Sbostic     register Char c;
3361299Sbill 
33749992Sbostic     while (1) {
33860237Schristos 	if ((c = peekc) != '\0') {
33949992Sbostic 	    peekc = 0;
34049992Sbostic 	    return (c);
3411299Sbill 	}
3421299Sbill 	if (lap) {
34349992Sbostic 	    if ((c = *lap++) == 0)
34449992Sbostic 		lap = 0;
34549992Sbostic 	    else {
34660488Schristos 		if (cmap(c, _META | _QF | _QB))
34749992Sbostic 		    c |= QUOTE;
34849992Sbostic 		return (c);
34949992Sbostic 	    }
3501299Sbill 	}
35160237Schristos 	if ((c = peekd) != '\0') {
35249992Sbostic 	    peekd = 0;
35349992Sbostic 	    return (c);
3541299Sbill 	}
3551299Sbill 	if (exclp) {
35660237Schristos 	    if ((c = *exclp++) != '\0')
35749992Sbostic 		return (c);
35849992Sbostic 	    if (exclnxt && --exclc >= 0) {
35949992Sbostic 		exclnxt = exclnxt->next;
36049992Sbostic 		setexclp(exclnxt->word);
36149992Sbostic 		return (' ');
36249992Sbostic 	    }
36349992Sbostic 	    exclp = 0;
36449992Sbostic 	    exclnxt = 0;
3651299Sbill 	}
3661299Sbill 	if (exclnxt) {
36749992Sbostic 	    exclnxt = exclnxt->next;
36849992Sbostic 	    if (--exclc < 0)
36949992Sbostic 		exclnxt = 0;
37049992Sbostic 	    else
37149992Sbostic 		setexclp(exclnxt->word);
37249992Sbostic 	    continue;
3731299Sbill 	}
3741299Sbill 	c = readc(0);
3751299Sbill 	if (c == '$' && (flag & DODOL)) {
37649992Sbostic 	    getdol();
37749992Sbostic 	    continue;
3781299Sbill 	}
3791299Sbill 	if (c == HIST && (flag & DOEXCL)) {
38049992Sbostic 	    getexcl(0);
38149992Sbostic 	    continue;
3821299Sbill 	}
38349992Sbostic 	break;
38449992Sbostic     }
38549992Sbostic     return (c);
3861299Sbill }
3871299Sbill 
38849992Sbostic static void
getdol()3891299Sbill getdol()
3901299Sbill {
39149992Sbostic     register Char *np, *ep;
39249992Sbostic     Char    name[4 * MAXVARLEN + 1];
39349992Sbostic     register int c;
39449992Sbostic     int     sc;
39549992Sbostic     bool    special = 0, toolong;
3961299Sbill 
39749992Sbostic     np = name, *np++ = '$';
39849992Sbostic     c = sc = getC(DOEXCL);
39949992Sbostic     if (any("\t \n", c)) {
40049992Sbostic 	ungetD(c);
40149992Sbostic 	ungetC('$' | QUOTE);
40249992Sbostic 	return;
40349992Sbostic     }
40449992Sbostic     if (c == '{')
40549992Sbostic 	*np++ = c, c = getC(DOEXCL);
40649992Sbostic     if (c == '#' || c == '?')
40749992Sbostic 	special++, *np++ = c, c = getC(DOEXCL);
40849992Sbostic     *np++ = c;
40949992Sbostic     switch (c) {
4101299Sbill 
41149992Sbostic     case '<':
41249992Sbostic     case '$':
41351526Schristos     case '!':
41449992Sbostic 	if (special)
41549992Sbostic 	    seterror(ERR_SPDOLLT);
41649992Sbostic 	*np = 0;
41749992Sbostic 	addla(name);
41849992Sbostic 	return;
4191299Sbill 
42049992Sbostic     case '\n':
42149992Sbostic 	ungetD(c);
42249992Sbostic 	np--;
42349992Sbostic 	seterror(ERR_NEWLINE);
42449992Sbostic 	*np = 0;
42549992Sbostic 	addla(name);
42649992Sbostic 	return;
4271299Sbill 
42849992Sbostic     case '*':
42949992Sbostic 	if (special)
43049992Sbostic 	    seterror(ERR_SPSTAR);
43149992Sbostic 	*np = 0;
43249992Sbostic 	addla(name);
43349992Sbostic 	return;
43449992Sbostic 
43549992Sbostic     default:
43649992Sbostic 	toolong = 0;
43749992Sbostic 	if (Isdigit(c)) {
43849992Sbostic #ifdef notdef
43949992Sbostic 	    /* let $?0 pass for now */
44049992Sbostic 	    if (special) {
44149992Sbostic 		seterror(ERR_DIGIT);
44249992Sbostic 		*np = 0;
44349992Sbostic 		addla(name);
44449992Sbostic 		return;
44549992Sbostic 	    }
44649992Sbostic #endif
44749992Sbostic 	    /* we know that np < &name[4] */
44849992Sbostic 	    ep = &np[MAXVARLEN];
44960237Schristos 	    while ((c = getC(DOEXCL)) != '\0'){
45049992Sbostic 		if (!Isdigit(c))
45149992Sbostic 		    break;
45249992Sbostic 		if (np < ep)
45349992Sbostic 		    *np++ = c;
4541299Sbill 		else
45549992Sbostic 		    toolong = 1;
45649992Sbostic 	    }
4571299Sbill 	}
45849992Sbostic 	else if (letter(c)) {
45949992Sbostic 	    /* we know that np < &name[4] */
46049992Sbostic 	    ep = &np[MAXVARLEN];
46149992Sbostic 	    toolong = 0;
46260237Schristos 	    while ((c = getC(DOEXCL)) != '\0') {
46349992Sbostic 		/* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
46449992Sbostic 		if (!letter(c) && !Isdigit(c))
46549992Sbostic 		    break;
46649992Sbostic 		if (np < ep)
46749992Sbostic 		    *np++ = c;
46849992Sbostic 		else
46949992Sbostic 		    toolong = 1;
47049992Sbostic 	    }
4711299Sbill 	}
47249992Sbostic 	else {
47349992Sbostic 	    *np = 0;
47449992Sbostic 	    seterror(ERR_VARILL);
47549992Sbostic 	    addla(name);
47649992Sbostic 	    return;
47749992Sbostic 	}
47849992Sbostic 	if (toolong) {
47949992Sbostic 	    seterror(ERR_VARTOOLONG);
48049992Sbostic 	    *np = 0;
48149992Sbostic 	    addla(name);
48249992Sbostic 	    return;
48349992Sbostic 	}
48449992Sbostic 	break;
48549992Sbostic     }
48649992Sbostic     if (c == '[') {
48749992Sbostic 	*np++ = c;
48849992Sbostic 	/*
48949992Sbostic 	 * Name up to here is a max of MAXVARLEN + 8.
49049992Sbostic 	 */
49149992Sbostic 	ep = &np[2 * MAXVARLEN + 8];
49249992Sbostic 	do {
49349992Sbostic 	    /*
49449992Sbostic 	     * Michael Greim: Allow $ expansion to take place in selector
49549992Sbostic 	     * expressions. (limits the number of characters returned)
49649992Sbostic 	     */
49749992Sbostic 	    c = getC(DOEXCL | DODOL);
49849992Sbostic 	    if (c == '\n') {
4991299Sbill 		ungetD(c);
50049992Sbostic 		np--;
50149992Sbostic 		seterror(ERR_NLINDEX);
50249992Sbostic 		*np = 0;
50349992Sbostic 		addla(name);
50449992Sbostic 		return;
50549992Sbostic 	    }
50649992Sbostic 	    if (np < ep)
5071299Sbill 		*np++ = c;
50849992Sbostic 	} while (c != ']');
50949992Sbostic 	*np = '\0';
51049992Sbostic 	if (np >= ep) {
51149992Sbostic 	    seterror(ERR_SELOVFL);
51249992Sbostic 	    addla(name);
51349992Sbostic 	    return;
5141299Sbill 	}
51549992Sbostic 	c = getC(DOEXCL);
51649992Sbostic     }
51749992Sbostic     /*
51849992Sbostic      * Name up to here is a max of 2 * MAXVARLEN + 8.
51949992Sbostic      */
52049992Sbostic     if (c == ':') {
52149992Sbostic 	/*
52249992Sbostic 	 * if the :g modifier is followed by a newline, then error right away!
52349992Sbostic 	 * -strike
52449992Sbostic 	 */
5251299Sbill 
52651526Schristos 	int     gmodflag = 0, amodflag = 0;
52749992Sbostic 
52850464Schristos 	do {
52950464Schristos 	    *np++ = c, c = getC(DOEXCL);
53051526Schristos 	    if (c == 'g' || c == 'a') {
53151526Schristos 		if (c == 'g')
53251526Schristos 		    gmodflag++;
53351526Schristos 		else
53451526Schristos 		    amodflag++;
53551526Schristos 		*np++ = c; c = getC(DOEXCL);
53651526Schristos 	    }
53751526Schristos 	    if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
53851526Schristos 		if (c == 'g')
53951526Schristos 		    gmodflag++;
54051526Schristos 		else
54151526Schristos 		    amodflag++;
54251526Schristos 		*np++ = c; c = getC(DOEXCL);
54351526Schristos 	    }
54450464Schristos 	    *np++ = c;
54551526Schristos 	    /* scan s// [eichin:19910926.0512EST] */
54651526Schristos 	    if (c == 's') {
54751526Schristos 		int delimcnt = 2;
54851526Schristos 		int delim = getC(0);
54951526Schristos 		*np++ = delim;
55051526Schristos 
55151526Schristos 		if (!delim || letter(delim)
55251526Schristos 		    || Isdigit(delim) || any(" \t\n", delim)) {
55351526Schristos 		    seterror(ERR_BADSUBST);
55451526Schristos 		    break;
55551526Schristos 		}
55651526Schristos 		while ((c = getC(0)) != (-1)) {
55751526Schristos 		    *np++ = c;
55851526Schristos 		    if(c == delim) delimcnt--;
55951526Schristos 		    if(!delimcnt) break;
56051526Schristos 		}
56151526Schristos 		if(delimcnt) {
56251526Schristos 		    seterror(ERR_BADSUBST);
56351526Schristos 		    break;
56451526Schristos 		}
56551526Schristos 		c = 's';
56651526Schristos 	    }
56751526Schristos 	    if (!any("htrqxes", c)) {
56851526Schristos 		if ((amodflag || gmodflag) && c == '\n')
56950464Schristos 		    stderror(ERR_VARSYN);	/* strike */
57050464Schristos 		seterror(ERR_VARMOD, c);
57150464Schristos 		*np = 0;
57250464Schristos 		addla(name);
57350464Schristos 		return;
57450464Schristos 	    }
57549992Sbostic 	}
57650464Schristos 	while ((c = getC(DOEXCL)) == ':');
57750464Schristos 	ungetD(c);
57849992Sbostic     }
57949992Sbostic     else
58049992Sbostic 	ungetD(c);
58149992Sbostic     if (sc == '{') {
58249992Sbostic 	c = getC(DOEXCL);
58349992Sbostic 	if (c != '}') {
58449992Sbostic 	    ungetD(c);
58549992Sbostic 	    seterror(ERR_MISSING, '}');
58649992Sbostic 	    *np = 0;
58749992Sbostic 	    addla(name);
58849992Sbostic 	    return;
58949992Sbostic 	}
59049992Sbostic 	*np++ = c;
59149992Sbostic     }
59249992Sbostic     *np = 0;
59349992Sbostic     addla(name);
59449992Sbostic     return;
5951299Sbill }
5961299Sbill 
59749992Sbostic void
addla(cp)5981299Sbill addla(cp)
59949992Sbostic     Char   *cp;
6001299Sbill {
60149992Sbostic     Char    buf[BUFSIZ];
6021299Sbill 
60349992Sbostic     if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
60449992Sbostic 	(sizeof(labuf) - 4) / sizeof(Char)) {
60549992Sbostic 	seterror(ERR_EXPOVFL);
60649992Sbostic 	return;
60749992Sbostic     }
60849992Sbostic     if (lap)
60949992Sbostic 	(void) Strcpy(buf, lap);
61049992Sbostic     (void) Strcpy(labuf, cp);
61149992Sbostic     if (lap)
61249992Sbostic 	(void) Strcat(labuf, buf);
61349992Sbostic     lap = labuf;
6141299Sbill }
6151299Sbill 
61649992Sbostic static Char lhsb[32];
61749992Sbostic static Char slhs[32];
61849992Sbostic static Char rhsb[64];
61949992Sbostic static int quesarg;
6201299Sbill 
62149992Sbostic static void
getexcl(sc)6221299Sbill getexcl(sc)
62350024Schristos     int    sc;
6241299Sbill {
62549992Sbostic     register struct wordent *hp, *ip;
62649992Sbostic     int     left, right, dol;
62749992Sbostic     register int c;
6281299Sbill 
62949992Sbostic     if (sc == 0) {
63049992Sbostic 	sc = getC(0);
63149992Sbostic 	if (sc != '{') {
63249992Sbostic 	    ungetC(sc);
63349992Sbostic 	    sc = 0;
6341299Sbill 	}
63549992Sbostic     }
63649992Sbostic     quesarg = -1;
63749992Sbostic     lastev = eventno;
63849992Sbostic     hp = gethent(sc);
63949992Sbostic     if (hp == 0)
64049992Sbostic 	return;
64149992Sbostic     hadhist = 1;
64249992Sbostic     dol = 0;
64349992Sbostic     if (hp == alhistp)
64449992Sbostic 	for (ip = hp->next->next; ip != alhistt; ip = ip->next)
64549992Sbostic 	    dol++;
64649992Sbostic     else
64749992Sbostic 	for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
64849992Sbostic 	    dol++;
64949992Sbostic     left = 0, right = dol;
65049992Sbostic     if (sc == HISTSUB) {
65149992Sbostic 	ungetC('s'), unreadc(HISTSUB), c = ':';
65249992Sbostic 	goto subst;
65349992Sbostic     }
65449992Sbostic     c = getC(0);
65549992Sbostic     if (!any(":^$*-%", c))
65649992Sbostic 	goto subst;
65749992Sbostic     left = right = -1;
65849992Sbostic     if (c == ':') {
65949992Sbostic 	c = getC(0);
66049992Sbostic 	unreadc(c);
66149992Sbostic 	if (letter(c) || c == '&') {
66249992Sbostic 	    c = ':';
66349992Sbostic 	    left = 0, right = dol;
66449992Sbostic 	    goto subst;
6651299Sbill 	}
66649992Sbostic     }
66749992Sbostic     else
66849992Sbostic 	ungetC(c);
66949992Sbostic     if (!getsel(&left, &right, dol))
67049992Sbostic 	return;
67149992Sbostic     c = getC(0);
67249992Sbostic     if (c == '*')
67349992Sbostic 	ungetC(c), c = '-';
67449992Sbostic     if (c == '-') {
6751299Sbill 	if (!getsel(&left, &right, dol))
67649992Sbostic 	    return;
6771299Sbill 	c = getC(0);
67849992Sbostic     }
6791299Sbill subst:
68049992Sbostic     exclc = right - left + 1;
68149992Sbostic     while (--left >= 0)
68249992Sbostic 	hp = hp->next;
68349992Sbostic     if (sc == HISTSUB || c == ':') {
68449992Sbostic 	do {
68549992Sbostic 	    hp = getsub(hp);
68649992Sbostic 	    c = getC(0);
68749992Sbostic 	} while (c == ':');
68849992Sbostic     }
68949992Sbostic     unreadc(c);
69049992Sbostic     if (sc == '{') {
69149992Sbostic 	c = getC(0);
69249992Sbostic 	if (c != '}')
69349992Sbostic 	    seterror(ERR_BADBANG);
69449992Sbostic     }
69549992Sbostic     exclnxt = hp;
6961299Sbill }
6971299Sbill 
69849992Sbostic static struct wordent *
getsub(en)6991299Sbill getsub(en)
70049992Sbostic     struct wordent *en;
7011299Sbill {
70249992Sbostic     register Char *cp;
70349992Sbostic     int     delim;
70449992Sbostic     register int c;
70549992Sbostic     int     sc;
70651526Schristos     bool global;
70749992Sbostic     Char    orhsb[sizeof(rhsb) / sizeof(Char)];
7081299Sbill 
70950464Schristos     do {
71050464Schristos 	exclnxt = 0;
71151526Schristos 	global = 0;
71250464Schristos 	sc = c = getC(0);
71351526Schristos 	if (c == 'g' || c == 'a') {
71451526Schristos 	    global |= (c == 'g') ? 1 : 2;
71551526Schristos 	    sc = c = getC(0);
71651526Schristos 	}
71751526Schristos 	if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
71851526Schristos 	    global |= (c == 'g') ? 1 : 2;
71951526Schristos 	    sc = c = getC(0);
72051526Schristos 	}
7211299Sbill 
72250464Schristos 	switch (c) {
72350464Schristos 	case 'p':
72450464Schristos 	    justpr++;
72550464Schristos 	    return (en);
7261299Sbill 
72750464Schristos 	case 'x':
72850464Schristos 	case 'q':
72951526Schristos 	    global |= 1;
7301299Sbill 
73150464Schristos 	    /* fall into ... */
7321299Sbill 
73350464Schristos 	case 'h':
73450464Schristos 	case 'r':
73550464Schristos 	case 't':
73650464Schristos 	case 'e':
73750464Schristos 	    break;
7381299Sbill 
73950464Schristos 	case '&':
74050464Schristos 	    if (slhs[0] == 0) {
74150464Schristos 		seterror(ERR_NOSUBST);
74250464Schristos 		return (en);
74350464Schristos 	    }
74450464Schristos 	    (void) Strcpy(lhsb, slhs);
74550464Schristos 	    break;
7461299Sbill 
74749992Sbostic #ifdef notdef
74850464Schristos 	case '~':
74950464Schristos 	    if (lhsb[0] == 0)
75050464Schristos 		goto badlhs;
75150464Schristos 	    break;
75249992Sbostic #endif
75349992Sbostic 
75450464Schristos 	case 's':
75550464Schristos 	    delim = getC(0);
75650464Schristos 	    if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
75750464Schristos 		unreadc(delim);
75849992Sbostic 		lhsb[0] = 0;
75949992Sbostic 		seterror(ERR_BADSUBST);
76049992Sbostic 		return (en);
76149992Sbostic 	    }
76250464Schristos 	    cp = lhsb;
76350464Schristos 	    for (;;) {
76449992Sbostic 		c = getC(0);
76550464Schristos 		if (c == '\n') {
76650464Schristos 		    unreadc(c);
76750464Schristos 		    break;
76850464Schristos 		}
76950464Schristos 		if (c == delim)
77050464Schristos 		    break;
77150464Schristos 		if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
77250464Schristos 		    lhsb[0] = 0;
77350464Schristos 		    seterror(ERR_BADSUBST);
77450464Schristos 		    return (en);
77550464Schristos 		}
77650464Schristos 		if (c == '\\') {
77750464Schristos 		    c = getC(0);
77850464Schristos 		    if (c != delim && c != '\\')
77950464Schristos 			*cp++ = '\\';
78050464Schristos 		}
78150464Schristos 		*cp++ = c;
78249992Sbostic 	    }
78350464Schristos 	    if (cp != lhsb)
78450464Schristos 		*cp++ = 0;
78550464Schristos 	    else if (lhsb[0] == 0) {
78650464Schristos 		seterror(ERR_LHS);
78750464Schristos 		return (en);
78849992Sbostic 	    }
78950464Schristos 	    cp = rhsb;
79050464Schristos 	    (void) Strcpy(orhsb, cp);
79150464Schristos 	    for (;;) {
79250464Schristos 		c = getC(0);
79350464Schristos 		if (c == '\n') {
79450464Schristos 		    unreadc(c);
79550464Schristos 		    break;
79650464Schristos 		}
79750464Schristos 		if (c == delim)
79850464Schristos 		    break;
79949992Sbostic #ifdef notdef
80050464Schristos 		if (c == '~') {
80151437Sleres 		    if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) /
80250464Schristos 						   sizeof(Char) - 2])
80350464Schristos 			goto toorhs;
80450464Schristos 		    (void) Strcpy(cp, orhsb);
80550464Schristos 		    cp = Strend(cp);
80650464Schristos 		    continue;
80750464Schristos 		}
80849992Sbostic #endif
80950464Schristos 		if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
81050464Schristos 		    seterror(ERR_RHSLONG);
81150464Schristos 		    return (en);
81250464Schristos 		}
81350464Schristos 		if (c == '\\') {
81450464Schristos 		    c = getC(0);
81550464Schristos 		    if (c != delim /* && c != '~' */ )
81650464Schristos 			*cp++ = '\\';
81750464Schristos 		}
81850464Schristos 		*cp++ = c;
81949992Sbostic 	    }
82050464Schristos 	    *cp++ = 0;
82150464Schristos 	    break;
82250464Schristos 
82350464Schristos 	default:
82450464Schristos 	    if (c == '\n')
82550464Schristos 		unreadc(c);
82650464Schristos 	    seterror(ERR_BADBANGMOD, c);
82750464Schristos 	    return (en);
82849992Sbostic 	}
82950464Schristos 	(void) Strcpy(slhs, lhsb);
83050464Schristos 	if (exclc)
83150464Schristos 	    en = dosub(sc, en, global);
83249992Sbostic     }
83350464Schristos     while ((c = getC(0)) == ':');
83450464Schristos     unreadc(c);
83549992Sbostic     return (en);
8361299Sbill }
8371299Sbill 
83849992Sbostic static struct wordent *
dosub(sc,en,global)8391299Sbill dosub(sc, en, global)
84049992Sbostic     int     sc;
84149992Sbostic     struct wordent *en;
84249992Sbostic     bool global;
8431299Sbill {
84449992Sbostic     struct wordent lexi;
84551526Schristos     bool    didsub = 0, didone = 0;
84649992Sbostic     struct wordent *hp = &lexi;
84749992Sbostic     register struct wordent *wdp;
84849992Sbostic     register int i = exclc;
8491299Sbill 
85049992Sbostic     wdp = hp;
85149992Sbostic     while (--i >= 0) {
85251526Schristos 	register struct wordent *new =
85351526Schristos 		(struct wordent *) xcalloc(1, sizeof *wdp);
8541299Sbill 
85549992Sbostic 	new->word = 0;
85649992Sbostic 	new->prev = wdp;
85749992Sbostic 	new->next = hp;
85849992Sbostic 	wdp->next = new;
85949992Sbostic 	wdp = new;
86049992Sbostic 	en = en->next;
86151526Schristos 	if (en->word) {
86251526Schristos 	    Char *tword, *otword;
86351526Schristos 
86451526Schristos 	    if ((global & 1) || didsub == 0) {
86551526Schristos 		tword = subword(en->word, sc, &didone);
86651526Schristos 		if (didone)
86751526Schristos 		    didsub = 1;
86851526Schristos 		if (global & 2) {
86951526Schristos 		    while (didone && tword != STRNULL) {
87051526Schristos 			otword = tword;
87151526Schristos 			tword = subword(otword, sc, &didone);
87251526Schristos 			if (Strcmp(tword, otword) == 0) {
87351526Schristos 			    xfree((ptr_t) otword);
87451526Schristos 			    break;
87551526Schristos 			}
87651526Schristos 			else
87751526Schristos 			    xfree((ptr_t) otword);
87851526Schristos 		    }
87951526Schristos 		}
88051526Schristos 	    }
88151526Schristos 	    else
88251526Schristos 		tword = Strsave(en->word);
88351526Schristos 	    wdp->word = tword;
88451526Schristos 	}
88549992Sbostic     }
88649992Sbostic     if (didsub == 0)
88749992Sbostic 	seterror(ERR_MODFAIL);
88849992Sbostic     hp->prev = wdp;
88949992Sbostic     return (&enthist(-1000, &lexi, 0)->Hlex);
8901299Sbill }
8911299Sbill 
89249992Sbostic static Char *
subword(cp,type,adid)8931299Sbill subword(cp, type, adid)
89449992Sbostic     Char   *cp;
89549992Sbostic     int     type;
89649992Sbostic     bool   *adid;
8971299Sbill {
89849992Sbostic     Char    wbuf[BUFSIZ];
89949992Sbostic     register Char *wp, *mp, *np;
90049992Sbostic     register int i;
9011299Sbill 
90251526Schristos     *adid = 0;
90349992Sbostic     switch (type) {
9041299Sbill 
90549992Sbostic     case 'r':
90649992Sbostic     case 'e':
90749992Sbostic     case 'h':
90849992Sbostic     case 't':
90949992Sbostic     case 'q':
91049992Sbostic     case 'x':
91149992Sbostic 	wp = domod(cp, type);
91249992Sbostic 	if (wp == 0)
91349992Sbostic 	    return (Strsave(cp));
91449992Sbostic 	*adid = 1;
91549992Sbostic 	return (wp);
9161299Sbill 
91749992Sbostic     default:
91849992Sbostic 	wp = wbuf;
91949992Sbostic 	i = BUFSIZ - 4;
92049992Sbostic 	for (mp = cp; *mp; mp++)
92149992Sbostic 	    if (matchs(mp, lhsb)) {
92249992Sbostic 		for (np = cp; np < mp;)
92349992Sbostic 		    *wp++ = *np++, --i;
92449992Sbostic 		for (np = rhsb; *np; np++)
92549992Sbostic 		    switch (*np) {
9261299Sbill 
92749992Sbostic 		    case '\\':
92849992Sbostic 			if (np[1] == '&')
92949992Sbostic 			    np++;
93049992Sbostic 			/* fall into ... */
9311299Sbill 
93249992Sbostic 		    default:
93349992Sbostic 			if (--i < 0) {
93449992Sbostic 			    seterror(ERR_SUBOVFL);
93549992Sbostic 			    return (STRNULL);
93649992Sbostic 			}
93749992Sbostic 			*wp++ = *np;
93849992Sbostic 			continue;
9391299Sbill 
94049992Sbostic 		    case '&':
94149992Sbostic 			i -= Strlen(lhsb);
94249992Sbostic 			if (i < 0) {
94349992Sbostic 			    seterror(ERR_SUBOVFL);
94449992Sbostic 			    return (STRNULL);
9451299Sbill 			}
94649992Sbostic 			*wp = 0;
94749992Sbostic 			(void) Strcat(wp, lhsb);
94849992Sbostic 			wp = Strend(wp);
94949992Sbostic 			continue;
95049992Sbostic 		    }
95149992Sbostic 		mp += Strlen(lhsb);
95249992Sbostic 		i -= Strlen(mp);
95349992Sbostic 		if (i < 0) {
95449992Sbostic 		    seterror(ERR_SUBOVFL);
95549992Sbostic 		    return (STRNULL);
95649992Sbostic 		}
95749992Sbostic 		*wp = 0;
95849992Sbostic 		(void) Strcat(wp, mp);
95949992Sbostic 		*adid = 1;
96049992Sbostic 		return (Strsave(wbuf));
96149992Sbostic 	    }
96249992Sbostic 	return (Strsave(cp));
96349992Sbostic     }
9641299Sbill }
9651299Sbill 
96649992Sbostic Char   *
domod(cp,type)9671299Sbill domod(cp, type)
96849992Sbostic     Char   *cp;
96949992Sbostic     int     type;
9701299Sbill {
97149992Sbostic     register Char *wp, *xp;
97249992Sbostic     register int c;
9731299Sbill 
97449992Sbostic     switch (type) {
9751299Sbill 
97649992Sbostic     case 'x':
97749992Sbostic     case 'q':
97849992Sbostic 	wp = Strsave(cp);
97960237Schristos 	for (xp = wp; (c = *xp) != '\0'; xp++)
98049992Sbostic 	    if ((c != ' ' && c != '\t') || type == 'q')
98149992Sbostic 		*xp |= QUOTE;
98249992Sbostic 	return (wp);
9831299Sbill 
98449992Sbostic     case 'h':
98549992Sbostic     case 't':
98649992Sbostic 	if (!any(short2str(cp), '/'))
98749992Sbostic 	    return (type == 't' ? Strsave(cp) : 0);
98849992Sbostic 	wp = Strend(cp);
98949992Sbostic 	while (*--wp != '/')
99049992Sbostic 	    continue;
99149992Sbostic 	if (type == 'h')
99249992Sbostic 	    xp = Strsave(cp), xp[wp - cp] = 0;
99349992Sbostic 	else
99449992Sbostic 	    xp = Strsave(wp + 1);
99549992Sbostic 	return (xp);
99649992Sbostic 
99749992Sbostic     case 'e':
99849992Sbostic     case 'r':
99949992Sbostic 	wp = Strend(cp);
100049992Sbostic 	for (wp--; wp >= cp && *wp != '/'; wp--)
100149992Sbostic 	    if (*wp == '.') {
100249992Sbostic 		if (type == 'e')
100349992Sbostic 		    xp = Strsave(wp + 1);
10041299Sbill 		else
100549992Sbostic 		    xp = Strsave(cp), xp[wp - cp] = 0;
10061299Sbill 		return (xp);
100749992Sbostic 	    }
100849992Sbostic 	return (Strsave(type == 'e' ? STRNULL : cp));
100951526Schristos     default:
101051526Schristos 	break;
101149992Sbostic     }
101249992Sbostic     return (0);
10131299Sbill }
10141299Sbill 
101549992Sbostic static int
matchs(str,pat)10161299Sbill matchs(str, pat)
101749992Sbostic     register Char *str, *pat;
10181299Sbill {
101949992Sbostic     while (*str && *pat && *str == *pat)
102049992Sbostic 	str++, pat++;
102149992Sbostic     return (*pat == 0);
10221299Sbill }
10231299Sbill 
102449992Sbostic static int
getsel(al,ar,dol)10251299Sbill getsel(al, ar, dol)
102649992Sbostic     register int *al, *ar;
102749992Sbostic     int     dol;
10281299Sbill {
102949992Sbostic     register int c = getC(0);
103049992Sbostic     register int i;
103149992Sbostic     bool    first = *al < 0;
10321299Sbill 
103349992Sbostic     switch (c) {
10341299Sbill 
103549992Sbostic     case '%':
103649992Sbostic 	if (quesarg == -1) {
103749992Sbostic 	    seterror(ERR_BADBANGARG);
103849992Sbostic 	    return (0);
103949992Sbostic 	}
104049992Sbostic 	if (*al < 0)
104149992Sbostic 	    *al = quesarg;
104249992Sbostic 	*ar = quesarg;
104349992Sbostic 	break;
10441299Sbill 
104549992Sbostic     case '-':
104649992Sbostic 	if (*al < 0) {
104749992Sbostic 	    *al = 0;
104849992Sbostic 	    *ar = dol - 1;
104949992Sbostic 	    unreadc(c);
105049992Sbostic 	}
105149992Sbostic 	return (1);
10521299Sbill 
105349992Sbostic     case '^':
105449992Sbostic 	if (*al < 0)
105549992Sbostic 	    *al = 1;
105649992Sbostic 	*ar = 1;
105749992Sbostic 	break;
10581299Sbill 
105949992Sbostic     case '$':
106049992Sbostic 	if (*al < 0)
106149992Sbostic 	    *al = dol;
106249992Sbostic 	*ar = dol;
106349992Sbostic 	break;
10641299Sbill 
106549992Sbostic     case '*':
106649992Sbostic 	if (*al < 0)
106749992Sbostic 	    *al = 1;
106849992Sbostic 	*ar = dol;
106949992Sbostic 	if (*ar < *al) {
107049992Sbostic 	    *ar = 0;
107149992Sbostic 	    *al = 1;
107249992Sbostic 	    return (1);
107349992Sbostic 	}
107449992Sbostic 	break;
10751299Sbill 
107649992Sbostic     default:
107749992Sbostic 	if (Isdigit(c)) {
107849992Sbostic 	    i = 0;
107949992Sbostic 	    while (Isdigit(c)) {
108049992Sbostic 		i = i * 10 + c - '0';
10811299Sbill 		c = getC(0);
108249992Sbostic 	    }
108349992Sbostic 	    if (i < 0)
108449992Sbostic 		i = dol + 1;
108549992Sbostic 	    if (*al < 0)
108649992Sbostic 		*al = i;
108749992Sbostic 	    *ar = i;
10881299Sbill 	}
108949992Sbostic 	else if (*al < 0)
109049992Sbostic 	    *al = 0, *ar = dol;
109149992Sbostic 	else
109249992Sbostic 	    *ar = dol - 1;
109349992Sbostic 	unreadc(c);
109449992Sbostic 	break;
109549992Sbostic     }
109649992Sbostic     if (first) {
109749992Sbostic 	c = getC(0);
109849992Sbostic 	unreadc(c);
109949992Sbostic 	if (any("-$*", c))
110049992Sbostic 	    return (1);
110149992Sbostic     }
110249992Sbostic     if (*al > *ar || *ar > dol) {
110349992Sbostic 	seterror(ERR_BADBANGARG);
110449992Sbostic 	return (0);
110549992Sbostic     }
110649992Sbostic     return (1);
11071299Sbill 
11081299Sbill }
11091299Sbill 
111049992Sbostic static struct wordent *
gethent(sc)11111299Sbill gethent(sc)
111249992Sbostic     int     sc;
11131299Sbill {
111449992Sbostic     register struct Hist *hp;
111549992Sbostic     register Char *np;
111649992Sbostic     register int c;
111749992Sbostic     int     event;
111849992Sbostic     bool    back = 0;
11191299Sbill 
112049992Sbostic     c = sc == HISTSUB ? HIST : getC(0);
112149992Sbostic     if (c == HIST) {
112249992Sbostic 	if (alhistp)
112349992Sbostic 	    return (alhistp);
112449992Sbostic 	event = eventno;
112549992Sbostic     }
112649992Sbostic     else
11271299Sbill 	switch (c) {
11281299Sbill 
11291299Sbill 	case ':':
11301299Sbill 	case '^':
11311299Sbill 	case '$':
11321299Sbill 	case '*':
11331299Sbill 	case '%':
113449992Sbostic 	    ungetC(c);
113549992Sbostic 	    if (lastev == eventno && alhistp)
113649992Sbostic 		return (alhistp);
113749992Sbostic 	    event = lastev;
113849992Sbostic 	    break;
11391299Sbill 
114049992Sbostic 	case '#':		/* !# is command being typed in (mrh) */
114149992Sbostic 	    if (--hleft == 0) {
114249992Sbostic 		seterror(ERR_HISTLOOP);
114349992Sbostic 		return (0);
114449992Sbostic 	    }
114549992Sbostic 	    else
114649992Sbostic 		return (&paraml);
114749992Sbostic 	    /* NOTREACHED */
114849992Sbostic 
11491299Sbill 	case '-':
115049992Sbostic 	    back = 1;
115149992Sbostic 	    c = getC(0);
115249992Sbostic 	    /* FALLSTHROUGH */
11531299Sbill 
11541299Sbill 	default:
115549992Sbostic 	    if (any("(=~", c)) {
11561299Sbill 		unreadc(c);
115749992Sbostic 		ungetC(HIST);
115849992Sbostic 		return (0);
115949992Sbostic 	    }
116049992Sbostic 	    np = lhsb;
116149992Sbostic 	    event = 0;
116260488Schristos 	    while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) {
116349992Sbostic 		if (event != -1 && Isdigit(c))
116449992Sbostic 		    event = event * 10 + c - '0';
116549992Sbostic 		else
116649992Sbostic 		    event = -1;
116749992Sbostic 		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
116849992Sbostic 		    *np++ = c;
116949992Sbostic 		c = getC(0);
117049992Sbostic 	    }
117149992Sbostic 	    unreadc(c);
117249992Sbostic 	    if (np == lhsb) {
117349992Sbostic 		ungetC(HIST);
117449992Sbostic 		return (0);
117549992Sbostic 	    }
117649992Sbostic 	    *np++ = 0;
117749992Sbostic 	    if (event != -1) {
117849992Sbostic 		/*
117949992Sbostic 		 * History had only digits
118049992Sbostic 		 */
118149992Sbostic 		if (back)
118249992Sbostic 		    event = eventno + (alhistp == 0) - (event ? event : 0);
118349992Sbostic 		break;
118449992Sbostic 	    }
118549992Sbostic 	    hp = findev(lhsb, 0);
118649992Sbostic 	    if (hp)
118749992Sbostic 		lastev = hp->Hnum;
118849992Sbostic 	    return (&hp->Hlex);
11891299Sbill 
11901299Sbill 	case '?':
119149992Sbostic 	    np = lhsb;
119249992Sbostic 	    for (;;) {
119349992Sbostic 		c = getC(0);
119449992Sbostic 		if (c == '\n') {
119549992Sbostic 		    unreadc(c);
119649992Sbostic 		    break;
11971299Sbill 		}
119849992Sbostic 		if (c == '?')
119949992Sbostic 		    break;
120049992Sbostic 		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
120149992Sbostic 		    *np++ = c;
120249992Sbostic 	    }
120349992Sbostic 	    if (np == lhsb) {
120449992Sbostic 		if (lhsb[0] == 0) {
120549992Sbostic 		    seterror(ERR_NOSEARCH);
120649992Sbostic 		    return (0);
12071299Sbill 		}
120849992Sbostic 	    }
120949992Sbostic 	    else
121049992Sbostic 		*np++ = 0;
121149992Sbostic 	    hp = findev(lhsb, 1);
121249992Sbostic 	    if (hp)
121349992Sbostic 		lastev = hp->Hnum;
121449992Sbostic 	    return (&hp->Hlex);
12151299Sbill 	}
121649992Sbostic 
121749992Sbostic     for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
121849992Sbostic 	if (hp->Hnum == event) {
121949992Sbostic 	    hp->Href = eventno;
122049992Sbostic 	    lastev = hp->Hnum;
122149992Sbostic 	    return (&hp->Hlex);
122249992Sbostic 	}
122349992Sbostic     np = putn(event);
122451589Schristos     seterror(ERR_NOEVENT, vis_str(np));
122549992Sbostic     return (0);
12261299Sbill }
12271299Sbill 
122849992Sbostic static struct Hist *
findev(cp,anyarg)12291299Sbill findev(cp, anyarg)
123049992Sbostic     Char   *cp;
123149992Sbostic     bool    anyarg;
12321299Sbill {
123349992Sbostic     register struct Hist *hp;
12341299Sbill 
123549992Sbostic     for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
123649992Sbostic 	Char   *dp;
123749992Sbostic 	register Char *p, *q;
123849992Sbostic 	register struct wordent *lp = hp->Hlex.next;
123949992Sbostic 	int     argno = 0;
124017517Sedward 
124149992Sbostic 	/*
124249992Sbostic 	 * The entries added by alias substitution don't have a newline but do
124349992Sbostic 	 * have a negative event number. Savehist() trims off these entries,
124449992Sbostic 	 * but it happens before alias expansion, too early to delete those
124549992Sbostic 	 * from the previous command.
124649992Sbostic 	 */
124749992Sbostic 	if (hp->Hnum < 0)
124849992Sbostic 	    continue;
124949992Sbostic 	if (lp->word[0] == '\n')
125049992Sbostic 	    continue;
125149992Sbostic 	if (!anyarg) {
125249992Sbostic 	    p = cp;
125349992Sbostic 	    q = lp->word;
125449992Sbostic 	    do
125549992Sbostic 		if (!*p)
125649992Sbostic 		    return (hp);
125749992Sbostic 	    while (*p++ == *q++);
125849992Sbostic 	    continue;
125917517Sedward 	}
126049992Sbostic 	do {
126149992Sbostic 	    for (dp = lp->word; *dp; dp++) {
126249992Sbostic 		p = cp;
126349992Sbostic 		q = dp;
126449992Sbostic 		do
126549992Sbostic 		    if (!*p) {
126649992Sbostic 			quesarg = argno;
126749992Sbostic 			return (hp);
126849992Sbostic 		    }
126949992Sbostic 		while (*p++ == *q++);
127049992Sbostic 	    }
127149992Sbostic 	    lp = lp->next;
127249992Sbostic 	    argno++;
127349992Sbostic 	} while (lp->word[0] != '\n');
127449992Sbostic     }
127551589Schristos     seterror(ERR_NOEVENT, vis_str(cp));
127649992Sbostic     return (0);
12771299Sbill }
12781299Sbill 
12791299Sbill 
128049992Sbostic static void
setexclp(cp)12811299Sbill setexclp(cp)
128249992Sbostic     register Char *cp;
12831299Sbill {
128449992Sbostic     if (cp && cp[0] == '\n')
128549992Sbostic 	return;
128649992Sbostic     exclp = cp;
12871299Sbill }
12881299Sbill 
128949992Sbostic void
unreadc(c)12901299Sbill unreadc(c)
129150023Sbostic     int    c;
12921299Sbill {
129349992Sbostic     peekread = c;
12941299Sbill }
12951299Sbill 
129649992Sbostic int
readc(wanteof)12971299Sbill readc(wanteof)
129849992Sbostic     bool    wanteof;
12991299Sbill {
130049992Sbostic     register int c;
130149992Sbostic     static  sincereal;
13021299Sbill 
130350944Schristos     aret = F_SEEK;
130460237Schristos     if ((c = peekread) != '\0') {
130549992Sbostic 	peekread = 0;
130649992Sbostic 	return (c);
130749992Sbostic     }
13081299Sbill top:
130950944Schristos     aret = F_SEEK;
131049992Sbostic     if (alvecp) {
131150944Schristos 	aret = A_SEEK;
131260237Schristos 	if ((c = *alvecp++) != '\0')
131349992Sbostic 	    return (c);
131450895Schristos 	if (alvec && *alvec) {
131550944Schristos 		alvecp = *alvec++;
131650944Schristos 		return (' ');
13171299Sbill 	}
131850944Schristos 	else {
131950944Schristos 	    aret = F_SEEK;
132050944Schristos 	    alvecp = NULL;
132150944Schristos 	    return('\n');
132250944Schristos 	}
132349992Sbostic     }
132449992Sbostic     if (alvec) {
132560237Schristos 	if ((alvecp = *alvec) != '\0') {
132649992Sbostic 	    alvec++;
132749992Sbostic 	    goto top;
13281299Sbill 	}
132949992Sbostic 	/* Infinite source! */
133049992Sbostic 	return ('\n');
133149992Sbostic     }
133249992Sbostic     if (evalp) {
133350944Schristos 	aret = E_SEEK;
133460237Schristos 	if ((c = *evalp++) != '\0')
133549992Sbostic 	    return (c);
133650944Schristos 	if (evalvec && *evalvec) {
133749992Sbostic 	    evalp = *evalvec++;
133849992Sbostic 	    return (' ');
13391299Sbill 	}
134050944Schristos 	aret = F_SEEK;
134149992Sbostic 	evalp = 0;
134249992Sbostic     }
134349992Sbostic     if (evalvec) {
134449992Sbostic 	if (evalvec == (Char **) 1) {
134549992Sbostic 	    doneinp = 1;
134649992Sbostic 	    reset();
134749992Sbostic 	}
134860237Schristos 	if ((evalp = *evalvec) != '\0') {
134949992Sbostic 	    evalvec++;
135049992Sbostic 	    goto top;
135149992Sbostic 	}
135249992Sbostic 	evalvec = (Char **) 1;
135349992Sbostic 	return ('\n');
135449992Sbostic     }
135549992Sbostic     do {
135649992Sbostic 	if (arginp == (Char *) 1 || onelflg == 1) {
135749992Sbostic 	    if (wanteof)
135849992Sbostic 		return (-1);
135949992Sbostic 	    exitstat();
136049992Sbostic 	}
136149992Sbostic 	if (arginp) {
136249992Sbostic 	    if ((c = *arginp++) == 0) {
136349992Sbostic 		arginp = (Char *) 1;
13641299Sbill 		return ('\n');
136549992Sbostic 	    }
136649992Sbostic 	    return (c);
13671299Sbill 	}
13681299Sbill reread:
136949992Sbostic 	c = bgetc();
137049992Sbostic 	if (c < 0) {
137149992Sbostic 	    struct termios tty;
137249992Sbostic 	    if (wanteof)
137349992Sbostic 		return (-1);
137449992Sbostic 	    /* was isatty but raw with ignoreeof yields problems */
137549992Sbostic 	    if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON))
137649992Sbostic 	    {
137749992Sbostic 		/* was 'short' for FILEC */
137849992Sbostic 		int     ctpgrp;
13791299Sbill 
138049992Sbostic 		if (++sincereal > 25)
138149992Sbostic 		    goto oops;
138249992Sbostic 		if (tpgrp != -1 &&
138349992Sbostic 		    (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
138449992Sbostic 		    tpgrp != ctpgrp) {
138549992Sbostic 		    (void) tcsetpgrp(FSHTTY, tpgrp);
138649992Sbostic 		    (void) killpg((pid_t) ctpgrp, SIGHUP);
138751437Sleres 		    (void) fprintf(csherr, "Reset tty pgrp from %d to %d\n",
138850439Schristos 				   ctpgrp, tpgrp);
138949992Sbostic 		    goto reread;
13901299Sbill 		}
139149992Sbostic 		if (adrof(STRignoreeof)) {
139249992Sbostic 		    if (loginsh)
139350439Schristos 			(void) fprintf(csherr,"\nUse \"logout\" to logout.\n");
139449992Sbostic 		    else
139550439Schristos 			(void) fprintf(csherr,"\nUse \"exit\" to leave csh.\n");
139649992Sbostic 		    reset();
139749992Sbostic 		}
139849992Sbostic 		if (chkstop == 0)
139949992Sbostic 		    panystop(1);
140049992Sbostic 	    }
140149992Sbostic     oops:
140249992Sbostic 	    doneinp = 1;
140349992Sbostic 	    reset();
140449992Sbostic 	}
140549992Sbostic 	sincereal = 0;
140649992Sbostic 	if (c == '\n' && onelflg)
140749992Sbostic 	    onelflg--;
140849992Sbostic     } while (c == 0);
140949992Sbostic     return (c);
14101299Sbill }
14111299Sbill 
141249992Sbostic static int
bgetc()14131299Sbill bgetc()
14141299Sbill {
141549992Sbostic     register int buf, off, c;
141649992Sbostic 
141715376Slayer #ifdef FILEC
141849992Sbostic     register int numleft = 0, roomleft;
141949992Sbostic     Char    ttyline[BUFSIZ];
142017148Ssam #endif
142149992Sbostic     char    tbuf[BUFSIZ + 1];
14221299Sbill 
142349992Sbostic     if (cantell) {
142449992Sbostic 	if (fseekp < fbobp || fseekp > feobp) {
142549992Sbostic 	    fbobp = feobp = fseekp;
142649992Sbostic 	    (void) lseek(SHIN, fseekp, L_SET);
14271299Sbill 	}
142849992Sbostic 	if (fseekp == feobp) {
142949992Sbostic 	    int     i;
143049992Sbostic 
143149992Sbostic 	    fbobp = feobp;
143249992Sbostic 	    do
143349992Sbostic 		c = read(SHIN, tbuf, BUFSIZ);
143449992Sbostic 	    while (c < 0 && errno == EINTR);
143549992Sbostic 	    if (c <= 0)
143649992Sbostic 		return (-1);
143749992Sbostic 	    for (i = 0; i < c; i++)
143849992Sbostic 		fbuf[0][i] = (unsigned char) tbuf[i];
143949992Sbostic 	    feobp += c;
144049992Sbostic 	}
144149992Sbostic 	c = fbuf[0][fseekp - fbobp];
144249992Sbostic 	fseekp++;
144349992Sbostic 	return (c);
144449992Sbostic     }
144549992Sbostic 
14461299Sbill again:
144749992Sbostic     buf = (int) fseekp / BUFSIZ;
144849992Sbostic     if (buf >= fblocks) {
144949992Sbostic 	register Char **nfbuf =
145049992Sbostic 	(Char **) xcalloc((size_t) (fblocks + 2),
145149992Sbostic 			  sizeof(Char **));
14521299Sbill 
145349992Sbostic 	if (fbuf) {
145449992Sbostic 	    (void) blkcpy(nfbuf, fbuf);
145549992Sbostic 	    xfree((ptr_t) fbuf);
145649992Sbostic 	}
145749992Sbostic 	fbuf = nfbuf;
145849992Sbostic 	fbuf[fblocks] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
145949992Sbostic 	fblocks++;
146049992Sbostic 	if (!intty)
146149992Sbostic 	    goto again;
146249992Sbostic     }
146349992Sbostic     if (fseekp >= feobp) {
146449992Sbostic 	buf = (int) feobp / BUFSIZ;
146549992Sbostic 	off = (int) feobp % BUFSIZ;
146649992Sbostic 	roomleft = BUFSIZ - off;
146749992Sbostic 
146849992Sbostic #ifdef FILEC
146949992Sbostic 	roomleft = BUFSIZ - off;
147049992Sbostic 	for (;;) {
147149992Sbostic 	    if (filec && intty) {
147249992Sbostic 		c = numleft ? numleft : tenex(ttyline, BUFSIZ);
147349992Sbostic 		if (c > roomleft) {
147449992Sbostic 		    /* start with fresh buffer */
147549992Sbostic 		    feobp = fseekp = fblocks * BUFSIZ;
147649992Sbostic 		    numleft = c;
147749992Sbostic 		    goto again;
14781299Sbill 		}
147949992Sbostic 		if (c > 0)
1480*69126Schristos 		    memmove(fbuf[buf] + off, ttyline, c * sizeof(Char));
148149992Sbostic 		numleft = 0;
148249992Sbostic 	    }
148349992Sbostic 	    else {
148417148Ssam #endif
148549992Sbostic 		c = read(SHIN, tbuf, roomleft);
148649992Sbostic 		if (c > 0) {
148749992Sbostic 		    int     i;
148849992Sbostic 		    Char   *ptr = fbuf[buf] + off;
148917884Sedward 
149049992Sbostic 		    for (i = 0; i < c; i++)
149149992Sbostic 			ptr[i] = (unsigned char) tbuf[i];
149217884Sedward 		}
149349992Sbostic #ifdef FILEC
149449992Sbostic 	    }
149549992Sbostic #endif
149649992Sbostic 	    if (c >= 0)
149749992Sbostic 		break;
149849992Sbostic 	    if (errno == EWOULDBLOCK) {
149949992Sbostic 		int     off = 0;
150049992Sbostic 
150149992Sbostic 		(void) ioctl(SHIN, FIONBIO, (ioctl_t) & off);
150249992Sbostic 	    }
150349992Sbostic 	    else if (errno != EINTR)
150449992Sbostic 		break;
150549992Sbostic 	}
150649992Sbostic 	if (c <= 0)
150749992Sbostic 	    return (-1);
150849992Sbostic 	feobp += c;
150915376Slayer #ifndef FILEC
151049992Sbostic 	goto again;
151117148Ssam #else
151249992Sbostic 	if (filec && !intty)
151349992Sbostic 	    goto again;
151417148Ssam #endif
151549992Sbostic     }
151649992Sbostic     c = fbuf[buf][(int) fseekp % BUFSIZ];
151749992Sbostic     fseekp++;
151849992Sbostic     return (c);
15191299Sbill }
15201299Sbill 
152149992Sbostic static void
bfree()15221299Sbill bfree()
15231299Sbill {
152449992Sbostic     register int sb, i;
15251299Sbill 
152649992Sbostic     if (cantell)
152749992Sbostic 	return;
152849992Sbostic     if (whyles)
152949992Sbostic 	return;
153049992Sbostic     sb = (int) (fseekp - 1) / BUFSIZ;
153149992Sbostic     if (sb > 0) {
153249992Sbostic 	for (i = 0; i < sb; i++)
153349992Sbostic 	    xfree((ptr_t) fbuf[i]);
153449992Sbostic 	(void) blkcpy(fbuf, &fbuf[sb]);
153549992Sbostic 	fseekp -= BUFSIZ * sb;
153649992Sbostic 	feobp -= BUFSIZ * sb;
153749992Sbostic 	fblocks -= sb;
153849992Sbostic     }
15391299Sbill }
15401299Sbill 
154149992Sbostic void
bseek(l)15421299Sbill bseek(l)
154350944Schristos     struct Ain   *l;
154450944Schristos {
154550944Schristos     switch (aret = l->type) {
154650944Schristos     case E_SEEK:
154750944Schristos 	evalvec = l->a_seek;
154858876Schristos 	evalp = l->c_seek;
154950944Schristos 	return;
155050944Schristos     case A_SEEK:
155150944Schristos 	alvec = l->a_seek;
155258876Schristos 	alvecp = l->c_seek;
155350944Schristos 	return;
155451437Sleres     case F_SEEK:
155550944Schristos 	fseekp = l->f_seek;
155650944Schristos 	return;
155750944Schristos     default:
155850944Schristos 	(void) fprintf(csherr, "Bad seek type %d\n", aret);
155950944Schristos 	abort();
156050944Schristos     }
156150944Schristos }
156249992Sbostic 
156350944Schristos void
btell(l)156450944Schristos btell(l)
156550944Schristos     struct Ain *l;
15661299Sbill {
156750944Schristos     switch (l->type = aret) {
156850944Schristos     case E_SEEK:
156950944Schristos 	l->a_seek = evalvec;
157058876Schristos 	l->c_seek = evalp;
157150944Schristos 	return;
157250944Schristos     case A_SEEK:
157350944Schristos 	l->a_seek = alvec;
157458876Schristos 	l->c_seek = alvecp;
157550944Schristos 	return;
157650944Schristos     case F_SEEK:
157750944Schristos 	l->f_seek = fseekp;
157850944Schristos 	l->a_seek = NULL;
157950944Schristos 	return;
158050944Schristos     default:
158150944Schristos 	(void) fprintf(csherr, "Bad seek type %d\n", aret);
158250944Schristos 	abort();
158349992Sbostic     }
15841299Sbill }
15851299Sbill 
158649992Sbostic void
btoeof()15871299Sbill btoeof()
15881299Sbill {
158949992Sbostic     (void) lseek(SHIN, (off_t) 0, L_XTND);
159050948Schristos     aret = F_SEEK;
159149992Sbostic     fseekp = feobp;
159250948Schristos     alvec = NULL;
159350948Schristos     alvecp = NULL;
159450948Schristos     evalvec = NULL;
159550948Schristos     evalp = NULL;
159649992Sbostic     wfree();
159749992Sbostic     bfree();
15981299Sbill }
15991299Sbill 
160049992Sbostic void
settell()16011299Sbill settell()
16021299Sbill {
160349992Sbostic     cantell = 0;
160449992Sbostic     if (arginp || onelflg || intty)
160549992Sbostic 	return;
160649992Sbostic     if (lseek(SHIN, (off_t) 0, L_INCR) < 0 || errno == ESPIPE)
160749992Sbostic 	return;
160849992Sbostic     fbuf = (Char **) xcalloc(2, sizeof(Char **));
160949992Sbostic     fblocks = 1;
161049992Sbostic     fbuf[0] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
161149992Sbostic     fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, L_INCR);
161249992Sbostic     cantell = 1;
161349992Sbostic }
1614