sh.lex.c revision 145479
1145479Smp/* $Header: /src/pub/tcsh/sh.lex.c,v 3.62 2004/12/25 21:15:07 christos Exp $ */
259243Sobrien/*
359243Sobrien * sh.lex.c: Lexical analysis into tokens
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien
35145479SmpRCSID("$Id: sh.lex.c,v 3.62 2004/12/25 21:15:07 christos Exp $")
3659243Sobrien
3759243Sobrien#include "ed.h"
38145479Smp
39145479Smp#include <assert.h>
4059243Sobrien/* #define DEBUG_INP */
4159243Sobrien/* #define DEBUG_SEEK */
4259243Sobrien
4359243Sobrien/*
4459243Sobrien * C shell
4559243Sobrien */
4659243Sobrien
4759243Sobrien/*
4859243Sobrien * These lexical routines read input and form lists of words.
4959243Sobrien * There is some involved processing here, because of the complications
5059243Sobrien * of input buffering, and especially because of history substitution.
5159243Sobrien */
52145479Smpstatic	Char		*word		__P((int));
53145479Smpstatic	eChar	 	 getC1		__P((int));
5459243Sobrienstatic	void	 	 getdol		__P((void));
55145479Smpstatic	void	 	 getexcl	__P((Char));
56145479Smpstatic	struct Hist 	*findev		__P((Char *, int));
5759243Sobrienstatic	void	 	 setexclp	__P((Char *));
58145479Smpstatic	eChar	 	 bgetc		__P((void));
5959243Sobrienstatic	void		 balloc		__P((int));
6059243Sobrienstatic	void	 	 bfree		__P((void));
61145479Smpstatic	struct wordent	*gethent	__P((Char));
6259243Sobrienstatic	int	 	 matchs		__P((Char *, Char *));
6359243Sobrienstatic	int	 	 getsel		__P((int *, int *, int));
6459243Sobrienstatic	struct wordent	*getsub		__P((struct wordent *));
65145479Smpstatic	Char 		*subword	__P((Char *, Char, int *));
66145479Smpstatic	struct wordent	*dosub		__P((Char, struct wordent *, int));
67145479Smpstatic	ssize_t		 wide_read	__P((int, Char *, size_t, int));
6859243Sobrien
6959243Sobrien/*
7059243Sobrien * Peekc is a peek character for getC, peekread for readc.
7159243Sobrien * There is a subtlety here in many places... history routines
7259243Sobrien * will read ahead and then insert stuff into the input stream.
7359243Sobrien * If they push back a character then they must push it behind
7459243Sobrien * the text substituted by the history substitution.  On the other
7559243Sobrien * hand in several places we need 2 peek characters.  To make this
7659243Sobrien * all work, the history routines read with getC, and make use both
7759243Sobrien * of ungetC and unreadc.  The key observation is that the state
7859243Sobrien * of getC at the call of a history reference is such that calls
7959243Sobrien * to getC from the history routines will always yield calls of
8059243Sobrien * readc, unless this peeking is involved.  That is to say that during
8159243Sobrien * getexcl the variables lap, exclp, and exclnxt are all zero.
8259243Sobrien *
8359243Sobrien * Getdol invokes history substitution, hence the extra peek, peekd,
8459243Sobrien * which it can ungetD to be before history substitutions.
8559243Sobrien */
8659243Sobrienstatic Char peekc = 0, peekd = 0;
8759243Sobrienstatic Char peekread = 0;
8859243Sobrien
8959243Sobrien/* (Tail of) current word from ! subst */
9059243Sobrienstatic Char *exclp = NULL;
9159243Sobrien
9259243Sobrien/* The rest of the ! subst words */
9359243Sobrienstatic struct wordent *exclnxt = NULL;
9459243Sobrien
9559243Sobrien/* Count of remaining words in ! subst */
9659243Sobrienstatic int exclc = 0;
9759243Sobrien
9859243Sobrien/* "Globp" for alias resubstitution */
9969408Sacheint aret = TCSH_F_SEEK;
10059243Sobrien
10159243Sobrien/*
10259243Sobrien * Labuf implements a general buffer for lookahead during lexical operations.
10359243Sobrien * Text which is to be placed in the input stream can be stuck here.
10459243Sobrien * We stick parsed ahead $ constructs during initial input,
10559243Sobrien * process id's from `$$', and modified variable values (from qualifiers
10659243Sobrien * during expansion in sh.dol.c) here.
10759243Sobrien */
10859243Sobrienstatic Char labuf[BUFSIZE];
10959243Sobrien
11059243Sobrien/*
11159243Sobrien * Lex returns to its caller not only a wordlist (as a "var" parameter)
11259243Sobrien * but also whether a history substitution occurred.  This is used in
11359243Sobrien * the main (process) routine to determine whether to echo, and also
11459243Sobrien * when called by the alias routine to determine whether to keep the
11559243Sobrien * argument list.
11659243Sobrien */
117145479Smpstatic int hadhist = 0;
11859243Sobrien
11959243Sobrien/*
12059243Sobrien * Avoid alias expansion recursion via \!#
12159243Sobrien */
12259243Sobrienint     hleft;
12359243Sobrien
12459243SobrienChar    histline[BUFSIZE + 2];	/* last line input */
12559243Sobrien
12659243Sobrien /* The +2 is to fool hp's optimizer */
127145479Smpint    histvalid = 0;		/* is histline valid */
12859243Sobrienstatic Char *histlinep = NULL;	/* current pointer into histline */
12959243Sobrien
13059243Sobrienstatic Char getCtmp;
13159243Sobrien
132145479Smp#define getC(f)		(((getCtmp = peekc) != '\0') ? (peekc = 0, (eChar)getCtmp) : getC1(f))
13359243Sobrien#define	ungetC(c)	peekc = (Char) c
13459243Sobrien#define	ungetD(c)	peekd = (Char) c
13559243Sobrien
13659243Sobrien/* Use Htime to store timestamps picked up from history file for enthist()
13759243Sobrien * if reading saved history (sg)
13859243Sobrien */
13959243Sobrientime_t Htime = (time_t)0;
14059243Sobrienstatic time_t a2time_t __P((Char *));
14159243Sobrien
14259243Sobrien/*
143145479Smp * special parsing rules apply for source -h
144145479Smp */
145145479Smpextern int enterhist;
146145479Smp
147145479Smp/*
14859243Sobrien * for history event processing
14959243Sobrien * in the command 'echo !?foo?:1 !$' we want the !$ to expand from the line
15059243Sobrien * 'foo' was found instead of the last command
15159243Sobrien */
15259243Sobrienstatic int uselastevent = 1;
15359243Sobrien
15459243Sobrienint
15559243Sobrienlex(hp)
15659243Sobrien    struct wordent *hp;
15759243Sobrien{
15859243Sobrien    struct wordent *wdp;
159145479Smp    eChar    c;
160145479Smp    int     parsehtime = enterhist;
16159243Sobrien
16259243Sobrien
16359243Sobrien    uselastevent = 1;
16459243Sobrien    histvalid = 0;
16559243Sobrien    histlinep = histline;
16659243Sobrien    *histlinep = '\0';
16759243Sobrien
16859243Sobrien    btell(&lineloc);
16959243Sobrien    hp->next = hp->prev = hp;
17059243Sobrien    hp->word = STRNULL;
17159243Sobrien    hadhist = 0;
17259243Sobrien    do
17359243Sobrien	c = readc(0);
17459243Sobrien    while (c == ' ' || c == '\t');
175145479Smp    if (c == (eChar)HISTSUB && intty)
17659243Sobrien	/* ^lef^rit	from tty is short !:s^lef^rit */
17759243Sobrien	getexcl(c);
17859243Sobrien    else
17959243Sobrien	unreadc(c);
18059243Sobrien    wdp = hp;
18159243Sobrien    /*
18259243Sobrien     * The following loop is written so that the links needed by freelex will
18359243Sobrien     * be ready and rarin to go even if it is interrupted.
18459243Sobrien     */
18559243Sobrien    do {
18659243Sobrien	struct wordent *new;
18759243Sobrien
18859243Sobrien	new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
18959243Sobrien	new->word = STRNULL;
19059243Sobrien	new->prev = wdp;
19159243Sobrien	new->next = hp;
19259243Sobrien	wdp->next = new;
19359243Sobrien	hp->prev = new;
19459243Sobrien	wdp = new;
195145479Smp	wdp->word = word(parsehtime);
196145479Smp	parsehtime = 0;
19759243Sobrien    } while (wdp->word[0] != '\n');
19859243Sobrien    if (histlinep < histline + BUFSIZE) {
19959243Sobrien	*histlinep = '\0';
20059243Sobrien	if (histlinep > histline && histlinep[-1] == '\n')
20159243Sobrien	    histlinep[-1] = '\0';
20259243Sobrien	histvalid = 1;
20359243Sobrien    }
20459243Sobrien    else {
20559243Sobrien	histline[BUFSIZE - 1] = '\0';
20659243Sobrien    }
20759243Sobrien
20859243Sobrien    return (hadhist);
20959243Sobrien}
21059243Sobrien
21159243Sobrienstatic time_t
212145479Smpa2time_t(wordx)
213145479Smp    Char *wordx;
21459243Sobrien{
21559243Sobrien    /* Attempt to distinguish timestamps from other possible entries.
21659243Sobrien     * Format: "+NNNNNNNNNN" (10 digits, left padded with ascii '0') */
21759243Sobrien
21859243Sobrien    time_t ret;
21959243Sobrien    Char *s;
22059243Sobrien    int ct;
22159243Sobrien
222145479Smp    if (!wordx || *(s = wordx) != '+')
22359243Sobrien	return (time_t)0;
22459243Sobrien
22559243Sobrien    for (++s, ret = 0, ct = 0; *s; ++s, ++ct)
22659243Sobrien    {
22759243Sobrien	if (!isdigit((unsigned char)*s))
22859243Sobrien	    return (time_t)0;
22959243Sobrien	ret = ret * 10 + (time_t)((unsigned char)*s - '0');
23059243Sobrien    }
23159243Sobrien
23259243Sobrien    if (ct != 10)
23359243Sobrien	return (time_t)0;
23459243Sobrien
23559243Sobrien    return ret;
23659243Sobrien}
23759243Sobrien
23859243Sobrienvoid
23959243Sobrienprlex(sp0)
24059243Sobrien    struct wordent *sp0;
24159243Sobrien{
24259243Sobrien    struct wordent *sp = sp0->next;
24359243Sobrien
24459243Sobrien    for (;;) {
24559243Sobrien	xprintf("%S", sp->word);
24659243Sobrien	sp = sp->next;
24759243Sobrien	if (sp == sp0)
24859243Sobrien	    break;
24959243Sobrien	if (sp->word[0] != '\n')
25059243Sobrien	    xputchar(' ');
25159243Sobrien    }
25259243Sobrien}
25359243Sobrien
25459243Sobrienvoid
25559243Sobriencopylex(hp, fp)
25659243Sobrien    struct wordent *hp;
25759243Sobrien    struct wordent *fp;
25859243Sobrien{
25959243Sobrien    struct wordent *wdp;
26059243Sobrien
26159243Sobrien    wdp = hp;
26259243Sobrien    fp = fp->next;
26359243Sobrien    do {
26459243Sobrien	struct wordent *new;
26559243Sobrien
26659243Sobrien	new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
26759243Sobrien	new->word = STRNULL;
26859243Sobrien	new->prev = wdp;
26959243Sobrien	new->next = hp;
27059243Sobrien	wdp->next = new;
27159243Sobrien	hp->prev = new;
27259243Sobrien	wdp = new;
27359243Sobrien	wdp->word = Strsave(fp->word);
27459243Sobrien	fp = fp->next;
27559243Sobrien    } while (wdp->word[0] != '\n');
27659243Sobrien}
27759243Sobrien
27859243Sobrienvoid
27959243Sobrienfreelex(vp)
28059243Sobrien    struct wordent *vp;
28159243Sobrien{
28259243Sobrien    struct wordent *fp;
28359243Sobrien
28459243Sobrien    while (vp->next != vp) {
28559243Sobrien	fp = vp->next;
28659243Sobrien	vp->next = fp->next;
28759243Sobrien	if (fp->word != STRNULL)
28859243Sobrien	    xfree((ptr_t) fp->word);
28959243Sobrien	xfree((ptr_t) fp);
29059243Sobrien    }
29159243Sobrien    vp->prev = vp;
29259243Sobrien}
29359243Sobrien
29459243Sobrienstatic Char *
295145479Smpword(parsehtime)
296145479Smp    int parsehtime;
29759243Sobrien{
298145479Smp    eChar c, c1;
299145479Smp    Char *wp, *unfinished = 0;
30059243Sobrien    Char    wbuf[BUFSIZE];
30159243Sobrien    Char    hbuf[12];
30259243Sobrien    int	    h;
303145479Smp    int dolflg;
30459243Sobrien    int i;
30559243Sobrien
30659243Sobrien    wp = wbuf;
30759243Sobrien    i = BUFSIZE - 4;
30859243Sobrienloop:
30959243Sobrien    while ((c = getC(DOALL)) == ' ' || c == '\t')
31059243Sobrien	continue;
31159243Sobrien    if (cmap(c, _META | _ESC))
31259243Sobrien	switch (c) {
31359243Sobrien	case '&':
31459243Sobrien	case '|':
31559243Sobrien	case '<':
31659243Sobrien	case '>':
31759243Sobrien	    *wp++ = c;
31859243Sobrien	    c1 = getC(DOALL);
31959243Sobrien	    if (c1 == c)
32059243Sobrien		*wp++ = c1;
32159243Sobrien	    else
32259243Sobrien		ungetC(c1);
32359243Sobrien	    goto ret;
32459243Sobrien
32559243Sobrien	case '#':
326145479Smp	    if (intty || (enterhist && !parsehtime))
32759243Sobrien		break;
32859243Sobrien	    c = 0;
32959243Sobrien	    h = 0;
33059243Sobrien	    do {
33159243Sobrien		c1 = c;
33259243Sobrien		c = getC(0);
333145479Smp		if (h < 11 && parsehtime)
33459243Sobrien		    hbuf[h++] = c;
33559243Sobrien	    } while (c != '\n');
336145479Smp	    if (parsehtime) {
337145479Smp		hbuf[11] = '\0';
338145479Smp		Htime = a2time_t(hbuf);
339145479Smp	    }
34059243Sobrien	    if (c1 == '\\')
34159243Sobrien		goto loop;
34259243Sobrien	    /*FALLTHROUGH*/
34359243Sobrien
34459243Sobrien	case ';':
34559243Sobrien	case '(':
34659243Sobrien	case ')':
34759243Sobrien	case '\n':
34859243Sobrien	    *wp++ = c;
34959243Sobrien	    goto ret;
35059243Sobrien
35159243Sobrien	case '\\':
35259243Sobrien	    c = getC(0);
35359243Sobrien	    if (c == '\n') {
35459243Sobrien		if (onelflg == 1)
35559243Sobrien		    onelflg = 2;
35659243Sobrien		goto loop;
35759243Sobrien	    }
358145479Smp	    if (c != (eChar)HIST)
35959243Sobrien		*wp++ = '\\', --i;
36059243Sobrien	    c |= QUOTE;
36159243Sobrien	default:
36259243Sobrien	    break;
36359243Sobrien	}
36459243Sobrien    c1 = 0;
36559243Sobrien    dolflg = DOALL;
36659243Sobrien    for (;;) {
36759243Sobrien	if (c1) {
36859243Sobrien	    if (c == c1) {
36959243Sobrien		c1 = 0;
37059243Sobrien		dolflg = DOALL;
37159243Sobrien	    }
37259243Sobrien	    else if (c == '\\') {
37359243Sobrien		c = getC(0);
37459243Sobrien/*
37559243Sobrien * PWP: this is dumb, but how all of the other shells work.  If \ quotes
37659243Sobrien * a character OUTSIDE of a set of ''s, why shouldn't it quote EVERY
37759243Sobrien * following character INSIDE a set of ''s.
37859243Sobrien *
37959243Sobrien * Actually, all I really want to be able to say is 'foo\'bar' --> foo'bar
38059243Sobrien */
381145479Smp		if (c == (eChar)HIST)
38259243Sobrien		    c |= QUOTE;
38359243Sobrien		else {
38459243Sobrien		    if (bslash_quote &&
38559243Sobrien			((c == '\'') || (c == '"') ||
38659243Sobrien			 (c == '\\'))) {
38759243Sobrien			c |= QUOTE;
38859243Sobrien		    }
38959243Sobrien		    else {
39059243Sobrien			if (c == '\n')
39159243Sobrien			    /*
39259243Sobrien			     * if (c1 == '`') c = ' '; else
39359243Sobrien			     */
39459243Sobrien			    c |= QUOTE;
39559243Sobrien			ungetC(c);
39659243Sobrien			c = '\\';
39759243Sobrien		    }
39859243Sobrien		}
39959243Sobrien	    }
40059243Sobrien	    else if (c == '\n') {
40159243Sobrien		seterror(ERR_UNMATCHED, c1);
40259243Sobrien		ungetC(c);
40359243Sobrien		break;
40459243Sobrien	    }
40559243Sobrien	}
40659243Sobrien	else if (cmap(c, _META | _QF | _QB | _ESC)) {
40759243Sobrien	    if (c == '\\') {
40859243Sobrien		c = getC(0);
40959243Sobrien		if (c == '\n') {
41059243Sobrien		    if (onelflg == 1)
41159243Sobrien			onelflg = 2;
41259243Sobrien		    break;
41359243Sobrien		}
414145479Smp		if (c != (eChar)HIST)
41559243Sobrien		    *wp++ = '\\', --i;
41659243Sobrien		c |= QUOTE;
41759243Sobrien	    }
41859243Sobrien	    else if (cmap(c, _QF | _QB)) {	/* '"` */
41959243Sobrien		c1 = c;
42059243Sobrien		dolflg = c == '"' ? DOALL : DOEXCL;
42159243Sobrien	    }
422145479Smp	    else if (c != '#' || (!intty && !enterhist)) {
42359243Sobrien		ungetC(c);
42459243Sobrien		break;
42559243Sobrien	    }
42659243Sobrien	}
42759243Sobrien	if (--i > 0) {
42859243Sobrien	    *wp++ = c;
42959243Sobrien	    c = getC(dolflg);
430145479Smp	    if (!unfinished)
431145479Smp		unfinished = wp - 1;
432145479Smp	    switch (NLSFinished(unfinished, wp - unfinished, c)) {
433145479Smp		case 1:
434145479Smp		case 0:
435145479Smp		    c |= QUOTE;
436145479Smp		    break;
437145479Smp		default:
438145479Smp		    unfinished = 0;
439145479Smp		    break;
440145479Smp	    }
44159243Sobrien	}
44259243Sobrien	else {
44359243Sobrien	    seterror(ERR_WTOOLONG);
44459243Sobrien	    wp = &wbuf[1];
44559243Sobrien	    break;
44659243Sobrien	}
44759243Sobrien    }
44859243Sobrienret:
44959243Sobrien    *wp = 0;
45059243Sobrien    return (Strsave(wbuf));
45159243Sobrien}
45259243Sobrien
453145479Smpstatic eChar
45459243SobriengetC1(flag)
45559243Sobrien    int flag;
45659243Sobrien{
457145479Smp    eChar c;
45859243Sobrien
45959243Sobrien    for (;;) {
46059243Sobrien	if ((c = peekc) != 0) {
46159243Sobrien	    peekc = 0;
46259243Sobrien	    return (c);
46359243Sobrien	}
46459243Sobrien	if (lap) {
46559243Sobrien	    if ((c = *lap++) == 0)
46659243Sobrien		lap = 0;
46759243Sobrien	    else {
46859243Sobrien		if (cmap(c, _META | _QF | _QB))
46959243Sobrien		    c |= QUOTE;
47059243Sobrien		return (c);
47159243Sobrien	    }
47259243Sobrien	}
47359243Sobrien	if ((c = peekd) != 0) {
47459243Sobrien	    peekd = 0;
47559243Sobrien	    return (c);
47659243Sobrien	}
47759243Sobrien	if (exclp) {
47859243Sobrien	    if ((c = *exclp++) != 0)
47959243Sobrien		return (c);
48059243Sobrien	    if (exclnxt && --exclc >= 0) {
48159243Sobrien		exclnxt = exclnxt->next;
48259243Sobrien		setexclp(exclnxt->word);
48359243Sobrien		return (' ');
48459243Sobrien	    }
48559243Sobrien	    exclp = 0;
48659243Sobrien	    exclnxt = 0;
48759243Sobrien	    /* this will throw away the dummy history entries */
48859243Sobrien	    savehist(NULL, 0);
48959243Sobrien
49059243Sobrien	}
49159243Sobrien	if (exclnxt) {
49259243Sobrien	    exclnxt = exclnxt->next;
49359243Sobrien	    if (--exclc < 0)
49459243Sobrien		exclnxt = 0;
49559243Sobrien	    else
49659243Sobrien		setexclp(exclnxt->word);
49759243Sobrien	    continue;
49859243Sobrien	}
49959243Sobrien	c = readc(0);
50059243Sobrien	if (c == '$' && (flag & DODOL)) {
50159243Sobrien	    getdol();
50259243Sobrien	    continue;
50359243Sobrien	}
504145479Smp	if (c == (eChar)HIST && (flag & DOEXCL)) {
50559243Sobrien	    getexcl(0);
50659243Sobrien	    continue;
50759243Sobrien	}
50859243Sobrien	break;
50959243Sobrien    }
51059243Sobrien    return (c);
51159243Sobrien}
51259243Sobrien
51359243Sobrienstatic void
51459243Sobriengetdol()
51559243Sobrien{
51659243Sobrien    Char *np, *ep;
51759243Sobrien    Char    name[4 * MAXVARLEN + 1];
518145479Smp    eChar c;
519145479Smp    eChar   sc;
520145479Smp    int    special = 0, toolong;
52159243Sobrien
52259243Sobrien    np = name, *np++ = '$';
52359243Sobrien    c = sc = getC(DOEXCL);
52459243Sobrien    if (any("\t \n", c)) {
52559243Sobrien	ungetD(c);
52659243Sobrien	ungetC('$' | QUOTE);
52759243Sobrien	return;
52859243Sobrien    }
52959243Sobrien    if (c == '{')
53059243Sobrien	*np++ = (Char) c, c = getC(DOEXCL);
53159243Sobrien    if (c == '#' || c == '?' || c == '%')
53259243Sobrien	special++, *np++ = (Char) c, c = getC(DOEXCL);
53359243Sobrien    *np++ = (Char) c;
53459243Sobrien    switch (c) {
53559243Sobrien
53659243Sobrien    case '<':
53759243Sobrien    case '$':
53859243Sobrien    case '!':
53959243Sobrien	if (special)
54059243Sobrien	    seterror(ERR_SPDOLLT);
54159243Sobrien	*np = 0;
54259243Sobrien	addla(name);
54359243Sobrien	return;
54459243Sobrien
54559243Sobrien    case '\n':
54659243Sobrien	ungetD(c);
54759243Sobrien	np--;
54859243Sobrien	if (!special)
54959243Sobrien	    seterror(ERR_NEWLINE);
55059243Sobrien	*np = 0;
55159243Sobrien	addla(name);
55259243Sobrien	return;
55359243Sobrien
55459243Sobrien    case '*':
55559243Sobrien	if (special)
55659243Sobrien	    seterror(ERR_SPSTAR);
55759243Sobrien	*np = 0;
55859243Sobrien	addla(name);
55959243Sobrien	return;
56059243Sobrien
56159243Sobrien    default:
56259243Sobrien	toolong = 0;
56359243Sobrien	if (Isdigit(c)) {
56459243Sobrien#ifdef notdef
56559243Sobrien	    /* let $?0 pass for now */
56659243Sobrien	    if (special) {
56759243Sobrien		seterror(ERR_DIGIT);
56859243Sobrien		*np = 0;
56959243Sobrien		addla(name);
57059243Sobrien		return;
57159243Sobrien	    }
57259243Sobrien#endif
57359243Sobrien	    /* we know that np < &name[4] */
57459243Sobrien	    ep = &np[MAXVARLEN];
57559243Sobrien	    while ((c = getC(DOEXCL)) != 0) {
57659243Sobrien		if (!Isdigit(c))
57759243Sobrien		    break;
57859243Sobrien		if (np < ep)
57959243Sobrien		    *np++ = (Char) c;
58059243Sobrien		else
58159243Sobrien		    toolong = 1;
58259243Sobrien	    }
58359243Sobrien	}
58459243Sobrien	else if (letter(c)) {
58559243Sobrien	    /* we know that np < &name[4] */
58659243Sobrien	    ep = &np[MAXVARLEN];
58759243Sobrien	    toolong = 0;
58859243Sobrien	    while ((c = getC(DOEXCL)) != 0) {
58959243Sobrien		/* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
59059243Sobrien		if (!letter(c) && !Isdigit(c))
59159243Sobrien		    break;
59259243Sobrien		if (np < ep)
59359243Sobrien		    *np++ = (Char) c;
59459243Sobrien		else
59559243Sobrien		    toolong = 1;
59659243Sobrien	    }
59759243Sobrien	}
59859243Sobrien	else {
59959243Sobrien	    if (!special)
60059243Sobrien		seterror(ERR_VARILL);
60159243Sobrien	    else {
60259243Sobrien		ungetD(c);
60359243Sobrien		--np;
60459243Sobrien	    }
60559243Sobrien	    *np = 0;
60659243Sobrien	    addla(name);
60759243Sobrien	    return;
60859243Sobrien	}
60959243Sobrien	if (toolong) {
61059243Sobrien	    seterror(ERR_VARTOOLONG);
61159243Sobrien	    *np = 0;
61259243Sobrien	    addla(name);
61359243Sobrien	    return;
61459243Sobrien	}
61559243Sobrien	break;
61659243Sobrien    }
61759243Sobrien    if (c == '[') {
61859243Sobrien	*np++ = (Char) c;
61959243Sobrien	/*
62059243Sobrien	 * Name up to here is a max of MAXVARLEN + 8.
62159243Sobrien	 */
62259243Sobrien	ep = &np[2 * MAXVARLEN + 8];
62359243Sobrien	do {
62459243Sobrien	    /*
62559243Sobrien	     * Michael Greim: Allow $ expansion to take place in selector
62659243Sobrien	     * expressions. (limits the number of characters returned)
62759243Sobrien	     */
62859243Sobrien	    c = getC(DOEXCL | DODOL);
62959243Sobrien	    if (c == '\n') {
63059243Sobrien		ungetD(c);
63159243Sobrien		np--;
63259243Sobrien		seterror(ERR_NLINDEX);
63359243Sobrien		*np = 0;
63459243Sobrien		addla(name);
63559243Sobrien		return;
63659243Sobrien	    }
63759243Sobrien	    if (np < ep)
63859243Sobrien		*np++ = (Char) c;
63959243Sobrien	} while (c != ']');
64059243Sobrien	*np = '\0';
64159243Sobrien	if (np >= ep) {
64259243Sobrien	    seterror(ERR_SELOVFL);
64359243Sobrien	    addla(name);
64459243Sobrien	    return;
64559243Sobrien	}
64659243Sobrien	c = getC(DOEXCL);
64759243Sobrien    }
64859243Sobrien    /*
64959243Sobrien     * Name up to here is a max of 2 * MAXVARLEN + 8.
65059243Sobrien     */
65159243Sobrien    if (c == ':') {
65259243Sobrien	/*
65359243Sobrien	 * if the :g modifier is followed by a newline, then error right away!
65459243Sobrien	 * -strike
65559243Sobrien	 */
65659243Sobrien
65759243Sobrien	int     gmodflag = 0, amodflag = 0;
65859243Sobrien
65959243Sobrien#ifndef COMPAT
66059243Sobrien	do {
66159243Sobrien#endif /* COMPAT */
66259243Sobrien	    *np++ = (Char) c, c = getC(DOEXCL);
66359243Sobrien	    if (c == 'g' || c == 'a') {
66459243Sobrien		if (c == 'g')
66559243Sobrien		    gmodflag++;
66659243Sobrien		else
66759243Sobrien		    amodflag++;
66859243Sobrien		*np++ = (Char) c; c = getC(DOEXCL);
66959243Sobrien	    }
67059243Sobrien	    if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
67159243Sobrien		if (c == 'g')
67259243Sobrien		    gmodflag++;
67359243Sobrien		else
67459243Sobrien		    amodflag++;
67559243Sobrien		*np++ = (Char) c; c = getC(DOEXCL);
67659243Sobrien	    }
67759243Sobrien	    *np++ = (Char) c;
67859243Sobrien	    /* scan s// [eichin:19910926.0512EST] */
67959243Sobrien	    if (c == 's') {
68059243Sobrien		int delimcnt = 2;
681145479Smp		eChar delim = getC(0);
68259243Sobrien		*np++ = (Char) delim;
68359243Sobrien
68459243Sobrien		if (!delim || letter(delim)
68559243Sobrien		    || Isdigit(delim) || any(" \t\n", delim)) {
68659243Sobrien		    seterror(ERR_BADSUBST);
68759243Sobrien		    break;
68859243Sobrien		}
689145479Smp		while ((c = getC(0)) != CHAR_ERR) {
69059243Sobrien		    *np++ = (Char) c;
69159243Sobrien		    if(c == delim) delimcnt--;
69259243Sobrien		    if(!delimcnt) break;
69359243Sobrien		}
69459243Sobrien		if(delimcnt) {
69559243Sobrien		    seterror(ERR_BADSUBST);
69659243Sobrien		    break;
69759243Sobrien		}
69859243Sobrien		c = 's';
69959243Sobrien	    }
70059243Sobrien	    if (!any("htrqxesul", c)) {
70159243Sobrien		if ((amodflag || gmodflag) && c == '\n')
70259243Sobrien		    stderror(ERR_VARSYN);	/* strike */
70359243Sobrien		seterror(ERR_BADMOD, c);
70459243Sobrien		*np = 0;
70559243Sobrien		addla(name);
70659243Sobrien		return;
70759243Sobrien	    }
70859243Sobrien#ifndef COMPAT
70959243Sobrien	}
71059243Sobrien	while ((c = getC(DOEXCL)) == ':');
71159243Sobrien	ungetD(c);
71259243Sobrien#endif /* COMPAT */
71359243Sobrien    }
71459243Sobrien    else
71559243Sobrien	ungetD(c);
71659243Sobrien    if (sc == '{') {
71759243Sobrien	c = getC(DOEXCL);
71859243Sobrien	if (c != '}') {
71959243Sobrien	    ungetD(c);
72059243Sobrien	    seterror(ERR_MISSING, '}');
72159243Sobrien	    *np = 0;
72259243Sobrien	    addla(name);
72359243Sobrien	    return;
72459243Sobrien	}
72559243Sobrien	*np++ = (Char) c;
72659243Sobrien    }
72759243Sobrien    *np = 0;
72859243Sobrien    addla(name);
72959243Sobrien    return;
73059243Sobrien}
73159243Sobrien
73259243Sobrienvoid
73359243Sobrienaddla(cp)
73459243Sobrien    Char   *cp;
73559243Sobrien{
73659243Sobrien    Char    buf[BUFSIZE];
73759243Sobrien
73859243Sobrien    if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
73959243Sobrien	(sizeof(labuf) - 4) / sizeof(Char)) {
74059243Sobrien	seterror(ERR_EXPOVFL);
74159243Sobrien	return;
74259243Sobrien    }
74359243Sobrien    if (lap)
74459243Sobrien	(void) Strcpy(buf, lap);
74559243Sobrien    (void) Strcpy(labuf, cp);
746145479Smp    NLSQuote(labuf);
74759243Sobrien    if (lap)
74859243Sobrien	(void) Strcat(labuf, buf);
74959243Sobrien    lap = labuf;
75059243Sobrien}
75159243Sobrien
75259243Sobrienstatic Char lhsb[32];
75359243Sobrienstatic Char slhs[32];
75459243Sobrienstatic Char rhsb[64];
75559243Sobrienstatic int quesarg;
75659243Sobrien
75759243Sobrienstatic void
75859243Sobriengetexcl(sc)
759145479Smp    Char    sc;
76059243Sobrien{
76159243Sobrien    struct wordent *hp, *ip;
76259243Sobrien    int     left, right, dol;
763145479Smp    eChar c;
76459243Sobrien
76559243Sobrien    if (sc == 0) {
76659243Sobrien	sc = getC(0);
76759243Sobrien	if (sc != '{') {
76859243Sobrien	    ungetC(sc);
76959243Sobrien	    sc = 0;
77059243Sobrien	}
77159243Sobrien    }
77259243Sobrien    quesarg = -1;
77359243Sobrien
77459243Sobrien    if (uselastevent) {
77559243Sobrien	uselastevent = 0;
77659243Sobrien	lastev = eventno;
77759243Sobrien    }
77859243Sobrien    else
77959243Sobrien	lastev = eventno;
78059243Sobrien    hp = gethent(sc);
78159243Sobrien    if (hp == 0)
78259243Sobrien	return;
78359243Sobrien    hadhist = 1;
78459243Sobrien    dol = 0;
78559243Sobrien    if (hp == alhistp)
78659243Sobrien	for (ip = hp->next->next; ip != alhistt; ip = ip->next)
78759243Sobrien	    dol++;
78859243Sobrien    else
78959243Sobrien	for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
79059243Sobrien	    dol++;
79159243Sobrien    left = 0, right = dol;
79259243Sobrien    if (sc == HISTSUB) {
79359243Sobrien	ungetC('s'), unreadc(HISTSUB), c = ':';
79459243Sobrien	goto subst;
79559243Sobrien    }
79659243Sobrien    c = getC(0);
79759243Sobrien    if (!any(":^$*-%", c))
79859243Sobrien	goto subst;
79959243Sobrien    left = right = -1;
80059243Sobrien    if (c == ':') {
80159243Sobrien	c = getC(0);
80259243Sobrien	unreadc(c);
80359243Sobrien	if (letter(c) || c == '&') {
80459243Sobrien	    c = ':';
80559243Sobrien	    left = 0, right = dol;
80659243Sobrien	    goto subst;
80759243Sobrien	}
80859243Sobrien    }
80959243Sobrien    else
81059243Sobrien	ungetC(c);
81159243Sobrien    if (!getsel(&left, &right, dol))
81259243Sobrien	return;
81359243Sobrien    c = getC(0);
81459243Sobrien    if (c == '*')
81559243Sobrien	ungetC(c), c = '-';
81659243Sobrien    if (c == '-') {
81759243Sobrien	if (!getsel(&left, &right, dol))
81859243Sobrien	    return;
81959243Sobrien	c = getC(0);
82059243Sobrien    }
82159243Sobriensubst:
82259243Sobrien    exclc = right - left + 1;
82359243Sobrien    while (--left >= 0)
82459243Sobrien	hp = hp->next;
82559243Sobrien    if (sc == HISTSUB || c == ':') {
82659243Sobrien	do {
82759243Sobrien	    hp = getsub(hp);
82859243Sobrien	    c = getC(0);
82959243Sobrien	} while (c == ':');
83059243Sobrien    }
83159243Sobrien    unreadc(c);
83259243Sobrien    if (sc == '{') {
83359243Sobrien	c = getC(0);
83459243Sobrien	if (c != '}')
83559243Sobrien	    seterror(ERR_BADBANG);
83659243Sobrien    }
83759243Sobrien    exclnxt = hp;
83859243Sobrien}
83959243Sobrien
84059243Sobrienstatic struct wordent *
84159243Sobriengetsub(en)
84259243Sobrien    struct wordent *en;
84359243Sobrien{
84459243Sobrien    Char *cp;
845145479Smp    eChar   delim;
846145479Smp    eChar   c;
847145479Smp    eChar   sc;
848145479Smp    int global;
84959243Sobrien    Char    orhsb[sizeof(rhsb) / sizeof(Char)];
85059243Sobrien
85159243Sobrien#ifndef COMPAT
85259243Sobrien    do {
85359243Sobrien#endif /* COMPAT */
85459243Sobrien	exclnxt = 0;
85559243Sobrien	global = 0;
85659243Sobrien	sc = c = getC(0);
85759243Sobrien	if (c == 'g' || c == 'a') {
85859243Sobrien	    global |= (c == 'g') ? 1 : 2;
85959243Sobrien	    sc = c = getC(0);
86059243Sobrien	}
86159243Sobrien	if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
86259243Sobrien	    global |= (c == 'g') ? 1 : 2;
86359243Sobrien	    sc = c = getC(0);
86459243Sobrien	}
86559243Sobrien
86659243Sobrien	switch (c) {
86759243Sobrien	case 'p':
86859243Sobrien	    justpr++;
86959243Sobrien	    return (en);
87059243Sobrien
87159243Sobrien	case 'x':
87259243Sobrien	case 'q':
87359243Sobrien	    global |= 1;
87459243Sobrien	    /*FALLTHROUGH*/
87559243Sobrien
87659243Sobrien	case 'h':
87759243Sobrien	case 'r':
87859243Sobrien	case 't':
87959243Sobrien	case 'e':
88059243Sobrien	case 'u':
88159243Sobrien	case 'l':
88259243Sobrien	    break;
88359243Sobrien
88459243Sobrien	case '&':
88559243Sobrien	    if (slhs[0] == 0) {
88659243Sobrien		seterror(ERR_NOSUBST);
88759243Sobrien		return (en);
88859243Sobrien	    }
88959243Sobrien	    (void) Strcpy(lhsb, slhs);
89059243Sobrien	    break;
89159243Sobrien
89259243Sobrien#ifdef notdef
89359243Sobrien	case '~':
89459243Sobrien	    if (lhsb[0] == 0)
89559243Sobrien		goto badlhs;
89659243Sobrien	    break;
89759243Sobrien#endif
89859243Sobrien
89959243Sobrien	case 's':
90059243Sobrien	    delim = getC(0);
90159243Sobrien	    if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
90259243Sobrien		unreadc(delim);
90359243Sobrien		lhsb[0] = 0;
90459243Sobrien		seterror(ERR_BADSUBST);
90559243Sobrien		return (en);
90659243Sobrien	    }
90759243Sobrien	    cp = lhsb;
90859243Sobrien	    for (;;) {
90959243Sobrien		c = getC(0);
91059243Sobrien		if (c == '\n') {
91159243Sobrien		    unreadc(c);
91259243Sobrien		    break;
91359243Sobrien		}
91459243Sobrien		if (c == delim)
91559243Sobrien		    break;
91659243Sobrien		if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
91759243Sobrien		    lhsb[0] = 0;
91859243Sobrien		    seterror(ERR_BADSUBST);
91959243Sobrien		    return (en);
92059243Sobrien		}
92159243Sobrien		if (c == '\\') {
92259243Sobrien		    c = getC(0);
92359243Sobrien		    if (c != delim && c != '\\')
92459243Sobrien			*cp++ = '\\';
92559243Sobrien		}
92659243Sobrien		*cp++ = (Char) c;
92759243Sobrien	    }
92859243Sobrien	    if (cp != lhsb)
92959243Sobrien		*cp++ = 0;
93059243Sobrien	    else if (lhsb[0] == 0) {
93159243Sobrien		seterror(ERR_LHS);
93259243Sobrien		return (en);
93359243Sobrien	    }
93459243Sobrien	    cp = rhsb;
93559243Sobrien	    (void) Strcpy(orhsb, cp);
93659243Sobrien	    for (;;) {
93759243Sobrien		c = getC(0);
93859243Sobrien		if (c == '\n') {
93959243Sobrien		    unreadc(c);
94059243Sobrien		    break;
94159243Sobrien		}
94259243Sobrien		if (c == delim)
94359243Sobrien		    break;
94459243Sobrien#ifdef notdef
94559243Sobrien		if (c == '~') {
94659243Sobrien		    if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) /
94759243Sobrien						   sizeof(Char) - 2])
94859243Sobrien			goto toorhs;
94959243Sobrien		    (void) Strcpy(cp, orhsb);
95059243Sobrien		    cp = Strend(cp);
95159243Sobrien		    continue;
95259243Sobrien		}
95359243Sobrien#endif
95459243Sobrien		if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
95559243Sobrien		    seterror(ERR_RHSLONG);
95659243Sobrien		    return (en);
95759243Sobrien		}
95859243Sobrien		if (c == '\\') {
95959243Sobrien		    c = getC(0);
96059243Sobrien		    if (c != delim /* && c != '~' */ )
96159243Sobrien			*cp++ = '\\';
96259243Sobrien		}
96359243Sobrien		*cp++ = (Char) c;
96459243Sobrien	    }
96559243Sobrien	    *cp++ = 0;
96659243Sobrien	    break;
96759243Sobrien
96859243Sobrien	default:
96959243Sobrien	    if (c == '\n')
97059243Sobrien		unreadc(c);
971145479Smp	    seterror(ERR_BADBANGMOD, (int)c);
97259243Sobrien	    return (en);
97359243Sobrien	}
97459243Sobrien	(void) Strcpy(slhs, lhsb);
97559243Sobrien	if (exclc)
97659243Sobrien	    en = dosub(sc, en, global);
97759243Sobrien#ifndef COMPAT
97859243Sobrien    }
97959243Sobrien    while ((c = getC(0)) == ':');
98059243Sobrien    unreadc(c);
98159243Sobrien#endif /* COMPAT */
98259243Sobrien    return (en);
98359243Sobrien}
98459243Sobrien
98559243Sobrien/*
98659243Sobrien *
98759243Sobrien * From Beto Appleton (beto@aixwiz.austin.ibm.com)
98859243Sobrien *
98959243Sobrien * when using history substitution, and the variable
99059243Sobrien * 'history' is set to a value higher than 1000,
99159243Sobrien * the shell might either freeze (hang) or core-dump.
99259243Sobrien * We raise the limit to 50000000
99359243Sobrien */
99459243Sobrien
99559243Sobrien#define HIST_PURGE -50000000
99659243Sobrienstatic struct wordent *
99759243Sobriendosub(sc, en, global)
998145479Smp    Char   sc;
99959243Sobrien    struct wordent *en;
1000145479Smp    int global;
100159243Sobrien{
100259243Sobrien    struct wordent lexi;
1003145479Smp    int    didsub = 0, didone = 0;
100459243Sobrien    struct wordent *hp = &lexi;
100559243Sobrien    struct wordent *wdp;
100659243Sobrien    int i = exclc;
100759243Sobrien    struct Hist *hst;
100859243Sobrien
100959243Sobrien    wdp = hp;
101059243Sobrien    while (--i >= 0) {
101159243Sobrien	struct wordent *new =
101259243Sobrien		(struct wordent *) xcalloc(1, sizeof *wdp);
101359243Sobrien
101459243Sobrien	new->word = 0;
101559243Sobrien	new->prev = wdp;
101659243Sobrien	new->next = hp;
101759243Sobrien	wdp->next = new;
101859243Sobrien	wdp = new;
101959243Sobrien	en = en->next;
102059243Sobrien	if (en->word) {
102159243Sobrien	    Char *tword, *otword;
102259243Sobrien
102359243Sobrien	    if ((global & 1) || didsub == 0) {
102459243Sobrien		tword = subword(en->word, sc, &didone);
102559243Sobrien		if (didone)
102659243Sobrien		    didsub = 1;
102759243Sobrien		if (global & 2) {
102859243Sobrien		    while (didone && tword != STRNULL) {
102959243Sobrien			otword = tword;
103059243Sobrien			tword = subword(otword, sc, &didone);
103159243Sobrien			if (Strcmp(tword, otword) == 0) {
103259243Sobrien			    xfree((ptr_t) otword);
103359243Sobrien			    break;
103459243Sobrien			}
103559243Sobrien			else
103659243Sobrien			    xfree((ptr_t) otword);
103759243Sobrien		    }
103859243Sobrien		}
103959243Sobrien	    }
104059243Sobrien	    else
104159243Sobrien		tword = Strsave(en->word);
104259243Sobrien	    wdp->word = tword;
104359243Sobrien	}
104459243Sobrien    }
104559243Sobrien    if (didsub == 0)
104659243Sobrien	seterror(ERR_MODFAIL);
104759243Sobrien    hp->prev = wdp;
104859243Sobrien    /*
104959243Sobrien     * ANSI mode HP/UX compiler chokes on
105059243Sobrien     * return &enthist(HIST_PURGE, &lexi, 0)->Hlex;
105159243Sobrien     */
105259243Sobrien    hst = enthist(HIST_PURGE, &lexi, 0, 0);
105359243Sobrien    return &(hst->Hlex);
105459243Sobrien}
105559243Sobrien
105659243Sobrienstatic Char *
105759243Sobriensubword(cp, type, adid)
105859243Sobrien    Char   *cp;
1059145479Smp    Char    type;
1060145479Smp    int   *adid;
106159243Sobrien{
106259243Sobrien    Char    wbuf[BUFSIZE];
106359243Sobrien    Char *wp, *mp, *np;
106459243Sobrien    int i;
106559243Sobrien
106659243Sobrien    *adid = 0;
106759243Sobrien    switch (type) {
106859243Sobrien
106959243Sobrien    case 'r':
107059243Sobrien    case 'e':
107159243Sobrien    case 'h':
107259243Sobrien    case 't':
107359243Sobrien    case 'q':
107459243Sobrien    case 'x':
107559243Sobrien    case 'u':
107659243Sobrien    case 'l':
107759243Sobrien	wp = domod(cp, type);
107859243Sobrien	if (wp == 0)
107959243Sobrien	    return (Strsave(cp));
108059243Sobrien	*adid = 1;
108159243Sobrien	return (wp);
108259243Sobrien
108359243Sobrien    default:
108459243Sobrien	wp = wbuf;
108559243Sobrien	i = BUFSIZE - 4;
108659243Sobrien	for (mp = cp; *mp; mp++)
108759243Sobrien	    if (matchs(mp, lhsb)) {
108859243Sobrien		for (np = cp; np < mp;)
108959243Sobrien		    *wp++ = *np++, --i;
109059243Sobrien		for (np = rhsb; *np; np++)
109159243Sobrien		    switch (*np) {
109259243Sobrien
109359243Sobrien		    case '\\':
109459243Sobrien			if (np[1] == '&')
109559243Sobrien			    np++;
109659243Sobrien			/* fall into ... */
109759243Sobrien
109859243Sobrien		    default:
109959243Sobrien			if (--i < 0) {
110059243Sobrien			    seterror(ERR_SUBOVFL);
110159243Sobrien			    return (STRNULL);
110259243Sobrien			}
110359243Sobrien			*wp++ = *np;
110459243Sobrien			continue;
110559243Sobrien
110659243Sobrien		    case '&':
110759243Sobrien			i -= Strlen(lhsb);
110859243Sobrien			if (i < 0) {
110959243Sobrien			    seterror(ERR_SUBOVFL);
111059243Sobrien			    return (STRNULL);
111159243Sobrien			}
111259243Sobrien			*wp = 0;
111359243Sobrien			(void) Strcat(wp, lhsb);
111459243Sobrien			wp = Strend(wp);
111559243Sobrien			continue;
111659243Sobrien		    }
111759243Sobrien		mp += Strlen(lhsb);
111859243Sobrien		i -= Strlen(mp);
111959243Sobrien		if (i < 0) {
112059243Sobrien		    seterror(ERR_SUBOVFL);
112159243Sobrien		    return (STRNULL);
112259243Sobrien		}
112359243Sobrien		*wp = 0;
112459243Sobrien		(void) Strcat(wp, mp);
112559243Sobrien		*adid = 1;
112659243Sobrien		return (Strsave(wbuf));
112759243Sobrien	    }
112859243Sobrien	return (Strsave(cp));
112959243Sobrien    }
113059243Sobrien}
113159243Sobrien
113259243SobrienChar   *
113359243Sobriendomod(cp, type)
113459243Sobrien    Char   *cp;
1135145479Smp    Char    type;
113659243Sobrien{
113759243Sobrien    Char *wp, *xp;
113859243Sobrien    int c;
113959243Sobrien
114059243Sobrien    switch (type) {
114159243Sobrien
114259243Sobrien    case 'x':
114359243Sobrien    case 'q':
114459243Sobrien	wp = Strsave(cp);
114559243Sobrien	for (xp = wp; (c = *xp) != 0; xp++)
114659243Sobrien	    if ((c != ' ' && c != '\t') || type == 'q')
114759243Sobrien		*xp |= QUOTE;
114859243Sobrien	return (wp);
114959243Sobrien
115059243Sobrien    case 'l':
1151145479Smp	wp = NLSChangeCase(cp, 1);
1152145479Smp	return wp ? wp : Strsave(cp);
115359243Sobrien
115459243Sobrien    case 'u':
1155145479Smp	wp = NLSChangeCase(cp, 0);
1156145479Smp	return wp ? wp : Strsave(cp);
115759243Sobrien
115859243Sobrien    case 'h':
115959243Sobrien    case 't':
116059243Sobrien	if (!any(short2str(cp), '/'))
116159243Sobrien	    return (type == 't' ? Strsave(cp) : 0);
116259243Sobrien	wp = Strend(cp);
116359243Sobrien	while (*--wp != '/')
116459243Sobrien	    continue;
116559243Sobrien	if (type == 'h')
116659243Sobrien	    xp = Strsave(cp), xp[wp - cp] = 0;
116759243Sobrien	else
116859243Sobrien	    xp = Strsave(wp + 1);
116959243Sobrien	return (xp);
117059243Sobrien
117159243Sobrien    case 'e':
117259243Sobrien    case 'r':
117359243Sobrien	wp = Strend(cp);
117459243Sobrien	for (wp--; wp >= cp && *wp != '/'; wp--)
117559243Sobrien	    if (*wp == '.') {
117659243Sobrien		if (type == 'e')
117759243Sobrien		    xp = Strsave(wp + 1);
117859243Sobrien		else
117959243Sobrien		    xp = Strsave(cp), xp[wp - cp] = 0;
118059243Sobrien		return (xp);
118159243Sobrien	    }
118259243Sobrien	return (Strsave(type == 'e' ? STRNULL : cp));
118359243Sobrien    default:
118459243Sobrien	break;
118559243Sobrien    }
118659243Sobrien    return (0);
118759243Sobrien}
118859243Sobrien
118959243Sobrienstatic int
119059243Sobrienmatchs(str, pat)
119159243Sobrien    Char *str, *pat;
119259243Sobrien{
119359243Sobrien    while (*str && *pat && *str == *pat)
119459243Sobrien	str++, pat++;
119559243Sobrien    return (*pat == 0);
119659243Sobrien}
119759243Sobrien
119859243Sobrienstatic int
119959243Sobriengetsel(al, ar, dol)
120059243Sobrien    int *al, *ar;
120159243Sobrien    int     dol;
120259243Sobrien{
1203145479Smp    eChar c = getC(0);
120459243Sobrien    int i;
1205145479Smp    int    first = *al < 0;
120659243Sobrien
120759243Sobrien    switch (c) {
120859243Sobrien
120959243Sobrien    case '%':
121059243Sobrien	if (quesarg == -1) {
121159243Sobrien	    seterror(ERR_BADBANGARG);
121259243Sobrien	    return (0);
121359243Sobrien	}
121459243Sobrien	if (*al < 0)
121559243Sobrien	    *al = quesarg;
121659243Sobrien	*ar = quesarg;
121759243Sobrien	break;
121859243Sobrien
121959243Sobrien    case '-':
122059243Sobrien	if (*al < 0) {
122159243Sobrien	    *al = 0;
122259243Sobrien	    *ar = dol - 1;
122359243Sobrien	    unreadc(c);
122459243Sobrien	}
122559243Sobrien	return (1);
122659243Sobrien
122759243Sobrien    case '^':
122859243Sobrien	if (*al < 0)
122959243Sobrien	    *al = 1;
123059243Sobrien	*ar = 1;
123159243Sobrien	break;
123259243Sobrien
123359243Sobrien    case '$':
123459243Sobrien	if (*al < 0)
123559243Sobrien	    *al = dol;
123659243Sobrien	*ar = dol;
123759243Sobrien	break;
123859243Sobrien
123959243Sobrien    case '*':
124059243Sobrien	if (*al < 0)
124159243Sobrien	    *al = 1;
124259243Sobrien	*ar = dol;
124359243Sobrien	if (*ar < *al) {
124459243Sobrien	    *ar = 0;
124559243Sobrien	    *al = 1;
124659243Sobrien	    return (1);
124759243Sobrien	}
124859243Sobrien	break;
124959243Sobrien
125059243Sobrien    default:
125159243Sobrien	if (Isdigit(c)) {
125259243Sobrien	    i = 0;
125359243Sobrien	    while (Isdigit(c)) {
125459243Sobrien		i = i * 10 + c - '0';
125559243Sobrien		c = getC(0);
125659243Sobrien	    }
125759243Sobrien	    if (i < 0)
125859243Sobrien		i = dol + 1;
125959243Sobrien	    if (*al < 0)
126059243Sobrien		*al = i;
126159243Sobrien	    *ar = i;
126259243Sobrien	}
126359243Sobrien	else if (*al < 0)
126459243Sobrien	    *al = 0, *ar = dol;
126559243Sobrien	else
126659243Sobrien	    *ar = dol - 1;
126759243Sobrien	unreadc(c);
126859243Sobrien	break;
126959243Sobrien    }
127059243Sobrien    if (first) {
127159243Sobrien	c = getC(0);
127259243Sobrien	unreadc(c);
127359243Sobrien	if (any("-$*", c))
127459243Sobrien	    return (1);
127559243Sobrien    }
127659243Sobrien    if (*al > *ar || *ar > dol) {
127759243Sobrien	seterror(ERR_BADBANGARG);
127859243Sobrien	return (0);
127959243Sobrien    }
128059243Sobrien    return (1);
128159243Sobrien
128259243Sobrien}
128359243Sobrien
128459243Sobrienstatic struct wordent *
128559243Sobriengethent(sc)
1286145479Smp    Char   sc;
128759243Sobrien{
128859243Sobrien    struct Hist *hp;
128959243Sobrien    Char *np;
1290145479Smp    eChar c;
129159243Sobrien    int     event;
1292145479Smp    int    back = 0;
129359243Sobrien
1294145479Smp    c = sc == HISTSUB ? (eChar)HIST : getC(0);
1295145479Smp    if (c == (eChar)HIST) {
129659243Sobrien	if (alhistp)
129759243Sobrien	    return (alhistp);
129859243Sobrien	event = eventno;
129959243Sobrien    }
130059243Sobrien    else
130159243Sobrien	switch (c) {
130259243Sobrien
130359243Sobrien	case ':':
130459243Sobrien	case '^':
130559243Sobrien	case '$':
130659243Sobrien	case '*':
130759243Sobrien	case '%':
130859243Sobrien	    ungetC(c);
130959243Sobrien	    if (lastev == eventno && alhistp)
131059243Sobrien		return (alhistp);
131159243Sobrien	    event = lastev;
131259243Sobrien	    break;
131359243Sobrien
131459243Sobrien	case '#':		/* !# is command being typed in (mrh) */
131559243Sobrien	    if (--hleft == 0) {
131659243Sobrien		seterror(ERR_HISTLOOP);
131759243Sobrien		return (0);
131859243Sobrien	    }
131959243Sobrien	    else
132059243Sobrien		return (&paraml);
132159243Sobrien	    /* NOTREACHED */
132259243Sobrien
132359243Sobrien	case '-':
132459243Sobrien	    back = 1;
132559243Sobrien	    c = getC(0);
132659243Sobrien	    /* FALLSTHROUGH */
132759243Sobrien
132859243Sobrien	default:
132959243Sobrien	    if (any("(=~", c)) {
133059243Sobrien		unreadc(c);
133159243Sobrien		ungetC(HIST);
133259243Sobrien		return (0);
133359243Sobrien	    }
133459243Sobrien	    np = lhsb;
133559243Sobrien	    event = 0;
133659243Sobrien	    while (!cmap(c, _ESC | _META | _QF | _QB) && !any("^*-%${}:#", c)) {
133759243Sobrien		if (event != -1 && Isdigit(c))
133859243Sobrien		    event = event * 10 + c - '0';
133959243Sobrien		else
134059243Sobrien		    event = -1;
134159243Sobrien		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
134259243Sobrien		    *np++ = (Char) c;
134359243Sobrien		c = getC(0);
134459243Sobrien	    }
134559243Sobrien	    unreadc(c);
134659243Sobrien	    if (np == lhsb) {
134759243Sobrien		ungetC(HIST);
134859243Sobrien		return (0);
134959243Sobrien	    }
135059243Sobrien	    *np++ = 0;
135159243Sobrien	    if (event != -1) {
135259243Sobrien		/*
135359243Sobrien		 * History had only digits
135459243Sobrien		 */
135559243Sobrien		if (back)
135659243Sobrien		    event = eventno + (alhistp == 0) - (event ? event : 0);
135759243Sobrien		break;
135859243Sobrien	    }
135959243Sobrien	    if (back) {
136059243Sobrien		event = sizeof(lhsb) / sizeof(lhsb[0]);
136159243Sobrien		np = &lhsb[--event];
136259243Sobrien		*np-- = '\0';
136359243Sobrien		for (event--; np > lhsb; *np-- = lhsb[--event])
136459243Sobrien		    continue;
136559243Sobrien		*np = '-';
136659243Sobrien	    }
136759243Sobrien	    hp = findev(lhsb, 0);
136859243Sobrien	    if (hp)
136959243Sobrien		lastev = hp->Hnum;
137059243Sobrien	    return (&hp->Hlex);
137159243Sobrien
137259243Sobrien	case '?':
137359243Sobrien	    np = lhsb;
137459243Sobrien	    for (;;) {
137559243Sobrien		c = getC(0);
137659243Sobrien		if (c == '\n') {
137759243Sobrien		    unreadc(c);
137859243Sobrien		    break;
137959243Sobrien		}
138059243Sobrien		if (c == '?')
138159243Sobrien		    break;
138259243Sobrien		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
138359243Sobrien		    *np++ = (Char) c;
138459243Sobrien	    }
138559243Sobrien	    if (np == lhsb) {
138659243Sobrien		if (lhsb[0] == 0) {
138759243Sobrien		    seterror(ERR_NOSEARCH);
138859243Sobrien		    return (0);
138959243Sobrien		}
139059243Sobrien	    }
139159243Sobrien	    else
139259243Sobrien		*np++ = 0;
139359243Sobrien	    hp = findev(lhsb, 1);
139459243Sobrien	    if (hp)
139559243Sobrien		lastev = hp->Hnum;
139659243Sobrien	    return (&hp->Hlex);
139759243Sobrien	}
139859243Sobrien
139959243Sobrien    for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
140059243Sobrien	if (hp->Hnum == event) {
140159243Sobrien	    hp->Href = eventno;
140259243Sobrien	    lastev = hp->Hnum;
140359243Sobrien	    return (&hp->Hlex);
140459243Sobrien	}
140559243Sobrien    np = putn(event);
140659243Sobrien    seterror(ERR_NOEVENT, short2str(np));
140759243Sobrien    return (0);
140859243Sobrien}
140959243Sobrien
141059243Sobrienstatic struct Hist *
141159243Sobrienfindev(cp, anyarg)
141259243Sobrien    Char   *cp;
1413145479Smp    int    anyarg;
141459243Sobrien{
141559243Sobrien    struct Hist *hp;
141659243Sobrien
141759243Sobrien    for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
141859243Sobrien	Char   *dp;
141959243Sobrien	Char *p, *q;
142059243Sobrien	struct wordent *lp = hp->Hlex.next;
142159243Sobrien	int     argno = 0;
142259243Sobrien
142359243Sobrien	/*
142459243Sobrien	 * The entries added by alias substitution don't have a newline but do
142559243Sobrien	 * have a negative event number. Savehist() trims off these entries,
142659243Sobrien	 * but it happens before alias expansion, too early to delete those
142759243Sobrien	 * from the previous command.
142859243Sobrien	 */
142959243Sobrien	if (hp->Hnum < 0)
143059243Sobrien	    continue;
143159243Sobrien	if (lp->word[0] == '\n')
143259243Sobrien	    continue;
143359243Sobrien	if (!anyarg) {
143459243Sobrien	    p = cp;
143559243Sobrien	    q = lp->word;
143659243Sobrien	    do
143759243Sobrien		if (!*p)
143859243Sobrien		    return (hp);
143959243Sobrien	    while (*p++ == *q++);
144059243Sobrien	    continue;
144159243Sobrien	}
144259243Sobrien	do {
144359243Sobrien	    for (dp = lp->word; *dp; dp++) {
144459243Sobrien		p = cp;
144559243Sobrien		q = dp;
144659243Sobrien		do
144759243Sobrien		    if (!*p) {
144859243Sobrien			quesarg = argno;
144959243Sobrien			return (hp);
145059243Sobrien		    }
145159243Sobrien		while (*p++ == *q++);
145259243Sobrien	    }
145359243Sobrien	    lp = lp->next;
145459243Sobrien	    argno++;
145559243Sobrien	} while (lp->word[0] != '\n');
145659243Sobrien    }
145759243Sobrien    seterror(ERR_NOEVENT, short2str(cp));
145859243Sobrien    return (0);
145959243Sobrien}
146059243Sobrien
146159243Sobrien
146259243Sobrienstatic void
146359243Sobriensetexclp(cp)
146459243Sobrien    Char *cp;
146559243Sobrien{
146659243Sobrien    if (cp && cp[0] == '\n')
146759243Sobrien	return;
146859243Sobrien    exclp = cp;
146959243Sobrien}
147059243Sobrien
147159243Sobrienvoid
147259243Sobrienunreadc(c)
1473145479Smp    Char    c;
147459243Sobrien{
147559243Sobrien    peekread = (Char) c;
147659243Sobrien}
147759243Sobrien
1478145479SmpeChar
147959243Sobrienreadc(wanteof)
1480145479Smp    int    wanteof;
148159243Sobrien{
1482145479Smp    eChar c;
148359243Sobrien    static  int sincereal;	/* Number of real EOFs we've seen */
148459243Sobrien
148559243Sobrien#ifdef DEBUG_INP
148659243Sobrien    xprintf("readc\n");
148759243Sobrien#endif
148859243Sobrien    if ((c = peekread) != 0) {
148959243Sobrien	peekread = 0;
149059243Sobrien	return (c);
149159243Sobrien    }
149259243Sobrien
149359243Sobrientop:
149469408Sache    aret = TCSH_F_SEEK;
149559243Sobrien    if (alvecp) {
149659243Sobrien	arun = 1;
149759243Sobrien#ifdef DEBUG_INP
149859243Sobrien	xprintf("alvecp %c\n", *alvecp & 0xff);
149959243Sobrien#endif
150069408Sache	aret = TCSH_A_SEEK;
150159243Sobrien	if ((c = *alvecp++) != 0)
150259243Sobrien	    return (c);
150359243Sobrien	if (alvec && *alvec) {
150459243Sobrien		alvecp = *alvec++;
150559243Sobrien		return (' ');
150659243Sobrien	}
150759243Sobrien	else {
150859243Sobrien	    alvecp = NULL;
150969408Sache	    aret = TCSH_F_SEEK;
151059243Sobrien	    return('\n');
151159243Sobrien	}
151259243Sobrien    }
151359243Sobrien    if (alvec) {
151459243Sobrien	arun = 1;
151559243Sobrien	if ((alvecp = *alvec) != 0) {
151659243Sobrien	    alvec++;
151759243Sobrien	    goto top;
151859243Sobrien	}
151959243Sobrien	/* Infinite source! */
152059243Sobrien	return ('\n');
152159243Sobrien    }
152259243Sobrien    arun = 0;
152359243Sobrien    if (evalp) {
152469408Sache	aret = TCSH_E_SEEK;
152559243Sobrien	if ((c = *evalp++) != 0)
152659243Sobrien	    return (c);
152759243Sobrien	if (evalvec && *evalvec) {
152859243Sobrien	    evalp = *evalvec++;
152959243Sobrien	    return (' ');
153059243Sobrien	}
153169408Sache	aret = TCSH_F_SEEK;
153259243Sobrien	evalp = 0;
153359243Sobrien    }
153459243Sobrien    if (evalvec) {
153559243Sobrien	if (evalvec == INVPPTR) {
153659243Sobrien	    doneinp = 1;
153759243Sobrien	    reset();
153859243Sobrien	}
153959243Sobrien	if ((evalp = *evalvec) != 0) {
154059243Sobrien	    evalvec++;
154159243Sobrien	    goto top;
154259243Sobrien	}
154359243Sobrien	evalvec = INVPPTR;
154459243Sobrien	return ('\n');
154559243Sobrien    }
154659243Sobrien    do {
154759243Sobrien	if (arginp == INVPTR || onelflg == 1) {
154859243Sobrien	    if (wanteof)
1549145479Smp		return CHAR_ERR;
155059243Sobrien	    exitstat();
155159243Sobrien	}
155259243Sobrien	if (arginp) {
155359243Sobrien	    if ((c = *arginp++) == 0) {
155459243Sobrien		arginp = INVPTR;
155559243Sobrien		return ('\n');
155659243Sobrien	    }
155759243Sobrien	    return (c);
155859243Sobrien	}
155959243Sobrien#ifdef BSDJOBS
156059243Sobrienreread:
156159243Sobrien#endif /* BSDJOBS */
156259243Sobrien	c = bgetc();
1563145479Smp	if (c == CHAR_ERR) {
156469408Sache#ifndef WINNT_NATIVE
156559243Sobrien# ifndef POSIX
156659243Sobrien#  ifdef TERMIO
156759243Sobrien	    struct termio tty;
156859243Sobrien#  else /* SGTTYB */
156959243Sobrien	    struct sgttyb tty;
157059243Sobrien#  endif /* TERMIO */
157159243Sobrien# else /* POSIX */
157259243Sobrien	    struct termios tty;
157359243Sobrien# endif /* POSIX */
157469408Sache#endif /* !WINNT_NATIVE */
157559243Sobrien	    if (wanteof)
1576145479Smp		return CHAR_ERR;
157759243Sobrien	    /* was isatty but raw with ignoreeof yields problems */
157869408Sache#ifndef WINNT_NATIVE
157959243Sobrien# ifndef POSIX
158059243Sobrien#  ifdef TERMIO
158159243Sobrien	    if (ioctl(SHIN, TCGETA, (ioctl_t) & tty) == 0 &&
158259243Sobrien		(tty.c_lflag & ICANON))
158359243Sobrien#  else /* GSTTYB */
158459243Sobrien	    if (ioctl(SHIN, TIOCGETP, (ioctl_t) & tty) == 0 &&
158559243Sobrien		(tty.sg_flags & RAW) == 0)
158659243Sobrien#  endif /* TERMIO */
158759243Sobrien# else /* POSIX */
158859243Sobrien	    if (tcgetattr(SHIN, &tty) == 0 &&
158959243Sobrien		(tty.c_lflag & ICANON))
159059243Sobrien# endif /* POSIX */
159169408Sache#else /* WINNT_NATIVE */
159259243Sobrien	    if (isatty(SHIN))
159369408Sache#endif /* !WINNT_NATIVE */
159459243Sobrien	    {
159559243Sobrien#ifdef BSDJOBS
159659243Sobrien		int     ctpgrp;
159759243Sobrien#endif /* BSDJOBS */
159859243Sobrien
1599100616Smp		if (numeof != 0 && ++sincereal >= numeof)	/* Too many EOFs?  Bye! */
160059243Sobrien		    goto oops;
160159243Sobrien#ifdef BSDJOBS
160259243Sobrien		if (tpgrp != -1 &&
160359243Sobrien		    (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
160459243Sobrien		    tpgrp != ctpgrp) {
160559243Sobrien		    (void) tcsetpgrp(FSHTTY, tpgrp);
160659243Sobrien# ifdef _SEQUENT_
160759243Sobrien		    if (ctpgrp)
160859243Sobrien# endif /* _SEQUENT */
160959243Sobrien		    (void) killpg((pid_t) ctpgrp, SIGHUP);
161059243Sobrien# ifdef notdef
161159243Sobrien		    /*
161259243Sobrien		     * With the walking process group fix, this message
161359243Sobrien		     * is now obsolete. As the foreground process group
161459243Sobrien		     * changes, the shell needs to adjust. Well too bad.
161559243Sobrien		     */
161659243Sobrien		    xprintf(CGETS(16, 1, "Reset tty pgrp from %d to %d\n"),
161759243Sobrien			    ctpgrp, tpgrp);
161859243Sobrien# endif /* notdef */
161959243Sobrien		    goto reread;
162059243Sobrien		}
162159243Sobrien#endif /* BSDJOBS */
162259243Sobrien		/* What follows is complicated EOF handling -- sterling@netcom.com */
162359243Sobrien		/* First, we check to see if we have ignoreeof set */
162459243Sobrien		if (adrof(STRignoreeof)) {
162559243Sobrien			/* If so, we check for any stopped jobs only on the first EOF */
162659243Sobrien			if ((sincereal == 1) && (chkstop == 0)) {
162759243Sobrien				panystop(1);
162859243Sobrien			}
162959243Sobrien		} else {
163059243Sobrien			/* If we don't have ignoreeof set, always check for stopped jobs */
163159243Sobrien			if (chkstop == 0) {
163259243Sobrien				panystop(1);
163359243Sobrien			}
163459243Sobrien		}
163559243Sobrien		/* At this point, if there were stopped jobs, we would have already
163659243Sobrien		 * called reset().  If we got this far, assume we can print an
163759243Sobrien		 * exit/logout message if we ignoreeof, or just exit.
163859243Sobrien		 */
163959243Sobrien		if (adrof(STRignoreeof)) {
164059243Sobrien			/* If so, tell the user to use exit or logout */
164159243Sobrien		    if (loginsh) {
164259243Sobrien				xprintf(CGETS(16, 2,
164359243Sobrien					"\nUse \"logout\" to logout.\n"));
164459243Sobrien		   	} else {
164559243Sobrien				xprintf(CGETS(16, 3,
164659243Sobrien					"\nUse \"exit\" to leave %s.\n"),
164759243Sobrien					progname);
164859243Sobrien			}
164959243Sobrien			reset();
165059243Sobrien		} else {
165159243Sobrien			/* If we don't have ignoreeof set, just fall through */
165259243Sobrien			;	/* EMPTY */
165359243Sobrien		}
165459243Sobrien	    }
165559243Sobrien    oops:
165659243Sobrien	    doneinp = 1;
165759243Sobrien	    reset();
165859243Sobrien	}
165959243Sobrien	sincereal = 0;
166059243Sobrien	if (c == '\n' && onelflg)
166159243Sobrien	    onelflg--;
166259243Sobrien    } while (c == 0);
166359243Sobrien    if (histlinep < histline + BUFSIZE)
166459243Sobrien	*histlinep++ = (Char) c;
166559243Sobrien    return (c);
166659243Sobrien}
166759243Sobrien
166859243Sobrienstatic void
166959243Sobrienballoc(buf)
167059243Sobrien    int buf;
167159243Sobrien{
167259243Sobrien    Char **nfbuf;
167359243Sobrien
167459243Sobrien    while (buf >= fblocks) {
167559243Sobrien	nfbuf = (Char **) xcalloc((size_t) (fblocks + 2),
167659243Sobrien			  sizeof(Char **));
167759243Sobrien	if (fbuf) {
167859243Sobrien	    (void) blkcpy(nfbuf, fbuf);
167959243Sobrien	    xfree((ptr_t) fbuf);
168059243Sobrien	}
168159243Sobrien	fbuf = nfbuf;
168259243Sobrien	fbuf[fblocks] = (Char *) xcalloc(BUFSIZE, sizeof(Char));
168359243Sobrien	fblocks++;
168459243Sobrien    }
168559243Sobrien}
168659243Sobrien
1687145479Smpstatic ssize_t
1688145479Smpwide_read(fildes, buf, nchars, use_fclens)
1689145479Smp    int fildes;
1690145479Smp    Char *buf;
1691145479Smp    size_t nchars;
1692145479Smp    int use_fclens;
1693145479Smp{
1694145479Smp    char cbuf[BUFSIZE + 1];
1695145479Smp    ssize_t res, r;
1696145479Smp    size_t partial;
1697145479Smp
1698145479Smp    assert (nchars <= sizeof(cbuf)/sizeof(*cbuf));
1699145479Smp    USE(use_fclens);
1700145479Smp    res = 0;
1701145479Smp    partial = 0;
1702145479Smp    do {
1703145479Smp	size_t i;
1704145479Smp
1705145479Smp	do
1706145479Smp	    r = read(fildes, cbuf + partial,
1707145479Smp		     nchars > partial ? nchars - partial : 1);
1708145479Smp	while (partial != 0 && r < 0 && errno == EINTR);
1709145479Smp	if (partial == 0 && r <= 0)
1710145479Smp	    break;
1711145479Smp	partial += r;
1712145479Smp	i = 0;
1713145479Smp	while (i < partial) {
1714145479Smp	    int len;
1715145479Smp
1716145479Smp	    len = normal_mbtowc(buf + res, cbuf + i, partial - i);
1717145479Smp	    if (len == -1) {
1718145479Smp	        reset_mbtowc();
1719145479Smp		if (partial < MB_LEN_MAX && r > 0)
1720145479Smp		    /* Maybe a partial character and there is still a chance
1721145479Smp		       to read more */
1722145479Smp		    break;
1723145479Smp		buf[res] = (unsigned char)cbuf[i] | INVALID_BYTE;
1724145479Smp	    }
1725145479Smp	    if (len <= 0)
1726145479Smp		len = 1;
1727145479Smp#ifdef WIDE_STRINGS
1728145479Smp	    if (use_fclens)
1729145479Smp		fclens[res] = len;
1730145479Smp#endif
1731145479Smp	    i += len;
1732145479Smp	    res++;
1733145479Smp	    nchars--;
1734145479Smp	}
1735145479Smp	if (i != partial)
1736145479Smp	    memmove(cbuf, cbuf + i, partial - i);
1737145479Smp	partial -= i;
1738145479Smp    } while (partial != 0);
1739145479Smp    /* Throwing away possible partial multibyte characters on error */
1740145479Smp    return res != 0 ? res : r;
1741145479Smp}
1742145479Smp
1743145479Smpstatic eChar
174459243Sobrienbgetc()
174559243Sobrien{
1746145479Smp    Char ch;
174759243Sobrien    int c, off, buf;
174859243Sobrien    int numleft = 0, roomleft;
174959243Sobrien
175059243Sobrien    if (cantell) {
175159243Sobrien	if (fseekp < fbobp || fseekp > feobp) {
175259243Sobrien	    fbobp = feobp = fseekp;
175359243Sobrien	    (void) lseek(SHIN, fseekp, L_SET);
175459243Sobrien	}
175559243Sobrien	if (fseekp == feobp) {
175659243Sobrien	    fbobp = feobp;
175759243Sobrien	    do
1758145479Smp		c = wide_read(SHIN, fbuf[0], BUFSIZE, 1);
175959243Sobrien	    while (c < 0 && errno == EINTR);
176059243Sobrien#ifdef convex
176159243Sobrien	    if (c < 0)
176259243Sobrien		stderror(ERR_SYSTEM, progname, strerror(errno));
176359243Sobrien#endif /* convex */
176459243Sobrien	    if (c <= 0)
1765145479Smp		return CHAR_ERR;
176659243Sobrien	    feobp += c;
176759243Sobrien	}
176869408Sache#ifndef WINNT_NATIVE
1769145479Smp	ch = fbuf[0][fseekp - fbobp];
177059243Sobrien	fseekp++;
177159243Sobrien#else
177259243Sobrien	do {
1773145479Smp	    ch = fbuf[0][fseekp - fbobp];
177459243Sobrien	    fseekp++;
1775145479Smp	} while(ch == '\r');
177669408Sache#endif /* !WINNT_NATIVE */
1777145479Smp	return (ch);
177859243Sobrien    }
177959243Sobrien
178059243Sobrien    while (fseekp >= feobp) {
1781100616Smp	if ((editing
1782100616Smp#if defined(FILEC) && defined(TIOCSTI)
1783100616Smp	    || filec
1784100616Smp#endif /* FILEC && TIOCSTI */
1785100616Smp	    ) && intty) {		/* then use twenex routine */
178659243Sobrien	    fseekp = feobp;		/* where else? */
1787100616Smp#if defined(FILEC) && defined(TIOCSTI)
1788100616Smp	    if (!editing)
1789100616Smp		c = numleft = tenex(InputBuf, BUFSIZE);
1790100616Smp	    else
1791100616Smp#endif /* FILEC && TIOCSTI */
179259243Sobrien	    c = numleft = Inputl();	/* PWP: get a line */
179359243Sobrien	    while (numleft > 0) {
179459243Sobrien		off = (int) feobp % BUFSIZE;
179559243Sobrien		buf = (int) feobp / BUFSIZE;
179659243Sobrien		balloc(buf);
179759243Sobrien		roomleft = BUFSIZE - off;
179859243Sobrien		if (roomleft > numleft)
179959243Sobrien		    roomleft = numleft;
1800100616Smp		(void) memmove((ptr_t) (fbuf[buf] + off),
1801100616Smp		    (ptr_t) (InputBuf + c - numleft),
1802100616Smp		    (size_t) (roomleft * sizeof(Char)));
180359243Sobrien		numleft -= roomleft;
180459243Sobrien		feobp += roomleft;
180559243Sobrien	    }
1806100616Smp	} else {
180759243Sobrien	    off = (int) feobp % BUFSIZE;
180859243Sobrien	    buf = (int) feobp / BUFSIZE;
180959243Sobrien	    balloc(buf);
181059243Sobrien	    roomleft = BUFSIZE - off;
1811145479Smp	    c = wide_read(SHIN, fbuf[buf] + off, (size_t) roomleft, 0);
1812145479Smp	    if (c > 0)
181359243Sobrien		feobp += c;
181459243Sobrien	}
181559243Sobrien	if (c == 0 || (c < 0 && fixio(SHIN, errno) == -1))
1816145479Smp	    return CHAR_ERR;
181759243Sobrien    }
1818145479Smp#ifdef SIG_WINDOW
1819145479Smp    if (windowchg)
1820145479Smp	(void) check_window_size(0);	/* for window systems */
1821145479Smp#endif /* SIG_WINDOW */
182269408Sache#ifndef WINNT_NATIVE
1823145479Smp    ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE];
182459243Sobrien    fseekp++;
182559243Sobrien#else
182659243Sobrien    do {
1827145479Smp	ch = fbuf[(int) fseekp / BUFSIZE][(int) fseekp % BUFSIZE];
182859243Sobrien	fseekp++;
1829145479Smp    } while(ch == '\r');
183069408Sache#endif /* !WINNT_NATIVE */
1831145479Smp    return (ch);
183259243Sobrien}
183359243Sobrien
183459243Sobrienstatic void
183559243Sobrienbfree()
183659243Sobrien{
183759243Sobrien    int sb, i;
183859243Sobrien
183959243Sobrien    if (cantell)
184059243Sobrien	return;
184159243Sobrien    if (whyles)
184259243Sobrien	return;
184359243Sobrien    sb = (int) (fseekp - 1) / BUFSIZE;
184459243Sobrien    if (sb > 0) {
184559243Sobrien	for (i = 0; i < sb; i++)
184659243Sobrien	    xfree((ptr_t) fbuf[i]);
184759243Sobrien	(void) blkcpy(fbuf, &fbuf[sb]);
184859243Sobrien	fseekp -= BUFSIZE * sb;
184959243Sobrien	feobp -= BUFSIZE * sb;
185059243Sobrien	fblocks -= sb;
185159243Sobrien    }
185259243Sobrien}
185359243Sobrien
185459243Sobrienvoid
185559243Sobrienbseek(l)
185659243Sobrien    struct Ain   *l;
185759243Sobrien{
185859243Sobrien    switch (aret = l->type) {
185969408Sache    case TCSH_E_SEEK:
186059243Sobrien	evalvec = l->a_seek;
186159243Sobrien	evalp = l->c_seek;
186259243Sobrien#ifdef DEBUG_SEEK
186359243Sobrien	xprintf(CGETS(16, 4, "seek to eval %x %x\n"), evalvec, evalp);
186459243Sobrien#endif
186559243Sobrien	return;
186669408Sache    case TCSH_A_SEEK:
186759243Sobrien	alvec = l->a_seek;
186859243Sobrien	alvecp = l->c_seek;
186959243Sobrien#ifdef DEBUG_SEEK
187059243Sobrien	xprintf(CGETS(16, 5, "seek to alias %x %x\n"), alvec, alvecp);
187159243Sobrien#endif
187259243Sobrien	return;
187369408Sache    case TCSH_F_SEEK:
187459243Sobrien#ifdef DEBUG_SEEK
187559243Sobrien	xprintf(CGETS(16, 6, "seek to file %x\n"), fseekp);
187659243Sobrien#endif
187759243Sobrien	fseekp = l->f_seek;
1878145479Smp#ifdef WIDE_STRINGS
1879145479Smp	if (cantell) {
1880145479Smp	    if (fseekp >= fbobp) {
1881145479Smp		size_t i;
1882145479Smp		off_t o;
1883145479Smp
1884145479Smp		o = fbobp;
1885145479Smp		for (i = 0; i < feobp - fbobp; i++) {
1886145479Smp		    if (fseekp == o) {
1887145479Smp			fseekp = fbobp + i;
1888145479Smp			return;
1889145479Smp		    }
1890145479Smp		    o += fclens[i];
1891145479Smp		}
1892145479Smp		if (fseekp == o) {
1893145479Smp		    fseekp = feobp;
1894145479Smp		    return;
1895145479Smp		}
1896145479Smp	    }
1897145479Smp	    fbobp = feobp = fseekp + 1; /* To force lseek() */
1898145479Smp	}
1899145479Smp#endif
190059243Sobrien	return;
190159243Sobrien    default:
190259243Sobrien	xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret);
190359243Sobrien	abort();
190459243Sobrien    }
190559243Sobrien}
190659243Sobrien
190759243Sobrien/* any similarity to bell telephone is purely accidental */
190859243Sobrienvoid
190959243Sobrienbtell(l)
191059243Sobrienstruct Ain *l;
191159243Sobrien{
191259243Sobrien    switch (l->type = aret) {
191369408Sache    case TCSH_E_SEEK:
191459243Sobrien	l->a_seek = evalvec;
191559243Sobrien	l->c_seek = evalp;
191659243Sobrien#ifdef DEBUG_SEEK
191759243Sobrien	xprintf(CGETS(16, 8, "tell eval %x %x\n"), evalvec, evalp);
191859243Sobrien#endif
191959243Sobrien	return;
192069408Sache    case TCSH_A_SEEK:
192159243Sobrien	l->a_seek = alvec;
192259243Sobrien	l->c_seek = alvecp;
192359243Sobrien#ifdef DEBUG_SEEK
192459243Sobrien	xprintf(CGETS(16, 9, "tell alias %x %x\n"), alvec, alvecp);
192559243Sobrien#endif
192659243Sobrien	return;
192769408Sache    case TCSH_F_SEEK:
1928145479Smp#ifdef WIDE_STRINGS
1929145479Smp	if (cantell && fseekp >= fbobp && fseekp < feobp) {
1930145479Smp	    size_t i;
1931145479Smp
1932145479Smp	    l->f_seek = fbobp;
1933145479Smp	    for (i = 0; i < fseekp - fbobp; i++)
1934145479Smp		l->f_seek += fclens[i];
1935145479Smp	} else
1936145479Smp#endif
1937145479Smp	    /*SUPPRESS 112*/
1938145479Smp	    l->f_seek = fseekp;
193959243Sobrien	l->a_seek = NULL;
194059243Sobrien#ifdef DEBUG_SEEK
194159243Sobrien	xprintf(CGETS(16, 10, "tell file %x\n"), fseekp);
194259243Sobrien#endif
194359243Sobrien	return;
194459243Sobrien    default:
194559243Sobrien	xprintf(CGETS(16, 7, "Bad seek type %d\n"), aret);
194659243Sobrien	abort();
194759243Sobrien    }
194859243Sobrien}
194959243Sobrien
195059243Sobrienvoid
195159243Sobrienbtoeof()
195259243Sobrien{
195359243Sobrien    (void) lseek(SHIN, (off_t) 0, L_XTND);
195469408Sache    aret = TCSH_F_SEEK;
195559243Sobrien    fseekp = feobp;
195659243Sobrien    alvec = NULL;
195759243Sobrien    alvecp = NULL;
195859243Sobrien    evalvec = NULL;
195959243Sobrien    evalp = NULL;
196059243Sobrien    wfree();
196159243Sobrien    bfree();
196259243Sobrien}
196359243Sobrien
196459243Sobrienvoid
196559243Sobriensettell()
196659243Sobrien{
196759243Sobrien    off_t x;
196859243Sobrien    cantell = 0;
196959243Sobrien    if (arginp || onelflg || intty)
197059243Sobrien	return;
197159243Sobrien    if ((x = lseek(SHIN, (off_t) 0, L_INCR)) == -1)
197259243Sobrien	return;
197359243Sobrien    fbuf = (Char **) xcalloc(2, sizeof(Char **));
197459243Sobrien    fblocks = 1;
197559243Sobrien    fbuf[0] = (Char *) xcalloc(BUFSIZE, sizeof(Char));
197659243Sobrien    fseekp = fbobp = feobp = x;
197759243Sobrien    cantell = 1;
197859243Sobrien}
1979