xref: /onnv-gate/usr/src/cmd/csh/sh.lex.c (revision 2182:221c5b409327)
10Sstevel@tonic-gate /*
2*2182Schin  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved  	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
110Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
120Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
130Sstevel@tonic-gate  */
140Sstevel@tonic-gate 
150Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
160Sstevel@tonic-gate 
170Sstevel@tonic-gate #include <unistd.h>	/* for lseek prototype */
180Sstevel@tonic-gate #include "sh.h"
190Sstevel@tonic-gate #include "sh.tconst.h"
200Sstevel@tonic-gate #include <sys/filio.h>
210Sstevel@tonic-gate #include <sys/ttold.h>
22559Snakanon #define	RAW 	O_RAW
230Sstevel@tonic-gate /*
240Sstevel@tonic-gate  * C shell
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * These lexical routines read input and form lists of words.
290Sstevel@tonic-gate  * There is some involved processing here, because of the complications
300Sstevel@tonic-gate  * of input buffering, and especially because of history substitution.
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
33356Smuffin tchar	*word(void);
34356Smuffin tchar	getC1(int);
35356Smuffin tchar	*subword(tchar *, int, bool *);
36356Smuffin void	getdol(void);
37356Smuffin void	addla(tchar *);
38356Smuffin void	getexcl(tchar);
39356Smuffin void	noev(tchar *);
40356Smuffin void	setexclp(tchar *);
41356Smuffin void	unreadc(tchar);
42356Smuffin int	readc(bool);
43356Smuffin struct wordent	*dosub(int, struct wordent *, bool);
44356Smuffin struct Hist	*findev(tchar *, bool);
45356Smuffin struct wordent	*gethent(int);
46356Smuffin struct wordent	*getsub(struct wordent *);
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate  * Peekc is a peek characer for getC, peekread for readc.
500Sstevel@tonic-gate  * There is a subtlety here in many places... history routines
510Sstevel@tonic-gate  * will read ahead and then insert stuff into the input stream.
520Sstevel@tonic-gate  * If they push back a character then they must push it behind
530Sstevel@tonic-gate  * the text substituted by the history substitution.  On the other
540Sstevel@tonic-gate  * hand in several places we need 2 peek characters.  To make this
550Sstevel@tonic-gate  * all work, the history routines read with getC, and make use both
560Sstevel@tonic-gate  * of ungetC and unreadc.  The key observation is that the state
570Sstevel@tonic-gate  * of getC at the call of a history reference is such that calls
580Sstevel@tonic-gate  * to getC from the history routines will always yield calls of
590Sstevel@tonic-gate  * readc, unless this peeking is involved.  That is to say that during
600Sstevel@tonic-gate  * getexcl the variables lap, exclp, and exclnxt are all zero.
610Sstevel@tonic-gate  *
620Sstevel@tonic-gate  * Getdol invokes history substitution, hence the extra peek, peekd,
630Sstevel@tonic-gate  * which it can ungetD to be before history substitutions.
640Sstevel@tonic-gate  */
650Sstevel@tonic-gate tchar peekc, peekd;
660Sstevel@tonic-gate tchar peekread;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate tchar *exclp;			/* (Tail of) current word from ! subst */
690Sstevel@tonic-gate struct	wordent *exclnxt;	/* The rest of the ! subst words */
700Sstevel@tonic-gate int	exclc;			/* Count of remainig words in ! subst */
710Sstevel@tonic-gate tchar *alvecp;		/* "Globp" for alias resubstitution */
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * Lex returns to its caller not only a wordlist (as a "var" parameter)
750Sstevel@tonic-gate  * but also whether a history substitution occurred.  This is used in
760Sstevel@tonic-gate  * the main (process) routine to determine whether to echo, and also
770Sstevel@tonic-gate  * when called by the alias routine to determine whether to keep the
780Sstevel@tonic-gate  * argument list.
790Sstevel@tonic-gate  */
800Sstevel@tonic-gate bool	hadhist;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate tchar getCtmp;
83559Snakanon #define	getC(f)		((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
840Sstevel@tonic-gate #define	ungetC(c)	peekc = c
850Sstevel@tonic-gate #define	ungetD(c)	peekd = c
860Sstevel@tonic-gate 
87356Smuffin bool
lex(struct wordent * hp)88356Smuffin lex(struct wordent *hp)
890Sstevel@tonic-gate {
90356Smuffin 	struct wordent *wdp;
910Sstevel@tonic-gate 	int c;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate #ifdef TRACE
940Sstevel@tonic-gate 	tprintf("TRACE- lex()\n");
950Sstevel@tonic-gate #endif
960Sstevel@tonic-gate 	lineloc = btell();
970Sstevel@tonic-gate 	hp->next = hp->prev = hp;
98559Snakanon 	hp->word = S_ /* "" */;
990Sstevel@tonic-gate 	alvecp = 0, hadhist = 0;
1000Sstevel@tonic-gate 	do
1010Sstevel@tonic-gate 		c = readc(0);
1020Sstevel@tonic-gate 	while (issp(c));
1030Sstevel@tonic-gate 	/* make sure history is enabled */
1040Sstevel@tonic-gate 	if (HIST && c == HISTSUB && intty)
1050Sstevel@tonic-gate 		/* ^lef^rit	from tty is short !:s^lef^rit */
1060Sstevel@tonic-gate 		getexcl(c);
1070Sstevel@tonic-gate 	else
1080Sstevel@tonic-gate 		unreadc(c);
1090Sstevel@tonic-gate 	wdp = hp;
1100Sstevel@tonic-gate 	/*
1110Sstevel@tonic-gate 	 * The following loop is written so that the links needed
1120Sstevel@tonic-gate 	 * by freelex will be ready and rarin to go even if it is
1130Sstevel@tonic-gate 	 * interrupted.
1140Sstevel@tonic-gate 	 */
1150Sstevel@tonic-gate 	do {
116559Snakanon 		struct wordent *new = (struct wordent *)xalloc(sizeof *wdp);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 		new->word = 0;
1190Sstevel@tonic-gate 		new->prev = wdp;
1200Sstevel@tonic-gate 		new->next = hp;
1210Sstevel@tonic-gate 		wdp->next = new;
1220Sstevel@tonic-gate 		wdp = new;
1230Sstevel@tonic-gate 		wdp->word = word();
1240Sstevel@tonic-gate 	} while (wdp->word[0] != '\n');
1250Sstevel@tonic-gate #ifdef TRACE
1260Sstevel@tonic-gate 	tprintf("Exiting lex()\n");
1270Sstevel@tonic-gate #endif
1280Sstevel@tonic-gate 	hp->prev = wdp;
1290Sstevel@tonic-gate 	return (hadhist);
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate 
132356Smuffin void
prlex(struct wordent * sp0)133356Smuffin prlex(struct wordent *sp0)
1340Sstevel@tonic-gate {
135356Smuffin 	struct wordent *sp = sp0->next;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate #ifdef TRACE
1380Sstevel@tonic-gate 	tprintf("TRACE- prlex()\n");
1390Sstevel@tonic-gate #endif
1400Sstevel@tonic-gate 	for (;;) {
1410Sstevel@tonic-gate 		printf("%t", sp->word);
1420Sstevel@tonic-gate 		sp = sp->next;
1430Sstevel@tonic-gate 		if (sp == sp0)
1440Sstevel@tonic-gate 			break;
1450Sstevel@tonic-gate 		if (sp->word[0] != '\n')
1460Sstevel@tonic-gate 			Putchar(' ');
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
150356Smuffin void
copylex(struct wordent * hp,struct wordent * fp)151356Smuffin copylex(struct wordent *hp, struct wordent *fp)
1520Sstevel@tonic-gate {
153356Smuffin 	struct wordent *wdp;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate #ifdef TRACE
1560Sstevel@tonic-gate 	tprintf("TRACE- copylex()\n");
1570Sstevel@tonic-gate #endif
1580Sstevel@tonic-gate 	wdp = hp;
1590Sstevel@tonic-gate 	fp = fp->next;
1600Sstevel@tonic-gate 	do {
161559Snakanon 		struct wordent *new = (struct wordent *)xalloc(sizeof *wdp);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 		new->prev = wdp;
1640Sstevel@tonic-gate 		new->next = hp;
1650Sstevel@tonic-gate 		wdp->next = new;
1660Sstevel@tonic-gate 		wdp = new;
1670Sstevel@tonic-gate 		wdp->word = savestr(fp->word);
1680Sstevel@tonic-gate 		fp = fp->next;
1690Sstevel@tonic-gate 	} while (wdp->word[0] != '\n');
1700Sstevel@tonic-gate 	hp->prev = wdp;
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate 
173356Smuffin void
freelex(struct wordent * vp)174356Smuffin freelex(struct wordent *vp)
1750Sstevel@tonic-gate {
176356Smuffin 	struct wordent *fp;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate #ifdef TRACE
1790Sstevel@tonic-gate 	tprintf("TRACE- freelex()\n");
1800Sstevel@tonic-gate #endif
1810Sstevel@tonic-gate 	while (vp->next != vp) {
1820Sstevel@tonic-gate 		fp = vp->next;
1830Sstevel@tonic-gate 		vp->next = fp->next;
184559Snakanon 		xfree(fp->word);
185559Snakanon 		xfree(fp);
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate 	vp->prev = vp;
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate tchar *
word(void)191356Smuffin word(void)
1920Sstevel@tonic-gate {
193356Smuffin 	tchar c, c1;
194356Smuffin 	tchar *wp;
1950Sstevel@tonic-gate 	tchar wbuf[BUFSIZ];
196356Smuffin 	bool dolflg;
197356Smuffin 	int i;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate #ifdef TRACE
2000Sstevel@tonic-gate 	tprintf("TRACE- word()\n");
2010Sstevel@tonic-gate #endif
2020Sstevel@tonic-gate 	wp = wbuf;
2030Sstevel@tonic-gate 	i = BUFSIZ - 4;
2040Sstevel@tonic-gate loop:
2050Sstevel@tonic-gate 	while (issp(c = getC(DOALL)))
2060Sstevel@tonic-gate 		;
2070Sstevel@tonic-gate 	if (cmap(c, _META|_ESC)||isauxsp(c))
2080Sstevel@tonic-gate 		switch (c) {
2090Sstevel@tonic-gate 		case '&':
2100Sstevel@tonic-gate 		case '|':
2110Sstevel@tonic-gate 		case '<':
2120Sstevel@tonic-gate 		case '>':
2130Sstevel@tonic-gate 			*wp++ = c;
2140Sstevel@tonic-gate 			c1 = getC(DOALL);
2150Sstevel@tonic-gate 			if (c1 == c)
2160Sstevel@tonic-gate 				*wp++ = c1;
2170Sstevel@tonic-gate 			else
2180Sstevel@tonic-gate 				ungetC(c1);
2190Sstevel@tonic-gate 			goto ret;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 		case '#':
2220Sstevel@tonic-gate 			if (intty)
2230Sstevel@tonic-gate 				break;
2240Sstevel@tonic-gate 			c = 0;
2250Sstevel@tonic-gate 			do {
2260Sstevel@tonic-gate 				c1 = c;
2270Sstevel@tonic-gate 				c = getC(0);
2280Sstevel@tonic-gate 			} while (c != '\n');
2290Sstevel@tonic-gate 			if (c1 == '\\')
2300Sstevel@tonic-gate 				goto loop;
2310Sstevel@tonic-gate 			/* fall into ... */
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 		case ';':
2340Sstevel@tonic-gate 		case '(':
2350Sstevel@tonic-gate 		case ')':
2360Sstevel@tonic-gate 		case '\n':
2370Sstevel@tonic-gate 			*wp++ = c;
2380Sstevel@tonic-gate 			goto ret;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 		case '\\':
2410Sstevel@tonic-gate 			c = getC(0);
2420Sstevel@tonic-gate 			if (c == '\n') {
2430Sstevel@tonic-gate 				if (onelflg == 1)
2440Sstevel@tonic-gate 					onelflg = 2;
2450Sstevel@tonic-gate 				goto loop;
2460Sstevel@tonic-gate 			}
2470Sstevel@tonic-gate 			if (c != HIST)
2480Sstevel@tonic-gate 				*wp++ = '\\', --i;
2490Sstevel@tonic-gate 			c |= QUOTE;
2500Sstevel@tonic-gate 		}
2510Sstevel@tonic-gate 	c1 = 0;
2520Sstevel@tonic-gate 	dolflg = DOALL;
2530Sstevel@tonic-gate 	for (;;) {
2540Sstevel@tonic-gate 		if (c1) {
2550Sstevel@tonic-gate 			if (c == c1) {
2560Sstevel@tonic-gate 				c1 = 0;
2570Sstevel@tonic-gate 				dolflg = DOALL;
2580Sstevel@tonic-gate 			} else if (c == '\\') {
2590Sstevel@tonic-gate 				c = getC(0);
2600Sstevel@tonic-gate 				if (c == HIST)
2610Sstevel@tonic-gate 					c |= QUOTE;
2620Sstevel@tonic-gate 				else {
2630Sstevel@tonic-gate 					if (c == '\n')
264559Snakanon #if 0
2650Sstevel@tonic-gate 						if (c1 == '`')
2660Sstevel@tonic-gate 							c = ' ';
2670Sstevel@tonic-gate 						else
268559Snakanon #endif
2690Sstevel@tonic-gate 							c |= QUOTE;
2700Sstevel@tonic-gate 					ungetC(c);
2710Sstevel@tonic-gate 					c = '\\';
2720Sstevel@tonic-gate 				}
2730Sstevel@tonic-gate 			} else if (c == '\n') {
2740Sstevel@tonic-gate 				seterrc(gettext("Unmatched "), c1);
2750Sstevel@tonic-gate 				ungetC(c);
2760Sstevel@tonic-gate 				break;
2770Sstevel@tonic-gate 			}
2780Sstevel@tonic-gate 		} else if (cmap(c, _META|_Q|_Q1|_ESC)||isauxsp(c)) {
2790Sstevel@tonic-gate 			if (c == '\\') {
2800Sstevel@tonic-gate 				c = getC(0);
2810Sstevel@tonic-gate 				if (c == '\n') {
2820Sstevel@tonic-gate 					if (onelflg == 1)
2830Sstevel@tonic-gate 						onelflg = 2;
2840Sstevel@tonic-gate 					break;
2850Sstevel@tonic-gate 				}
2860Sstevel@tonic-gate 				if (c != HIST)
2870Sstevel@tonic-gate 					*wp++ = '\\', --i;
2880Sstevel@tonic-gate 				c |= QUOTE;
2890Sstevel@tonic-gate 			} else if (cmap(c, _Q|_Q1)) {		/* '"` */
2900Sstevel@tonic-gate 				c1 = c;
2910Sstevel@tonic-gate 				dolflg = c == '"' ? DOALL : DOEXCL;
2920Sstevel@tonic-gate 			} else if (c != '#' || !intty) {
2930Sstevel@tonic-gate 				ungetC(c);
2940Sstevel@tonic-gate 				break;
2950Sstevel@tonic-gate 			}
2960Sstevel@tonic-gate 		}
2970Sstevel@tonic-gate 		if (--i > 0) {
2980Sstevel@tonic-gate 			*wp++ = c;
2990Sstevel@tonic-gate 			c = getC(dolflg);
3000Sstevel@tonic-gate 		} else {
3010Sstevel@tonic-gate 			seterr("Word too long");
3020Sstevel@tonic-gate 			wp = &wbuf[1];
3030Sstevel@tonic-gate 			break;
3040Sstevel@tonic-gate 		}
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate ret:
3070Sstevel@tonic-gate 	*wp = 0;
3080Sstevel@tonic-gate #ifdef TRACE
3090Sstevel@tonic-gate 	tprintf("word() returning:%t\n", wbuf);
3100Sstevel@tonic-gate #endif
3110Sstevel@tonic-gate 	return (savestr(wbuf));
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
314356Smuffin tchar
getC1(int flag)315356Smuffin getC1(int flag)
3160Sstevel@tonic-gate {
317356Smuffin 	tchar c;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate top:
3200Sstevel@tonic-gate 	if (c = peekc) {
3210Sstevel@tonic-gate 		peekc = 0;
3220Sstevel@tonic-gate 		return (c);
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 	if (lap) {
3250Sstevel@tonic-gate 		if ((c = *lap++) == 0)
3260Sstevel@tonic-gate 			lap = 0;
3270Sstevel@tonic-gate 		else {
3280Sstevel@tonic-gate 			/*
329559Snakanon 			 * don't quote things if there was an error (err!=0)
330559Snakanon 			 * the input is original, not from a substitution and
331559Snakanon 			 * therefore should not be quoted
3320Sstevel@tonic-gate 			 */
3330Sstevel@tonic-gate 			if (!err && cmap(c, _META|_Q|_Q1)||isauxsp(c))
3340Sstevel@tonic-gate 				c |= QUOTE;
3350Sstevel@tonic-gate 			return (c);
3360Sstevel@tonic-gate 		}
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 	if (c = peekd) {
3390Sstevel@tonic-gate 		peekd = 0;
3400Sstevel@tonic-gate 		return (c);
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 	if (exclp) {
3430Sstevel@tonic-gate 		if (c = *exclp++)
3440Sstevel@tonic-gate 			return (c);
3450Sstevel@tonic-gate 		if (exclnxt && --exclc >= 0) {
3460Sstevel@tonic-gate 			exclnxt = exclnxt->next;
3470Sstevel@tonic-gate 			setexclp(exclnxt->word);
3480Sstevel@tonic-gate 			return (' ');
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 		exclp = 0;
3510Sstevel@tonic-gate 		exclnxt = 0;
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 	if (exclnxt) {
3540Sstevel@tonic-gate 		exclnxt = exclnxt->next;
3550Sstevel@tonic-gate 		if (--exclc < 0)
3560Sstevel@tonic-gate 			exclnxt = 0;
3570Sstevel@tonic-gate 		else
3580Sstevel@tonic-gate 			setexclp(exclnxt->word);
3590Sstevel@tonic-gate 		goto top;
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 	c = readc(0);
3620Sstevel@tonic-gate 	if (c == '$' && (flag & DODOL)) {
3630Sstevel@tonic-gate 		getdol();
3640Sstevel@tonic-gate 		goto top;
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 	if (c == HIST && (flag & DOEXCL)) {
3670Sstevel@tonic-gate 		getexcl(0);
3680Sstevel@tonic-gate 		goto top;
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 	return (c);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
373356Smuffin void
getdol(void)374356Smuffin getdol(void)
3750Sstevel@tonic-gate {
376356Smuffin 	tchar *np, *p;
3770Sstevel@tonic-gate 	tchar name[MAX_VREF_LEN];
378356Smuffin 	int c;
3790Sstevel@tonic-gate 	int sc;
3800Sstevel@tonic-gate 	bool special = 0;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate #ifdef TRACE
3830Sstevel@tonic-gate 	tprintf("TRACE- getdol()\n");
3840Sstevel@tonic-gate #endif
3850Sstevel@tonic-gate 	np = name, *np++ = '$';
3860Sstevel@tonic-gate 	c = sc = getC(DOEXCL);
3870Sstevel@tonic-gate 	if (isspnl(c)) {
3880Sstevel@tonic-gate 		ungetD(c);
3890Sstevel@tonic-gate 		ungetC('$' | QUOTE);
3900Sstevel@tonic-gate 		return;
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 	if (c == '{')
3930Sstevel@tonic-gate 		*np++ = c, c = getC(DOEXCL);
3940Sstevel@tonic-gate 	if (c == '#' || c == '?')
3950Sstevel@tonic-gate 		special++, *np++ = c, c = getC(DOEXCL);
3960Sstevel@tonic-gate 	*np++ = c;
3970Sstevel@tonic-gate 	switch (c) {
398559Snakanon 
3990Sstevel@tonic-gate 	case '<':
4000Sstevel@tonic-gate 	case '$':
4010Sstevel@tonic-gate 	case '*':
4020Sstevel@tonic-gate 		if (special)
4030Sstevel@tonic-gate 			goto vsyn;
4040Sstevel@tonic-gate 		goto ret;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	case '\n':
4070Sstevel@tonic-gate 		ungetD(c);
4080Sstevel@tonic-gate 		np--;
4090Sstevel@tonic-gate 		goto vsyn;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	default:
4120Sstevel@tonic-gate 		p = np;
4130Sstevel@tonic-gate 		if (digit(c)) {
4140Sstevel@tonic-gate 			/* make sure the variable names are MAX_VAR_LEN chars or less */
415559Snakanon 			while (digit(c = getC(DOEXCL)) && (np - p) < MAX_VAR_LEN) {
4160Sstevel@tonic-gate 				*np++ = c;
4170Sstevel@tonic-gate 			}
4180Sstevel@tonic-gate 		} else if (letter(c)) {
4190Sstevel@tonic-gate 			while ((letter(c = getC(DOEXCL)) || digit(c)) &&
420559Snakanon 				(np - p) < MAX_VAR_LEN) {
4210Sstevel@tonic-gate 				*np++ = c;
4220Sstevel@tonic-gate 			}
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 		else
4250Sstevel@tonic-gate 			goto vsyn;
4260Sstevel@tonic-gate 
427559Snakanon 		if ((np - p) > MAX_VAR_LEN)
4280Sstevel@tonic-gate 		{
4290Sstevel@tonic-gate 			seterr("Variable name too long");
4300Sstevel@tonic-gate 			goto ret;
4310Sstevel@tonic-gate 		}
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 	if (c == '[') {
4340Sstevel@tonic-gate 		*np++ = c;
4350Sstevel@tonic-gate 		do {
4360Sstevel@tonic-gate 			c = getC(DOEXCL);
4370Sstevel@tonic-gate 			if (c == '\n') {
4380Sstevel@tonic-gate 				ungetD(c);
4390Sstevel@tonic-gate 				np--;
4400Sstevel@tonic-gate 				goto vsyn;
4410Sstevel@tonic-gate 			}
4420Sstevel@tonic-gate 			/* need to leave space for possible modifiers */
4430Sstevel@tonic-gate 			if (np >= &name[MAX_VREF_LEN - 8])
4440Sstevel@tonic-gate 			{
4450Sstevel@tonic-gate 				seterr("Variable reference too long");
4460Sstevel@tonic-gate 				goto ret;
4470Sstevel@tonic-gate 			}
4480Sstevel@tonic-gate 			*np++ = c;
4490Sstevel@tonic-gate 		} while (c != ']');
4500Sstevel@tonic-gate 		c = getC(DOEXCL);
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate 	if (c == ':') {
4530Sstevel@tonic-gate 		*np++ = c, c = getC(DOEXCL);
4540Sstevel@tonic-gate 		if (c == 'g')
4550Sstevel@tonic-gate 			*np++ = c, c = getC(DOEXCL);
4560Sstevel@tonic-gate 		*np++ = c;
4570Sstevel@tonic-gate 		if (!any(c, S_htrqxe))
4580Sstevel@tonic-gate 			goto vsyn;
4590Sstevel@tonic-gate 	} else
4600Sstevel@tonic-gate 		ungetD(c);
4610Sstevel@tonic-gate 	if (sc == '{') {
4620Sstevel@tonic-gate 		c = getC(DOEXCL);
4630Sstevel@tonic-gate 		if (c != '}') {
4640Sstevel@tonic-gate 			ungetC(c);
4650Sstevel@tonic-gate 			goto vsyn;
4660Sstevel@tonic-gate 		}
4670Sstevel@tonic-gate 		*np++ = c;
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate ret:
4700Sstevel@tonic-gate 	*np = 0;
4710Sstevel@tonic-gate 	addla(name);
4720Sstevel@tonic-gate 	return;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate vsyn:
4750Sstevel@tonic-gate 	seterr("Variable syntax");
4760Sstevel@tonic-gate 	goto ret;
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate 
479356Smuffin void
addla(tchar * cp)480356Smuffin addla(tchar *cp)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate 	tchar *buf;
4830Sstevel@tonic-gate 	int len = 0;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate #ifdef TRACE
4860Sstevel@tonic-gate 	tprintf("TRACE- addla()\n");
4870Sstevel@tonic-gate #endif
4880Sstevel@tonic-gate 	if (lap) {
4890Sstevel@tonic-gate 		len = strlen_(lap);
4900Sstevel@tonic-gate 		buf = xalloc((len+1) * sizeof (tchar));
4910Sstevel@tonic-gate 		(void) strcpy_(buf, lap);
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 	len += strlen_(cp);
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	/* len+5 is allow 4 additional charecters just to be safe */
4960Sstevel@tonic-gate 	labuf = xrealloc(labuf, (len+5) * sizeof (tchar));
4970Sstevel@tonic-gate 	(void) strcpy_(labuf, cp);
4980Sstevel@tonic-gate 	if (lap) {
4990Sstevel@tonic-gate 		(void) strcat_(labuf, buf);
500559Snakanon 		xfree(buf);
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 	lap = labuf;
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate 
505*2182Schin tchar	lhsb[256];
506*2182Schin tchar	slhs[256];
507*2182Schin tchar	rhsb[512];
5080Sstevel@tonic-gate int	quesarg;
5090Sstevel@tonic-gate 
510356Smuffin void
getexcl(tchar sc)511356Smuffin getexcl(tchar sc)
5120Sstevel@tonic-gate {
513356Smuffin 	struct wordent *hp, *ip;
5140Sstevel@tonic-gate 	int left, right, dol;
515356Smuffin 	int c;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate #ifdef TRACE
5180Sstevel@tonic-gate 	tprintf("TRACE- getexcl()\n");
5190Sstevel@tonic-gate #endif
5200Sstevel@tonic-gate 	if (sc == 0) {
5210Sstevel@tonic-gate 		sc = getC(0);
5220Sstevel@tonic-gate 		if (sc != '{') {
5230Sstevel@tonic-gate 			ungetC(sc);
5240Sstevel@tonic-gate 			sc = 0;
5250Sstevel@tonic-gate 		}
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 	quesarg = -1;
5280Sstevel@tonic-gate 	lastev = eventno;
5290Sstevel@tonic-gate 	hp = gethent(sc);
5300Sstevel@tonic-gate 	if (hp == 0)
5310Sstevel@tonic-gate 		return;
5320Sstevel@tonic-gate 	hadhist = 1;
5330Sstevel@tonic-gate 	dol = 0;
5340Sstevel@tonic-gate 	if (hp == alhistp)
5350Sstevel@tonic-gate 		for (ip = hp->next->next; ip != alhistt; ip = ip->next)
5360Sstevel@tonic-gate 			dol++;
5370Sstevel@tonic-gate 	else
5380Sstevel@tonic-gate 		for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
5390Sstevel@tonic-gate 			dol++;
5400Sstevel@tonic-gate 	left = 0, right = dol;
5410Sstevel@tonic-gate 	if (sc == HISTSUB) {
5420Sstevel@tonic-gate 		ungetC('s'), unreadc(HISTSUB), c = ':';
5430Sstevel@tonic-gate 		goto subst;
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 	c = getC(0);
546559Snakanon 	/* if (!any(c, ":^$*-%")) */	/* change needed for char -> tchar */
5470Sstevel@tonic-gate 	if (! (c == ':' || c == '^' || c == '$' || c == '*' ||
548559Snakanon 	    c == '-' || c == '%'))
5490Sstevel@tonic-gate 		goto subst;
5500Sstevel@tonic-gate 	left = right = -1;
5510Sstevel@tonic-gate 	if (c == ':') {
5520Sstevel@tonic-gate 		c = getC(0);
5530Sstevel@tonic-gate 		unreadc(c);
5540Sstevel@tonic-gate 		if (letter(c) || c == '&') {
5550Sstevel@tonic-gate 			c = ':';
5560Sstevel@tonic-gate 			left = 0, right = dol;
5570Sstevel@tonic-gate 			goto subst;
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 	} else
5600Sstevel@tonic-gate 		ungetC(c);
5610Sstevel@tonic-gate 	if (!getsel(&left, &right, dol))
5620Sstevel@tonic-gate 		return;
5630Sstevel@tonic-gate 	c = getC(0);
5640Sstevel@tonic-gate 	if (c == '*')
5650Sstevel@tonic-gate 		ungetC(c), c = '-';
5660Sstevel@tonic-gate 	if (c == '-') {
5670Sstevel@tonic-gate 		if (!getsel(&left, &right, dol))
5680Sstevel@tonic-gate 			return;
5690Sstevel@tonic-gate 		c = getC(0);
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate subst:
5720Sstevel@tonic-gate 	exclc = right - left + 1;
5730Sstevel@tonic-gate 	while (--left >= 0)
5740Sstevel@tonic-gate 		hp = hp->next;
5750Sstevel@tonic-gate 	if (sc == HISTSUB || c == ':') {
5760Sstevel@tonic-gate 		do {
5770Sstevel@tonic-gate 			hp = getsub(hp);
5780Sstevel@tonic-gate 			c = getC(0);
5790Sstevel@tonic-gate 		} while (c == ':');
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 	unreadc(c);
5820Sstevel@tonic-gate 	if (sc == '{') {
5830Sstevel@tonic-gate 		c = getC(0);
5840Sstevel@tonic-gate 		if (c != '}')
5850Sstevel@tonic-gate 			seterr("Bad ! form");
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate 	exclnxt = hp;
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate struct wordent *
getsub(struct wordent * en)591356Smuffin getsub(struct wordent *en)
5920Sstevel@tonic-gate {
593356Smuffin 	tchar *cp;
5940Sstevel@tonic-gate 	int delim;
595356Smuffin 	int c;
5960Sstevel@tonic-gate 	int sc;
5970Sstevel@tonic-gate 	bool global = 0;
5980Sstevel@tonic-gate 	tchar orhsb[(sizeof rhsb)/(sizeof rhsb[0])];
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate #ifdef TRACE
6010Sstevel@tonic-gate 	tprintf("TRACE- getsub()\n");
6020Sstevel@tonic-gate #endif
6030Sstevel@tonic-gate 	exclnxt = 0;
6040Sstevel@tonic-gate 	sc = c = getC(0);
6050Sstevel@tonic-gate 	if (c == 'g')
6060Sstevel@tonic-gate 		global++, c = getC(0);
6070Sstevel@tonic-gate 	switch (c) {
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	case 'p':
6100Sstevel@tonic-gate 		justpr++;
6110Sstevel@tonic-gate 		goto ret;
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	case 'x':
6140Sstevel@tonic-gate 	case 'q':
6150Sstevel@tonic-gate 		global++;
6160Sstevel@tonic-gate 		/* fall into ... */
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	case 'h':
6190Sstevel@tonic-gate 	case 'r':
6200Sstevel@tonic-gate 	case 't':
6210Sstevel@tonic-gate 	case 'e':
6220Sstevel@tonic-gate 		break;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	case '&':
6250Sstevel@tonic-gate 		if (slhs[0] == 0) {
6260Sstevel@tonic-gate 			seterr("No prev sub");
6270Sstevel@tonic-gate 			goto ret;
6280Sstevel@tonic-gate 		}
6290Sstevel@tonic-gate 		(void) strcpy_(lhsb, slhs);
6300Sstevel@tonic-gate 		break;
6310Sstevel@tonic-gate 
632559Snakanon #if 0
6330Sstevel@tonic-gate 	case '~':
6340Sstevel@tonic-gate 		if (lhsb[0] == 0)
6350Sstevel@tonic-gate 			goto badlhs;
6360Sstevel@tonic-gate 		break;
637559Snakanon #endif
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	case 's':
6400Sstevel@tonic-gate 		delim = getC(0);
641559Snakanon 		if (alnum(delim) || isspnl(delim)) {
6420Sstevel@tonic-gate 			unreadc(delim);
6430Sstevel@tonic-gate bads:
6440Sstevel@tonic-gate 			lhsb[0] = 0;
6450Sstevel@tonic-gate 			seterr("Bad substitute");
6460Sstevel@tonic-gate 			goto ret;
6470Sstevel@tonic-gate 		}
6480Sstevel@tonic-gate 		cp = lhsb;
6490Sstevel@tonic-gate 		for (;;) {
6500Sstevel@tonic-gate 			c = getC(0);
6510Sstevel@tonic-gate 			if (c == '\n') {
6520Sstevel@tonic-gate 				unreadc(c);
6530Sstevel@tonic-gate 				break;
6540Sstevel@tonic-gate 			}
6550Sstevel@tonic-gate 			if (c == delim)
6560Sstevel@tonic-gate 				break;
6570Sstevel@tonic-gate 			if (cp > &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
6580Sstevel@tonic-gate 				goto bads;
6590Sstevel@tonic-gate 			if (c == '\\') {
6600Sstevel@tonic-gate 				c = getC(0);
6610Sstevel@tonic-gate 				if (c != delim && c != '\\')
6620Sstevel@tonic-gate 					*cp++ = '\\';
6630Sstevel@tonic-gate 			}
6640Sstevel@tonic-gate 			*cp++ = c;
6650Sstevel@tonic-gate 		}
6660Sstevel@tonic-gate 		if (cp != lhsb)
6670Sstevel@tonic-gate 			*cp++ = 0;
6680Sstevel@tonic-gate 		else if (lhsb[0] == 0) {
669559Snakanon /* badlhs: */
6700Sstevel@tonic-gate 			seterr("No prev lhs");
6710Sstevel@tonic-gate 			goto ret;
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 		cp = rhsb;
6740Sstevel@tonic-gate 		(void) strcpy_(orhsb, cp);
6750Sstevel@tonic-gate 		for (;;) {
6760Sstevel@tonic-gate 			c = getC(0);
6770Sstevel@tonic-gate 			if (c == '\n') {
6780Sstevel@tonic-gate 				unreadc(c);
6790Sstevel@tonic-gate 				break;
6800Sstevel@tonic-gate 			}
6810Sstevel@tonic-gate 			if (c == delim)
6820Sstevel@tonic-gate 				break;
683559Snakanon #if 0
6840Sstevel@tonic-gate 			if (c == '~') {
685559Snakanon 				if (&cp[strlen_(orhsb)]
6860Sstevel@tonic-gate 				> &rhsb[(sizeof rhsb)/(sizeof rhsb[0]) - 2])
6870Sstevel@tonic-gate 					goto toorhs;
6880Sstevel@tonic-gate 				(void) strcpy_(cp, orhsb);
6890Sstevel@tonic-gate 				cp = strend(cp);
6900Sstevel@tonic-gate 				continue;
6910Sstevel@tonic-gate 			}
692559Snakanon #endif
6930Sstevel@tonic-gate 			if (cp > &rhsb[(sizeof rhsb)/(sizeof rhsb[0]) - 2]) {
694559Snakanon /* toorhs: */
6950Sstevel@tonic-gate 				seterr("Rhs too long");
6960Sstevel@tonic-gate 				goto ret;
6970Sstevel@tonic-gate 			}
6980Sstevel@tonic-gate 			if (c == '\\') {
6990Sstevel@tonic-gate 				c = getC(0);
7000Sstevel@tonic-gate 				if (c != delim /* && c != '~' */)
7010Sstevel@tonic-gate 					*cp++ = '\\';
7020Sstevel@tonic-gate 			}
7030Sstevel@tonic-gate 			*cp++ = c;
7040Sstevel@tonic-gate 		}
7050Sstevel@tonic-gate 		*cp++ = 0;
7060Sstevel@tonic-gate 		break;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	default:
7090Sstevel@tonic-gate 		if (c == '\n')
7100Sstevel@tonic-gate 			unreadc(c);
7110Sstevel@tonic-gate 		seterrc(gettext("Bad ! modifier: "), c);
7120Sstevel@tonic-gate 		goto ret;
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 	(void) strcpy_(slhs, lhsb);
7150Sstevel@tonic-gate 	if (exclc)
7160Sstevel@tonic-gate 		en = dosub(sc, en, global);
7170Sstevel@tonic-gate ret:
7180Sstevel@tonic-gate 	return (en);
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate struct wordent *
dosub(int sc,struct wordent * en,bool global)722356Smuffin dosub(int sc, struct wordent *en, bool global)
7230Sstevel@tonic-gate {
7240Sstevel@tonic-gate 	struct wordent lex;
7250Sstevel@tonic-gate 	bool didsub = 0;
7260Sstevel@tonic-gate 	struct wordent *hp = &lex;
727356Smuffin 	struct wordent *wdp;
728356Smuffin 	int i = exclc;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate #ifdef TRACE
7310Sstevel@tonic-gate 	tprintf("TRACE- dosub()\n");
7320Sstevel@tonic-gate #endif
7330Sstevel@tonic-gate 	wdp = hp;
7340Sstevel@tonic-gate 	while (--i >= 0) {
735559Snakanon 		struct wordent *new = (struct wordent *)xcalloc(1, sizeof *wdp);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		new->prev = wdp;
7380Sstevel@tonic-gate 		new->next = hp;
7390Sstevel@tonic-gate 		wdp->next = new;
7400Sstevel@tonic-gate 		wdp = new;
7410Sstevel@tonic-gate 		en = en->next;
7420Sstevel@tonic-gate 		wdp->word = global || didsub == 0 ?
7430Sstevel@tonic-gate 		    subword(en->word, sc, &didsub) : savestr(en->word);
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 	if (didsub == 0)
7460Sstevel@tonic-gate 		seterr("Modifier failed");
7470Sstevel@tonic-gate 	hp->prev = wdp;
7480Sstevel@tonic-gate 	return (&enthist(-1000, &lex, 0)->Hlex);
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate tchar *
subword(tchar * cp,int type,bool * adid)752356Smuffin subword(tchar *cp, int type, bool *adid)
7530Sstevel@tonic-gate {
7540Sstevel@tonic-gate 	tchar wbuf[BUFSIZ];
755356Smuffin 	tchar *wp, *mp, *np;
756356Smuffin 	int i;
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate #ifdef TRACE
7590Sstevel@tonic-gate 	tprintf("TRACE- subword()\n");
7600Sstevel@tonic-gate #endif
7610Sstevel@tonic-gate 	switch (type) {
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	case 'r':
7640Sstevel@tonic-gate 	case 'e':
7650Sstevel@tonic-gate 	case 'h':
7660Sstevel@tonic-gate 	case 't':
7670Sstevel@tonic-gate 	case 'q':
7680Sstevel@tonic-gate 	case 'x':
7690Sstevel@tonic-gate 		wp = domod(cp, type);
7700Sstevel@tonic-gate 		if (wp == 0)
7710Sstevel@tonic-gate 			return (savestr(cp));
7720Sstevel@tonic-gate 		*adid = 1;
7730Sstevel@tonic-gate 		return (wp);
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	default:
7760Sstevel@tonic-gate 		wp = wbuf;
7770Sstevel@tonic-gate 		i = BUFSIZ - 4;
7780Sstevel@tonic-gate 		for (mp = cp; *mp; mp++)
7790Sstevel@tonic-gate 			if (matchs(mp, lhsb)) {
780559Snakanon 				for (np = cp; np < mp; )
7810Sstevel@tonic-gate 					*wp++ = *np++, --i;
7820Sstevel@tonic-gate 				for (np = rhsb; *np; np++) switch (*np) {
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 				case '\\':
7850Sstevel@tonic-gate 					if (np[1] == '&')
7860Sstevel@tonic-gate 						np++;
7870Sstevel@tonic-gate 					/* fall into ... */
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 				default:
7900Sstevel@tonic-gate 					if (--i < 0)
7910Sstevel@tonic-gate 						goto ovflo;
7920Sstevel@tonic-gate 					*wp++ = *np;
7930Sstevel@tonic-gate 					continue;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 				case '&':
7960Sstevel@tonic-gate 					i -= strlen_(lhsb);
7970Sstevel@tonic-gate 					if (i < 0)
7980Sstevel@tonic-gate 						goto ovflo;
7990Sstevel@tonic-gate 					*wp = 0;
8000Sstevel@tonic-gate 					(void) strcat_(wp, lhsb);
8010Sstevel@tonic-gate 					wp = strend(wp);
8020Sstevel@tonic-gate 					continue;
8030Sstevel@tonic-gate 				}
8040Sstevel@tonic-gate 				mp += strlen_(lhsb);
8050Sstevel@tonic-gate 				i -= strlen_(mp);
8060Sstevel@tonic-gate 				if (i < 0) {
8070Sstevel@tonic-gate ovflo:
8080Sstevel@tonic-gate 					seterr("Subst buf ovflo");
809559Snakanon 					return (S_ /* "" */);
8100Sstevel@tonic-gate 				}
8110Sstevel@tonic-gate 				*wp = 0;
8120Sstevel@tonic-gate 				(void) strcat_(wp, mp);
8130Sstevel@tonic-gate 				*adid = 1;
8140Sstevel@tonic-gate 				return (savestr(wbuf));
8150Sstevel@tonic-gate 			}
8160Sstevel@tonic-gate 		return (savestr(cp));
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate tchar *
domod(tchar * cp,int type)821356Smuffin domod(tchar *cp, int type)
8220Sstevel@tonic-gate {
823356Smuffin 	tchar *wp, *xp;
824356Smuffin 	int c;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate #ifdef TRACE
8270Sstevel@tonic-gate 	tprintf("TRACE- domod()\n");
8280Sstevel@tonic-gate #endif
8290Sstevel@tonic-gate 	switch (type) {
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	case 'x':
8320Sstevel@tonic-gate 	case 'q':
8330Sstevel@tonic-gate 		wp = savestr(cp);
8340Sstevel@tonic-gate 		for (xp = wp; c = *xp; xp++)
8350Sstevel@tonic-gate 			if (!issp(c) || type == 'q')
8360Sstevel@tonic-gate 				*xp |= QUOTE;
8370Sstevel@tonic-gate 		return (wp);
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	case 'h':
8400Sstevel@tonic-gate 	case 't':
8410Sstevel@tonic-gate 		if (!any('/', cp))
8420Sstevel@tonic-gate 			return (type == 't' ? savestr(cp) : 0);
8430Sstevel@tonic-gate 		wp = strend(cp);
8440Sstevel@tonic-gate 		while (*--wp != '/')
8450Sstevel@tonic-gate 			continue;
8460Sstevel@tonic-gate 		if (type == 'h')
8470Sstevel@tonic-gate 			xp = savestr(cp), xp[wp - cp] = 0;
8480Sstevel@tonic-gate 		else
8490Sstevel@tonic-gate 			xp = savestr(wp + 1);
8500Sstevel@tonic-gate 		return (xp);
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	case 'e':
8530Sstevel@tonic-gate 	case 'r':
8540Sstevel@tonic-gate 		wp = strend(cp);
8550Sstevel@tonic-gate 		for (wp--; wp >= cp && *wp != '/'; wp--)
8560Sstevel@tonic-gate 			if (*wp == '.') {
8570Sstevel@tonic-gate 				if (type == 'e')
8580Sstevel@tonic-gate 					xp = savestr(wp + 1);
8590Sstevel@tonic-gate 				else
8600Sstevel@tonic-gate 					xp = savestr(cp), xp[wp - cp] = 0;
8610Sstevel@tonic-gate 				return (xp);
8620Sstevel@tonic-gate 			}
863559Snakanon 		return (savestr(type == 'e' ? S_ /* "" */ : cp));
8640Sstevel@tonic-gate 	}
8650Sstevel@tonic-gate 	return (0);
8660Sstevel@tonic-gate }
8670Sstevel@tonic-gate 
868356Smuffin int
matchs(tchar * str,tchar * pat)869356Smuffin matchs(tchar *str, tchar *pat)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate #ifdef TRACE
8730Sstevel@tonic-gate 	tprintf("TRACE- matchs()\n");
8740Sstevel@tonic-gate #endif
8750Sstevel@tonic-gate 	while (*str && *pat && *str == *pat)
8760Sstevel@tonic-gate 		str++, pat++;
8770Sstevel@tonic-gate 	return (*pat == 0);
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate 
880356Smuffin int
getsel(int * al,int * ar,int dol)881356Smuffin getsel(int *al, int *ar, int dol)
8820Sstevel@tonic-gate {
883356Smuffin 	int c = getC(0);
884356Smuffin 	int i;
8850Sstevel@tonic-gate 	bool first = *al < 0;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate #ifdef TRACE
8880Sstevel@tonic-gate 	tprintf("TRACE- getsel()\n");
8890Sstevel@tonic-gate #endif
8900Sstevel@tonic-gate 	switch (c) {
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	case '%':
8930Sstevel@tonic-gate 		if (quesarg == -1)
8940Sstevel@tonic-gate 			goto bad;
8950Sstevel@tonic-gate 		if (*al < 0)
8960Sstevel@tonic-gate 			*al = quesarg;
8970Sstevel@tonic-gate 		*ar = quesarg;
8980Sstevel@tonic-gate 		break;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	case '-':
9010Sstevel@tonic-gate 		if (*al < 0) {
9020Sstevel@tonic-gate 			*al = 0;
9030Sstevel@tonic-gate 			*ar = dol - 1;
9040Sstevel@tonic-gate 			unreadc(c);
9050Sstevel@tonic-gate 		}
9060Sstevel@tonic-gate 		return (1);
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	case '^':
9090Sstevel@tonic-gate 		if (*al < 0)
9100Sstevel@tonic-gate 			*al = 1;
9110Sstevel@tonic-gate 		*ar = 1;
9120Sstevel@tonic-gate 		break;
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	case '$':
9150Sstevel@tonic-gate 		if (*al < 0)
9160Sstevel@tonic-gate 			*al = dol;
9170Sstevel@tonic-gate 		*ar = dol;
9180Sstevel@tonic-gate 		break;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	case '*':
9210Sstevel@tonic-gate 		if (*al < 0)
9220Sstevel@tonic-gate 			*al = 1;
9230Sstevel@tonic-gate 		*ar = dol;
9240Sstevel@tonic-gate 		if (*ar < *al) {
9250Sstevel@tonic-gate 			*ar = 0;
9260Sstevel@tonic-gate 			*al = 1;
9270Sstevel@tonic-gate 			return (1);
9280Sstevel@tonic-gate 		}
9290Sstevel@tonic-gate 		break;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	default:
9320Sstevel@tonic-gate 		if (digit(c)) {
9330Sstevel@tonic-gate 			i = 0;
9340Sstevel@tonic-gate 			while (digit(c)) {
9350Sstevel@tonic-gate 				i = i * 10 + c - '0';
9360Sstevel@tonic-gate 				c = getC(0);
9370Sstevel@tonic-gate 			}
9380Sstevel@tonic-gate 			if (i < 0)
9390Sstevel@tonic-gate 				i = dol + 1;
9400Sstevel@tonic-gate 			if (*al < 0)
9410Sstevel@tonic-gate 				*al = i;
9420Sstevel@tonic-gate 			*ar = i;
9430Sstevel@tonic-gate 		} else
9440Sstevel@tonic-gate 			if (*al < 0)
9450Sstevel@tonic-gate 				*al = 0, *ar = dol;
9460Sstevel@tonic-gate 			else
9470Sstevel@tonic-gate 				*ar = dol - 1;
9480Sstevel@tonic-gate 		unreadc(c);
9490Sstevel@tonic-gate 		break;
9500Sstevel@tonic-gate 	}
9510Sstevel@tonic-gate 	if (first) {
9520Sstevel@tonic-gate 		c = getC(0);
9530Sstevel@tonic-gate 		unreadc(c);
9540Sstevel@tonic-gate 		/* if (any(c, "-$*")) */	/* char -> tchar */
9550Sstevel@tonic-gate 		if (c == '-' || c == '$' || c == '*')
9560Sstevel@tonic-gate 			return (1);
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 	if (*al > *ar || *ar > dol) {
9590Sstevel@tonic-gate bad:
9600Sstevel@tonic-gate 		seterr("Bad ! arg selector");
9610Sstevel@tonic-gate 		return (0);
9620Sstevel@tonic-gate 	}
9630Sstevel@tonic-gate 	return (1);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate struct wordent *
gethent(int sc)968356Smuffin gethent(int sc)
9690Sstevel@tonic-gate {
970356Smuffin 	struct Hist *hp;
971356Smuffin 	tchar *np;
972356Smuffin 	int c;
9730Sstevel@tonic-gate 	int event;
9740Sstevel@tonic-gate 	bool back = 0;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate #ifdef TRACE
9770Sstevel@tonic-gate 	tprintf("TRACE- gethent()\n");
9780Sstevel@tonic-gate #endif
9790Sstevel@tonic-gate 	c = sc == HISTSUB ? HIST : getC(0);
9800Sstevel@tonic-gate 	if (c == HIST) {
9810Sstevel@tonic-gate 		if (alhistp)
9820Sstevel@tonic-gate 			return (alhistp);
9830Sstevel@tonic-gate 		event = eventno;
9840Sstevel@tonic-gate 		goto skip;
9850Sstevel@tonic-gate 	}
9860Sstevel@tonic-gate 	switch (c) {
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	case ':':
9890Sstevel@tonic-gate 	case '^':
9900Sstevel@tonic-gate 	case '$':
9910Sstevel@tonic-gate 	case '*':
9920Sstevel@tonic-gate 	case '%':
9930Sstevel@tonic-gate 		ungetC(c);
9940Sstevel@tonic-gate 		if (lastev == eventno && alhistp)
9950Sstevel@tonic-gate 			return (alhistp);
9960Sstevel@tonic-gate 		event = lastev;
9970Sstevel@tonic-gate 		break;
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	case '-':
10000Sstevel@tonic-gate 		back = 1;
10010Sstevel@tonic-gate 		c = getC(0);
10020Sstevel@tonic-gate 		goto number;
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	case '#':			/* !# is command being typed in (mrh) */
1005559Snakanon 		return (&paraml);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	default:
1008559Snakanon 		/* if (any(c, "(=~")) { */
10090Sstevel@tonic-gate 		if (c == '(' || c == '=' || c == '~') {
10100Sstevel@tonic-gate 			unreadc(c);
10110Sstevel@tonic-gate 			ungetC(HIST);
10120Sstevel@tonic-gate 			return (0);
10130Sstevel@tonic-gate 		}
10140Sstevel@tonic-gate 		if (digit(c))
10150Sstevel@tonic-gate 			goto number;
10160Sstevel@tonic-gate 		np = lhsb;
10170Sstevel@tonic-gate 		/* while (!any(c, ": \t\\\n}")) { */
10180Sstevel@tonic-gate 		while (! (c == ':' || c == '\\' || isspnl(c) || c == '}')) {
10190Sstevel@tonic-gate 			if (np < &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
10200Sstevel@tonic-gate 				*np++ = c;
10210Sstevel@tonic-gate 			c = getC(0);
10220Sstevel@tonic-gate 		}
10230Sstevel@tonic-gate 		unreadc(c);
10240Sstevel@tonic-gate 		if (np == lhsb) {
10250Sstevel@tonic-gate 			ungetC(HIST);
10260Sstevel@tonic-gate 			return (0);
10270Sstevel@tonic-gate 		}
10280Sstevel@tonic-gate 		*np++ = 0;
10290Sstevel@tonic-gate 		hp = findev(lhsb, 0);
10300Sstevel@tonic-gate 		if (hp)
10310Sstevel@tonic-gate 			lastev = hp->Hnum;
10320Sstevel@tonic-gate 		return (&hp->Hlex);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	case '?':
10350Sstevel@tonic-gate 		np = lhsb;
10360Sstevel@tonic-gate 		for (;;) {
10370Sstevel@tonic-gate 			c = getC(0);
10380Sstevel@tonic-gate 			if (c == '\n') {
10390Sstevel@tonic-gate 				unreadc(c);
10400Sstevel@tonic-gate 				break;
10410Sstevel@tonic-gate 			}
10420Sstevel@tonic-gate 			if (c == '?')
10430Sstevel@tonic-gate 				break;
10440Sstevel@tonic-gate 			if (np < &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
10450Sstevel@tonic-gate 				*np++ = c;
10460Sstevel@tonic-gate 		}
10470Sstevel@tonic-gate 		if (np == lhsb) {
10480Sstevel@tonic-gate 			if (lhsb[0] == 0) {
10490Sstevel@tonic-gate 				seterr("No prev search");
10500Sstevel@tonic-gate 				return (0);
10510Sstevel@tonic-gate 			}
10520Sstevel@tonic-gate 		} else
10530Sstevel@tonic-gate 			*np++ = 0;
10540Sstevel@tonic-gate 		hp = findev(lhsb, 1);
10550Sstevel@tonic-gate 		if (hp)
10560Sstevel@tonic-gate 			lastev = hp->Hnum;
10570Sstevel@tonic-gate 		return (&hp->Hlex);
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	number:
10600Sstevel@tonic-gate 		event = 0;
10610Sstevel@tonic-gate 		while (digit(c)) {
10620Sstevel@tonic-gate 			event = event * 10 + c - '0';
10630Sstevel@tonic-gate 			c = getC(0);
10640Sstevel@tonic-gate 		}
10650Sstevel@tonic-gate 		if (back)
10660Sstevel@tonic-gate 			event = eventno + (alhistp == 0) - (event ? event : 0);
10670Sstevel@tonic-gate 		unreadc(c);
10680Sstevel@tonic-gate 		break;
10690Sstevel@tonic-gate 	}
10700Sstevel@tonic-gate skip:
10710Sstevel@tonic-gate 	for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
10720Sstevel@tonic-gate 		if (hp->Hnum == event) {
10730Sstevel@tonic-gate 			hp->Href = eventno;
10740Sstevel@tonic-gate 			lastev = hp->Hnum;
10750Sstevel@tonic-gate 			return (&hp->Hlex);
10760Sstevel@tonic-gate 		}
10770Sstevel@tonic-gate 	np = putn(event);
10780Sstevel@tonic-gate 	noev(np);
10790Sstevel@tonic-gate 	return (0);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate struct Hist *
findev(tchar * cp,bool anyarg)1083356Smuffin findev(tchar *cp, bool anyarg)
10840Sstevel@tonic-gate {
1085356Smuffin 	struct Hist *hp;
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate #ifdef TRACE
10880Sstevel@tonic-gate 	tprintf("TRACE- findev()\n");
10890Sstevel@tonic-gate #endif
10900Sstevel@tonic-gate 	for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
1091356Smuffin 		tchar *dp;
1092356Smuffin 		tchar *p, *q;
1093356Smuffin 		struct wordent *lp = hp->Hlex.next;
10940Sstevel@tonic-gate 		int argno = 0;
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 		if (lp->word[0] == '\n')
10970Sstevel@tonic-gate 			continue;
10980Sstevel@tonic-gate 		if (!anyarg) {
10990Sstevel@tonic-gate 			p = cp;
11000Sstevel@tonic-gate 			q = lp->word;
11010Sstevel@tonic-gate 			do
11020Sstevel@tonic-gate 				if (!*p)
11030Sstevel@tonic-gate 					return (hp);
11040Sstevel@tonic-gate 			while (*p++ == *q++);
11050Sstevel@tonic-gate 			continue;
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 		do {
11080Sstevel@tonic-gate 			for (dp = lp->word; *dp; dp++) {
11090Sstevel@tonic-gate 				p = cp;
11100Sstevel@tonic-gate 				q = dp;
11110Sstevel@tonic-gate 				do
11120Sstevel@tonic-gate 					if (!*p) {
11130Sstevel@tonic-gate 						quesarg = argno;
11140Sstevel@tonic-gate 						return (hp);
11150Sstevel@tonic-gate 					}
11160Sstevel@tonic-gate 				while (*p++ == *q++);
11170Sstevel@tonic-gate 			}
11180Sstevel@tonic-gate 			lp = lp->next;
11190Sstevel@tonic-gate 			argno++;
11200Sstevel@tonic-gate 		} while (lp->word[0] != '\n');
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 	noev(cp);
11230Sstevel@tonic-gate 	return (0);
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate 
1126356Smuffin void
noev(tchar * cp)1127356Smuffin noev(tchar *cp)
11280Sstevel@tonic-gate {
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate #ifdef TRACE
11310Sstevel@tonic-gate 	tprintf("TRACE- noev()\n");
11320Sstevel@tonic-gate #endif
11330Sstevel@tonic-gate 	seterr2(cp, ": Event not found");
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate 
1136356Smuffin void
setexclp(tchar * cp)1137356Smuffin setexclp(tchar *cp)
11380Sstevel@tonic-gate {
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate #ifdef TRACE
11410Sstevel@tonic-gate 	tprintf("TRACE- setexclp()\n");
11420Sstevel@tonic-gate #endif
11430Sstevel@tonic-gate 	if (cp && cp[0] == '\n')
11440Sstevel@tonic-gate 		return;
11450Sstevel@tonic-gate 	exclp = cp;
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate 
1148356Smuffin void
unreadc(tchar c)1149356Smuffin unreadc(tchar c)
11500Sstevel@tonic-gate {
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	peekread = c;
11530Sstevel@tonic-gate }
11540Sstevel@tonic-gate 
1155356Smuffin int
readc(bool wanteof)1156356Smuffin readc(bool wanteof)
11570Sstevel@tonic-gate {
1158356Smuffin 	int c;
1159356Smuffin 	static int sincereal;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	if (c = peekread) {
11620Sstevel@tonic-gate 		peekread = 0;
11630Sstevel@tonic-gate 		return (c);
11640Sstevel@tonic-gate 	}
11650Sstevel@tonic-gate top:
11660Sstevel@tonic-gate 	if (alvecp) {
11670Sstevel@tonic-gate 		if (c = *alvecp++)
11680Sstevel@tonic-gate 			return (c);
11690Sstevel@tonic-gate 		if (*alvec) {
11700Sstevel@tonic-gate 			alvecp = *alvec++;
11710Sstevel@tonic-gate 			return (' ');
11720Sstevel@tonic-gate 		}
11730Sstevel@tonic-gate 	}
11740Sstevel@tonic-gate 	if (alvec) {
11750Sstevel@tonic-gate 		if (alvecp = *alvec) {
11760Sstevel@tonic-gate 			alvec++;
11770Sstevel@tonic-gate 			goto top;
11780Sstevel@tonic-gate 		}
11790Sstevel@tonic-gate 		/* Infinite source! */
11800Sstevel@tonic-gate 		return ('\n');
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 	if (evalp) {
11830Sstevel@tonic-gate 		if (c = *evalp++)
11840Sstevel@tonic-gate 			return (c);
11850Sstevel@tonic-gate 		if (*evalvec) {
11860Sstevel@tonic-gate 			evalp = *evalvec++;
11870Sstevel@tonic-gate 			return (' ');
11880Sstevel@tonic-gate 		}
11890Sstevel@tonic-gate 		evalp = 0;
11900Sstevel@tonic-gate 	}
11910Sstevel@tonic-gate 	if (evalvec) {
11920Sstevel@tonic-gate 		if (evalvec ==  (tchar **)1) {
11930Sstevel@tonic-gate 			doneinp = 1;
11940Sstevel@tonic-gate 			reset();
11950Sstevel@tonic-gate 		}
11960Sstevel@tonic-gate 		if (evalp = *evalvec) {
11970Sstevel@tonic-gate 			evalvec++;
11980Sstevel@tonic-gate 			goto top;
11990Sstevel@tonic-gate 		}
12000Sstevel@tonic-gate 		evalvec =  (tchar **)1;
12010Sstevel@tonic-gate 		return ('\n');
12020Sstevel@tonic-gate 	}
12030Sstevel@tonic-gate 	do {
12040Sstevel@tonic-gate 		if (arginp ==  (tchar *) 1 || onelflg == 1) {
12050Sstevel@tonic-gate 			if (wanteof)
12060Sstevel@tonic-gate 				return (-1);
12070Sstevel@tonic-gate 			exitstat();
12080Sstevel@tonic-gate 		}
12090Sstevel@tonic-gate 		if (arginp) {
12100Sstevel@tonic-gate 			if ((c = *arginp++) == 0) {
12110Sstevel@tonic-gate 				arginp =  (tchar *) 1;
12120Sstevel@tonic-gate 				return ('\n');
12130Sstevel@tonic-gate 			}
12140Sstevel@tonic-gate 			return (c);
12150Sstevel@tonic-gate 		}
12160Sstevel@tonic-gate reread:
12170Sstevel@tonic-gate 		c = bgetc();
12180Sstevel@tonic-gate 		if (c < 0) {
12190Sstevel@tonic-gate 			struct sgttyb tty;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 			if (wanteof)
12220Sstevel@tonic-gate 				return (-1);
12230Sstevel@tonic-gate 			/* was isatty but raw with ignoreeof yields problems */
12240Sstevel@tonic-gate 			if (ioctl(SHIN, TIOCGETP,  (char *)&tty) == 0 &&
12250Sstevel@tonic-gate 			    (tty.sg_flags & RAW) == 0) {
12260Sstevel@tonic-gate 				/* was 'short' for FILEC */
12270Sstevel@tonic-gate 				int ctpgrp;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 				if (++sincereal > 25)
12300Sstevel@tonic-gate 					goto oops;
12310Sstevel@tonic-gate 				if (tpgrp != -1 &&
1232559Snakanon 				    ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp) == 0 &&
12330Sstevel@tonic-gate 				    tpgrp != ctpgrp) {
12340Sstevel@tonic-gate 					(void) ioctl(FSHTTY, TIOCSPGRP,
1235559Snakanon 						(char *)&tpgrp);
12360Sstevel@tonic-gate 					(void) killpg(ctpgrp, SIGHUP);
12370Sstevel@tonic-gate printf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp);
12380Sstevel@tonic-gate 					goto reread;
12390Sstevel@tonic-gate 				}
1240559Snakanon 				if (adrof(S_ignoreeof /* "ignoreeof" */)) {
12410Sstevel@tonic-gate 					if (loginsh)
1242559Snakanon 				printf("\nUse \"logout\" to logout.\n");
12430Sstevel@tonic-gate 					else
1244559Snakanon 				printf("\nUse \"exit\" to leave csh.\n");
12450Sstevel@tonic-gate 					reset();
12460Sstevel@tonic-gate 				}
12470Sstevel@tonic-gate 				if (chkstop == 0) {
12480Sstevel@tonic-gate 					panystop(1);
12490Sstevel@tonic-gate 				}
12500Sstevel@tonic-gate 			}
12510Sstevel@tonic-gate oops:
12520Sstevel@tonic-gate 			doneinp = 1;
12530Sstevel@tonic-gate 			reset();
12540Sstevel@tonic-gate 		}
12550Sstevel@tonic-gate 		sincereal = 0;
12560Sstevel@tonic-gate 		if (c == '\n' && onelflg)
12570Sstevel@tonic-gate 			onelflg--;
12580Sstevel@tonic-gate 	} while (c == 0);
12590Sstevel@tonic-gate 	return (c);
12600Sstevel@tonic-gate }
12610Sstevel@tonic-gate 
1262559Snakanon static void
expand_fbuf(void)1263559Snakanon expand_fbuf(void)
1264559Snakanon {
1265559Snakanon 	tchar **nfbuf =
1266559Snakanon 	    (tchar **)xcalloc((unsigned)(fblocks + 2), sizeof (tchar **));
1267559Snakanon 
1268559Snakanon 	if (fbuf) {
1269559Snakanon 		(void) blkcpy(nfbuf, fbuf);
1270559Snakanon 		xfree((char *)fbuf);
1271559Snakanon 	}
1272559Snakanon 	fbuf = nfbuf;
1273559Snakanon 	fbuf[fblocks] = (tchar *)xcalloc(BUFSIZ + MB_LEN_MAX,
1274559Snakanon 		sizeof (tchar));
1275559Snakanon 	fblocks++;
1276559Snakanon }
1277559Snakanon 
1278356Smuffin int
bgetc(void)1279356Smuffin bgetc(void)
12800Sstevel@tonic-gate {
1281356Smuffin 	int buf, off, c;
12820Sstevel@tonic-gate #ifdef FILEC
1283559Snakanon 	tchar ttyline[BUFSIZ + MB_LEN_MAX]; /* read_() can return extra bytes */
1284559Snakanon 	int roomleft;
12850Sstevel@tonic-gate #endif
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate #ifdef TELL
12880Sstevel@tonic-gate 	if (cantell) {
12890Sstevel@tonic-gate 		if (fseekp < fbobp || fseekp > feobp) {
12900Sstevel@tonic-gate 			fbobp = feobp = fseekp;
12910Sstevel@tonic-gate 			(void) lseek(SHIN, fseekp, 0);
12920Sstevel@tonic-gate 		}
12930Sstevel@tonic-gate 		if (fseekp == feobp) {
12940Sstevel@tonic-gate 			fbobp = feobp;
12950Sstevel@tonic-gate 			do
12960Sstevel@tonic-gate 				c = read_(SHIN, fbuf[0], BUFSIZ);
12970Sstevel@tonic-gate 			while (c < 0 && errno == EINTR);
12980Sstevel@tonic-gate 			if (c <= 0)
12990Sstevel@tonic-gate 				return (-1);
13000Sstevel@tonic-gate 			feobp += c;
13010Sstevel@tonic-gate 		}
13020Sstevel@tonic-gate 		c = fbuf[0][fseekp - fbobp];
13030Sstevel@tonic-gate 		fseekp++;
13040Sstevel@tonic-gate 		return (c);
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate #endif
13070Sstevel@tonic-gate again:
1308559Snakanon 	buf = (int)fseekp / BUFSIZ;
13090Sstevel@tonic-gate 	if (buf >= fblocks) {
1310559Snakanon 		expand_fbuf();
13110Sstevel@tonic-gate 		goto again;
13120Sstevel@tonic-gate 	}
13130Sstevel@tonic-gate 	if (fseekp >= feobp) {
1314559Snakanon 		buf = (int)feobp / BUFSIZ;
1315559Snakanon 		off = (int)feobp % BUFSIZ;
13160Sstevel@tonic-gate #ifndef FILEC
13170Sstevel@tonic-gate 		for (;;) {
13180Sstevel@tonic-gate 			c = read_(SHIN, fbuf[buf] + off, BUFSIZ - off);
13190Sstevel@tonic-gate #else
13200Sstevel@tonic-gate 		roomleft = BUFSIZ - off;
13210Sstevel@tonic-gate 		for (;;) {
13220Sstevel@tonic-gate 			if (filec && intty) {
1323559Snakanon 				c = tenex(ttyline, BUFSIZ);
13240Sstevel@tonic-gate 				if (c > roomleft) {
1325559Snakanon 					expand_fbuf();
1326559Snakanon 					copy(fbuf[buf] + off, ttyline,
1327559Snakanon 					    roomleft * sizeof (tchar));
1328559Snakanon 					copy(fbuf[buf + 1], ttyline + roomleft,
1329559Snakanon 					    (c - roomleft) * sizeof (tchar));
1330559Snakanon 				} else if (c > 0) {
1331559Snakanon 					copy(fbuf[buf] + off, ttyline,
1332559Snakanon 						c * sizeof (tchar));
13330Sstevel@tonic-gate 				}
1334559Snakanon 			} else {
13350Sstevel@tonic-gate 				c = read_(SHIN, fbuf[buf] + off, roomleft);
1336559Snakanon 				if (c > roomleft) {
1337559Snakanon 					expand_fbuf();
1338559Snakanon 					copy(fbuf[buf + 1],
1339559Snakanon 					    fbuf[buf] + off + roomleft,
1340559Snakanon 					    (c - roomleft) * sizeof (tchar));
1341559Snakanon 				}
1342559Snakanon 			}
13430Sstevel@tonic-gate #endif
13440Sstevel@tonic-gate 			if (c >= 0)
13450Sstevel@tonic-gate 				break;
13460Sstevel@tonic-gate 			if (errno == EWOULDBLOCK) {
13470Sstevel@tonic-gate 				int off = 0;
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 				(void) ioctl(SHIN, FIONBIO,  (char *)&off);
13500Sstevel@tonic-gate 			} else if (errno != EINTR)
13510Sstevel@tonic-gate 				break;
13520Sstevel@tonic-gate 		}
13530Sstevel@tonic-gate 		if (c <= 0)
13540Sstevel@tonic-gate 			return (-1);
13550Sstevel@tonic-gate 		feobp += c;
13560Sstevel@tonic-gate #ifndef FILEC
13570Sstevel@tonic-gate 		goto again;
13580Sstevel@tonic-gate #else
13590Sstevel@tonic-gate 		if (filec && !intty)
13600Sstevel@tonic-gate 			goto again;
13610Sstevel@tonic-gate #endif
13620Sstevel@tonic-gate 	}
1363559Snakanon 	c = fbuf[buf][(int)fseekp % BUFSIZ];
13640Sstevel@tonic-gate 	fseekp++;
13650Sstevel@tonic-gate 	return (c);
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate 
1368559Snakanon void
1369356Smuffin bfree(void)
13700Sstevel@tonic-gate {
1371356Smuffin 	int sb, i;
13720Sstevel@tonic-gate 
13730Sstevel@tonic-gate #ifdef TELL
13740Sstevel@tonic-gate 	if (cantell)
13750Sstevel@tonic-gate 		return;
13760Sstevel@tonic-gate #endif
13770Sstevel@tonic-gate 	if (whyles)
13780Sstevel@tonic-gate 		return;
1379559Snakanon 	sb = (int)(fseekp - 1) / BUFSIZ;
13800Sstevel@tonic-gate 	if (sb > 0) {
13810Sstevel@tonic-gate 		for (i = 0; i < sb; i++)
13820Sstevel@tonic-gate 			xfree(fbuf[i]);
13830Sstevel@tonic-gate 		(void) blkcpy(fbuf, &fbuf[sb]);
13840Sstevel@tonic-gate 		fseekp -= BUFSIZ * sb;
13850Sstevel@tonic-gate 		feobp -= BUFSIZ * sb;
13860Sstevel@tonic-gate 		fblocks -= sb;
13870Sstevel@tonic-gate 	}
13880Sstevel@tonic-gate }
13890Sstevel@tonic-gate 
1390356Smuffin void
1391356Smuffin bseek(off_t l)
13920Sstevel@tonic-gate {
1393356Smuffin 	struct whyle *wp;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	fseekp = l;
13960Sstevel@tonic-gate #ifdef TELL
13970Sstevel@tonic-gate 	if (!cantell) {
13980Sstevel@tonic-gate #endif
13990Sstevel@tonic-gate 		if (!whyles)
14000Sstevel@tonic-gate 			return;
14010Sstevel@tonic-gate 		for (wp = whyles; wp->w_next; wp = wp->w_next)
14020Sstevel@tonic-gate 			continue;
14030Sstevel@tonic-gate 		if (wp->w_start > l)
14040Sstevel@tonic-gate 			l = wp->w_start;
14050Sstevel@tonic-gate #ifdef TELL
14060Sstevel@tonic-gate 	}
14070Sstevel@tonic-gate #endif
14080Sstevel@tonic-gate }
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate /* any similarity to bell telephone is purely accidental */
14110Sstevel@tonic-gate #ifndef btell
14120Sstevel@tonic-gate off_t
1413356Smuffin btell(void)
14140Sstevel@tonic-gate {
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	return (fseekp);
14170Sstevel@tonic-gate }
14180Sstevel@tonic-gate #endif
14190Sstevel@tonic-gate 
1420356Smuffin void
1421356Smuffin btoeof(void)
14220Sstevel@tonic-gate {
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	(void) lseek(SHIN, (off_t)0, 2);
14250Sstevel@tonic-gate 	fseekp = feobp;
14260Sstevel@tonic-gate 	wfree();
14270Sstevel@tonic-gate 	bfree();
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate #ifdef TELL
1431356Smuffin void
1432356Smuffin settell(void)
14330Sstevel@tonic-gate {
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	cantell = 0;
14360Sstevel@tonic-gate 	if (arginp || onelflg || intty)
14370Sstevel@tonic-gate 		return;
14380Sstevel@tonic-gate 	if (lseek(SHIN, (off_t)0, 1) < 0 || errno == ESPIPE)
14390Sstevel@tonic-gate 		return;
1440559Snakanon 	fbuf = (tchar **)xcalloc(2, sizeof (tchar **));
14410Sstevel@tonic-gate 	fblocks = 1;
1442559Snakanon 	fbuf[0] = (tchar *)xcalloc(BUFSIZ + MB_LEN_MAX, sizeof (tchar));
14430Sstevel@tonic-gate 	fseekp = fbobp = feobp = lseek(SHIN, (off_t)0, 1);
14440Sstevel@tonic-gate 	cantell = 1;
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate #endif
1447