Home | History | Annotate | Download | only in csh
      1     0   stevel /*
      2  2182     chin  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
      3     0   stevel  * Use is subject to license terms.
      4     0   stevel  */
      5     0   stevel 
      6     0   stevel /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7     0   stevel /*	  All Rights Reserved  	*/
      8     0   stevel 
      9     0   stevel /*
     10     0   stevel  * Copyright (c) 1980 Regents of the University of California.
     11     0   stevel  * All rights reserved.  The Berkeley Software License Agreement
     12     0   stevel  * specifies the terms and conditions for redistribution.
     13     0   stevel  */
     14     0   stevel 
     15     0   stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     16     0   stevel 
     17     0   stevel #include <unistd.h>	/* for lseek prototype */
     18     0   stevel #include "sh.h"
     19     0   stevel #include "sh.tconst.h"
     20     0   stevel #include <sys/filio.h>
     21     0   stevel #include <sys/ttold.h>
     22   559  nakanon #define	RAW 	O_RAW
     23     0   stevel /*
     24     0   stevel  * C shell
     25     0   stevel  */
     26     0   stevel 
     27     0   stevel /*
     28     0   stevel  * These lexical routines read input and form lists of words.
     29     0   stevel  * There is some involved processing here, because of the complications
     30     0   stevel  * of input buffering, and especially because of history substitution.
     31     0   stevel  */
     32     0   stevel 
     33   356   muffin tchar	*word(void);
     34   356   muffin tchar	getC1(int);
     35   356   muffin tchar	*subword(tchar *, int, bool *);
     36   356   muffin void	getdol(void);
     37   356   muffin void	addla(tchar *);
     38   356   muffin void	getexcl(tchar);
     39   356   muffin void	noev(tchar *);
     40   356   muffin void	setexclp(tchar *);
     41   356   muffin void	unreadc(tchar);
     42   356   muffin int	readc(bool);
     43   356   muffin struct wordent	*dosub(int, struct wordent *, bool);
     44   356   muffin struct Hist	*findev(tchar *, bool);
     45   356   muffin struct wordent	*gethent(int);
     46   356   muffin struct wordent	*getsub(struct wordent *);
     47     0   stevel 
     48     0   stevel /*
     49     0   stevel  * Peekc is a peek characer for getC, peekread for readc.
     50     0   stevel  * There is a subtlety here in many places... history routines
     51     0   stevel  * will read ahead and then insert stuff into the input stream.
     52     0   stevel  * If they push back a character then they must push it behind
     53     0   stevel  * the text substituted by the history substitution.  On the other
     54     0   stevel  * hand in several places we need 2 peek characters.  To make this
     55     0   stevel  * all work, the history routines read with getC, and make use both
     56     0   stevel  * of ungetC and unreadc.  The key observation is that the state
     57     0   stevel  * of getC at the call of a history reference is such that calls
     58     0   stevel  * to getC from the history routines will always yield calls of
     59     0   stevel  * readc, unless this peeking is involved.  That is to say that during
     60     0   stevel  * getexcl the variables lap, exclp, and exclnxt are all zero.
     61     0   stevel  *
     62     0   stevel  * Getdol invokes history substitution, hence the extra peek, peekd,
     63     0   stevel  * which it can ungetD to be before history substitutions.
     64     0   stevel  */
     65     0   stevel tchar peekc, peekd;
     66     0   stevel tchar peekread;
     67     0   stevel 
     68     0   stevel tchar *exclp;			/* (Tail of) current word from ! subst */
     69     0   stevel struct	wordent *exclnxt;	/* The rest of the ! subst words */
     70     0   stevel int	exclc;			/* Count of remainig words in ! subst */
     71     0   stevel tchar *alvecp;		/* "Globp" for alias resubstitution */
     72     0   stevel 
     73     0   stevel /*
     74     0   stevel  * Lex returns to its caller not only a wordlist (as a "var" parameter)
     75     0   stevel  * but also whether a history substitution occurred.  This is used in
     76     0   stevel  * the main (process) routine to determine whether to echo, and also
     77     0   stevel  * when called by the alias routine to determine whether to keep the
     78     0   stevel  * argument list.
     79     0   stevel  */
     80     0   stevel bool	hadhist;
     81     0   stevel 
     82     0   stevel tchar getCtmp;
     83   559  nakanon #define	getC(f)		((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
     84     0   stevel #define	ungetC(c)	peekc = c
     85     0   stevel #define	ungetD(c)	peekd = c
     86     0   stevel 
     87   356   muffin bool
     88   356   muffin lex(struct wordent *hp)
     89     0   stevel {
     90   356   muffin 	struct wordent *wdp;
     91     0   stevel 	int c;
     92     0   stevel 
     93     0   stevel #ifdef TRACE
     94     0   stevel 	tprintf("TRACE- lex()\n");
     95     0   stevel #endif
     96     0   stevel 	lineloc = btell();
     97     0   stevel 	hp->next = hp->prev = hp;
     98   559  nakanon 	hp->word = S_ /* "" */;
     99     0   stevel 	alvecp = 0, hadhist = 0;
    100     0   stevel 	do
    101     0   stevel 		c = readc(0);
    102     0   stevel 	while (issp(c));
    103     0   stevel 	/* make sure history is enabled */
    104     0   stevel 	if (HIST && c == HISTSUB && intty)
    105     0   stevel 		/* ^lef^rit	from tty is short !:s^lef^rit */
    106     0   stevel 		getexcl(c);
    107     0   stevel 	else
    108     0   stevel 		unreadc(c);
    109     0   stevel 	wdp = hp;
    110     0   stevel 	/*
    111     0   stevel 	 * The following loop is written so that the links needed
    112     0   stevel 	 * by freelex will be ready and rarin to go even if it is
    113     0   stevel 	 * interrupted.
    114     0   stevel 	 */
    115     0   stevel 	do {
    116   559  nakanon 		struct wordent *new = (struct wordent *)xalloc(sizeof *wdp);
    117     0   stevel 
    118     0   stevel 		new->word = 0;
    119     0   stevel 		new->prev = wdp;
    120     0   stevel 		new->next = hp;
    121     0   stevel 		wdp->next = new;
    122     0   stevel 		wdp = new;
    123     0   stevel 		wdp->word = word();
    124     0   stevel 	} while (wdp->word[0] != '\n');
    125     0   stevel #ifdef TRACE
    126     0   stevel 	tprintf("Exiting lex()\n");
    127     0   stevel #endif
    128     0   stevel 	hp->prev = wdp;
    129     0   stevel 	return (hadhist);
    130     0   stevel }
    131     0   stevel 
    132   356   muffin void
    133   356   muffin prlex(struct wordent *sp0)
    134     0   stevel {
    135   356   muffin 	struct wordent *sp = sp0->next;
    136     0   stevel 
    137     0   stevel #ifdef TRACE
    138     0   stevel 	tprintf("TRACE- prlex()\n");
    139     0   stevel #endif
    140     0   stevel 	for (;;) {
    141     0   stevel 		printf("%t", sp->word);
    142     0   stevel 		sp = sp->next;
    143     0   stevel 		if (sp == sp0)
    144     0   stevel 			break;
    145     0   stevel 		if (sp->word[0] != '\n')
    146     0   stevel 			Putchar(' ');
    147     0   stevel 	}
    148     0   stevel }
    149     0   stevel 
    150   356   muffin void
    151   356   muffin copylex(struct wordent *hp, struct wordent *fp)
    152     0   stevel {
    153   356   muffin 	struct wordent *wdp;
    154     0   stevel 
    155     0   stevel #ifdef TRACE
    156     0   stevel 	tprintf("TRACE- copylex()\n");
    157     0   stevel #endif
    158     0   stevel 	wdp = hp;
    159     0   stevel 	fp = fp->next;
    160     0   stevel 	do {
    161   559  nakanon 		struct wordent *new = (struct wordent *)xalloc(sizeof *wdp);
    162     0   stevel 
    163     0   stevel 		new->prev = wdp;
    164     0   stevel 		new->next = hp;
    165     0   stevel 		wdp->next = new;
    166     0   stevel 		wdp = new;
    167     0   stevel 		wdp->word = savestr(fp->word);
    168     0   stevel 		fp = fp->next;
    169     0   stevel 	} while (wdp->word[0] != '\n');
    170     0   stevel 	hp->prev = wdp;
    171     0   stevel }
    172     0   stevel 
    173   356   muffin void
    174   356   muffin freelex(struct wordent *vp)
    175     0   stevel {
    176   356   muffin 	struct wordent *fp;
    177     0   stevel 
    178     0   stevel #ifdef TRACE
    179     0   stevel 	tprintf("TRACE- freelex()\n");
    180     0   stevel #endif
    181     0   stevel 	while (vp->next != vp) {
    182     0   stevel 		fp = vp->next;
    183     0   stevel 		vp->next = fp->next;
    184   559  nakanon 		xfree(fp->word);
    185   559  nakanon 		xfree(fp);
    186     0   stevel 	}
    187     0   stevel 	vp->prev = vp;
    188     0   stevel }
    189     0   stevel 
    190     0   stevel tchar *
    191   356   muffin word(void)
    192     0   stevel {
    193   356   muffin 	tchar c, c1;
    194   356   muffin 	tchar *wp;
    195     0   stevel 	tchar wbuf[BUFSIZ];
    196   356   muffin 	bool dolflg;
    197   356   muffin 	int i;
    198     0   stevel 
    199     0   stevel #ifdef TRACE
    200     0   stevel 	tprintf("TRACE- word()\n");
    201     0   stevel #endif
    202     0   stevel 	wp = wbuf;
    203     0   stevel 	i = BUFSIZ - 4;
    204     0   stevel loop:
    205     0   stevel 	while (issp(c = getC(DOALL)))
    206     0   stevel 		;
    207     0   stevel 	if (cmap(c, _META|_ESC)||isauxsp(c))
    208     0   stevel 		switch (c) {
    209     0   stevel 		case '&':
    210     0   stevel 		case '|':
    211     0   stevel 		case '<':
    212     0   stevel 		case '>':
    213     0   stevel 			*wp++ = c;
    214     0   stevel 			c1 = getC(DOALL);
    215     0   stevel 			if (c1 == c)
    216     0   stevel 				*wp++ = c1;
    217     0   stevel 			else
    218     0   stevel 				ungetC(c1);
    219     0   stevel 			goto ret;
    220     0   stevel 
    221     0   stevel 		case '#':
    222     0   stevel 			if (intty)
    223     0   stevel 				break;
    224     0   stevel 			c = 0;
    225     0   stevel 			do {
    226     0   stevel 				c1 = c;
    227     0   stevel 				c = getC(0);
    228     0   stevel 			} while (c != '\n');
    229     0   stevel 			if (c1 == '\\')
    230     0   stevel 				goto loop;
    231     0   stevel 			/* fall into ... */
    232     0   stevel 
    233     0   stevel 		case ';':
    234     0   stevel 		case '(':
    235     0   stevel 		case ')':
    236     0   stevel 		case '\n':
    237     0   stevel 			*wp++ = c;
    238     0   stevel 			goto ret;
    239     0   stevel 
    240     0   stevel 		case '\\':
    241     0   stevel 			c = getC(0);
    242     0   stevel 			if (c == '\n') {
    243     0   stevel 				if (onelflg == 1)
    244     0   stevel 					onelflg = 2;
    245     0   stevel 				goto loop;
    246     0   stevel 			}
    247     0   stevel 			if (c != HIST)
    248     0   stevel 				*wp++ = '\\', --i;
    249     0   stevel 			c |= QUOTE;
    250     0   stevel 		}
    251     0   stevel 	c1 = 0;
    252     0   stevel 	dolflg = DOALL;
    253     0   stevel 	for (;;) {
    254     0   stevel 		if (c1) {
    255     0   stevel 			if (c == c1) {
    256     0   stevel 				c1 = 0;
    257     0   stevel 				dolflg = DOALL;
    258     0   stevel 			} else if (c == '\\') {
    259     0   stevel 				c = getC(0);
    260     0   stevel 				if (c == HIST)
    261     0   stevel 					c |= QUOTE;
    262     0   stevel 				else {
    263     0   stevel 					if (c == '\n')
    264   559  nakanon #if 0
    265     0   stevel 						if (c1 == '`')
    266     0   stevel 							c = ' ';
    267     0   stevel 						else
    268   559  nakanon #endif
    269     0   stevel 							c |= QUOTE;
    270     0   stevel 					ungetC(c);
    271     0   stevel 					c = '\\';
    272     0   stevel 				}
    273     0   stevel 			} else if (c == '\n') {
    274     0   stevel 				seterrc(gettext("Unmatched "), c1);
    275     0   stevel 				ungetC(c);
    276     0   stevel 				break;
    277     0   stevel 			}
    278     0   stevel 		} else if (cmap(c, _META|_Q|_Q1|_ESC)||isauxsp(c)) {
    279     0   stevel 			if (c == '\\') {
    280     0   stevel 				c = getC(0);
    281     0   stevel 				if (c == '\n') {
    282     0   stevel 					if (onelflg == 1)
    283     0   stevel 						onelflg = 2;
    284     0   stevel 					break;
    285     0   stevel 				}
    286     0   stevel 				if (c != HIST)
    287     0   stevel 					*wp++ = '\\', --i;
    288     0   stevel 				c |= QUOTE;
    289     0   stevel 			} else if (cmap(c, _Q|_Q1)) {		/* '"` */
    290     0   stevel 				c1 = c;
    291     0   stevel 				dolflg = c == '"' ? DOALL : DOEXCL;
    292     0   stevel 			} else if (c != '#' || !intty) {
    293     0   stevel 				ungetC(c);
    294     0   stevel 				break;
    295     0   stevel 			}
    296     0   stevel 		}
    297     0   stevel 		if (--i > 0) {
    298     0   stevel 			*wp++ = c;
    299     0   stevel 			c = getC(dolflg);
    300     0   stevel 		} else {
    301     0   stevel 			seterr("Word too long");
    302     0   stevel 			wp = &wbuf[1];
    303     0   stevel 			break;
    304     0   stevel 		}
    305     0   stevel 	}
    306     0   stevel ret:
    307     0   stevel 	*wp = 0;
    308     0   stevel #ifdef TRACE
    309     0   stevel 	tprintf("word() returning:%t\n", wbuf);
    310     0   stevel #endif
    311     0   stevel 	return (savestr(wbuf));
    312     0   stevel }
    313     0   stevel 
    314   356   muffin tchar
    315   356   muffin getC1(int flag)
    316     0   stevel {
    317   356   muffin 	tchar c;
    318     0   stevel 
    319     0   stevel top:
    320     0   stevel 	if (c = peekc) {
    321     0   stevel 		peekc = 0;
    322     0   stevel 		return (c);
    323     0   stevel 	}
    324     0   stevel 	if (lap) {
    325     0   stevel 		if ((c = *lap++) == 0)
    326     0   stevel 			lap = 0;
    327     0   stevel 		else {
    328     0   stevel 			/*
    329   559  nakanon 			 * don't quote things if there was an error (err!=0)
    330   559  nakanon 			 * the input is original, not from a substitution and
    331   559  nakanon 			 * therefore should not be quoted
    332     0   stevel 			 */
    333     0   stevel 			if (!err && cmap(c, _META|_Q|_Q1)||isauxsp(c))
    334     0   stevel 				c |= QUOTE;
    335     0   stevel 			return (c);
    336     0   stevel 		}
    337     0   stevel 	}
    338     0   stevel 	if (c = peekd) {
    339     0   stevel 		peekd = 0;
    340     0   stevel 		return (c);
    341     0   stevel 	}
    342     0   stevel 	if (exclp) {
    343     0   stevel 		if (c = *exclp++)
    344     0   stevel 			return (c);
    345     0   stevel 		if (exclnxt && --exclc >= 0) {
    346     0   stevel 			exclnxt = exclnxt->next;
    347     0   stevel 			setexclp(exclnxt->word);
    348     0   stevel 			return (' ');
    349     0   stevel 		}
    350     0   stevel 		exclp = 0;
    351     0   stevel 		exclnxt = 0;
    352     0   stevel 	}
    353     0   stevel 	if (exclnxt) {
    354     0   stevel 		exclnxt = exclnxt->next;
    355     0   stevel 		if (--exclc < 0)
    356     0   stevel 			exclnxt = 0;
    357     0   stevel 		else
    358     0   stevel 			setexclp(exclnxt->word);
    359     0   stevel 		goto top;
    360     0   stevel 	}
    361     0   stevel 	c = readc(0);
    362     0   stevel 	if (c == '$' && (flag & DODOL)) {
    363     0   stevel 		getdol();
    364     0   stevel 		goto top;
    365     0   stevel 	}
    366     0   stevel 	if (c == HIST && (flag & DOEXCL)) {
    367     0   stevel 		getexcl(0);
    368     0   stevel 		goto top;
    369     0   stevel 	}
    370     0   stevel 	return (c);
    371     0   stevel }
    372     0   stevel 
    373   356   muffin void
    374   356   muffin getdol(void)
    375     0   stevel {
    376   356   muffin 	tchar *np, *p;
    377     0   stevel 	tchar name[MAX_VREF_LEN];
    378   356   muffin 	int c;
    379     0   stevel 	int sc;
    380     0   stevel 	bool special = 0;
    381     0   stevel 
    382     0   stevel #ifdef TRACE
    383     0   stevel 	tprintf("TRACE- getdol()\n");
    384     0   stevel #endif
    385     0   stevel 	np = name, *np++ = '$';
    386     0   stevel 	c = sc = getC(DOEXCL);
    387     0   stevel 	if (isspnl(c)) {
    388     0   stevel 		ungetD(c);
    389     0   stevel 		ungetC('$' | QUOTE);
    390     0   stevel 		return;
    391     0   stevel 	}
    392     0   stevel 	if (c == '{')
    393     0   stevel 		*np++ = c, c = getC(DOEXCL);
    394     0   stevel 	if (c == '#' || c == '?')
    395     0   stevel 		special++, *np++ = c, c = getC(DOEXCL);
    396     0   stevel 	*np++ = c;
    397     0   stevel 	switch (c) {
    398   559  nakanon 
    399     0   stevel 	case '<':
    400     0   stevel 	case '$':
    401     0   stevel 	case '*':
    402     0   stevel 		if (special)
    403     0   stevel 			goto vsyn;
    404     0   stevel 		goto ret;
    405     0   stevel 
    406     0   stevel 	case '\n':
    407     0   stevel 		ungetD(c);
    408     0   stevel 		np--;
    409     0   stevel 		goto vsyn;
    410     0   stevel 
    411     0   stevel 	default:
    412     0   stevel 		p = np;
    413     0   stevel 		if (digit(c)) {
    414     0   stevel 			/* make sure the variable names are MAX_VAR_LEN chars or less */
    415   559  nakanon 			while (digit(c = getC(DOEXCL)) && (np - p) < MAX_VAR_LEN) {
    416     0   stevel 				*np++ = c;
    417     0   stevel 			}
    418     0   stevel 		} else if (letter(c)) {
    419     0   stevel 			while ((letter(c = getC(DOEXCL)) || digit(c)) &&
    420   559  nakanon 				(np - p) < MAX_VAR_LEN) {
    421     0   stevel 				*np++ = c;
    422     0   stevel 			}
    423     0   stevel 		}
    424     0   stevel 		else
    425     0   stevel 			goto vsyn;
    426     0   stevel 
    427   559  nakanon 		if ((np - p) > MAX_VAR_LEN)
    428     0   stevel 		{
    429     0   stevel 			seterr("Variable name too long");
    430     0   stevel 			goto ret;
    431     0   stevel 		}
    432     0   stevel 	}
    433     0   stevel 	if (c == '[') {
    434     0   stevel 		*np++ = c;
    435     0   stevel 		do {
    436     0   stevel 			c = getC(DOEXCL);
    437     0   stevel 			if (c == '\n') {
    438     0   stevel 				ungetD(c);
    439     0   stevel 				np--;
    440     0   stevel 				goto vsyn;
    441     0   stevel 			}
    442     0   stevel 			/* need to leave space for possible modifiers */
    443     0   stevel 			if (np >= &name[MAX_VREF_LEN - 8])
    444     0   stevel 			{
    445     0   stevel 				seterr("Variable reference too long");
    446     0   stevel 				goto ret;
    447     0   stevel 			}
    448     0   stevel 			*np++ = c;
    449     0   stevel 		} while (c != ']');
    450     0   stevel 		c = getC(DOEXCL);
    451     0   stevel 	}
    452     0   stevel 	if (c == ':') {
    453     0   stevel 		*np++ = c, c = getC(DOEXCL);
    454     0   stevel 		if (c == 'g')
    455     0   stevel 			*np++ = c, c = getC(DOEXCL);
    456     0   stevel 		*np++ = c;
    457     0   stevel 		if (!any(c, S_htrqxe))
    458     0   stevel 			goto vsyn;
    459     0   stevel 	} else
    460     0   stevel 		ungetD(c);
    461     0   stevel 	if (sc == '{') {
    462     0   stevel 		c = getC(DOEXCL);
    463     0   stevel 		if (c != '}') {
    464     0   stevel 			ungetC(c);
    465     0   stevel 			goto vsyn;
    466     0   stevel 		}
    467     0   stevel 		*np++ = c;
    468     0   stevel 	}
    469     0   stevel ret:
    470     0   stevel 	*np = 0;
    471     0   stevel 	addla(name);
    472     0   stevel 	return;
    473     0   stevel 
    474     0   stevel vsyn:
    475     0   stevel 	seterr("Variable syntax");
    476     0   stevel 	goto ret;
    477     0   stevel }
    478     0   stevel 
    479   356   muffin void
    480   356   muffin addla(tchar *cp)
    481     0   stevel {
    482     0   stevel 	tchar *buf;
    483     0   stevel 	int len = 0;
    484     0   stevel 
    485     0   stevel #ifdef TRACE
    486     0   stevel 	tprintf("TRACE- addla()\n");
    487     0   stevel #endif
    488     0   stevel 	if (lap) {
    489     0   stevel 		len = strlen_(lap);
    490     0   stevel 		buf = xalloc((len+1) * sizeof (tchar));
    491     0   stevel 		(void) strcpy_(buf, lap);
    492     0   stevel 	}
    493     0   stevel 	len += strlen_(cp);
    494     0   stevel 
    495     0   stevel 	/* len+5 is allow 4 additional charecters just to be safe */
    496     0   stevel 	labuf = xrealloc(labuf, (len+5) * sizeof (tchar));
    497     0   stevel 	(void) strcpy_(labuf, cp);
    498     0   stevel 	if (lap) {
    499     0   stevel 		(void) strcat_(labuf, buf);
    500   559  nakanon 		xfree(buf);
    501     0   stevel 	}
    502     0   stevel 	lap = labuf;
    503     0   stevel }
    504     0   stevel 
    505  2182     chin tchar	lhsb[256];
    506  2182     chin tchar	slhs[256];
    507  2182     chin tchar	rhsb[512];
    508     0   stevel int	quesarg;
    509     0   stevel 
    510   356   muffin void
    511   356   muffin getexcl(tchar sc)
    512     0   stevel {
    513   356   muffin 	struct wordent *hp, *ip;
    514     0   stevel 	int left, right, dol;
    515   356   muffin 	int c;
    516     0   stevel 
    517     0   stevel #ifdef TRACE
    518     0   stevel 	tprintf("TRACE- getexcl()\n");
    519     0   stevel #endif
    520     0   stevel 	if (sc == 0) {
    521     0   stevel 		sc = getC(0);
    522     0   stevel 		if (sc != '{') {
    523     0   stevel 			ungetC(sc);
    524     0   stevel 			sc = 0;
    525     0   stevel 		}
    526     0   stevel 	}
    527     0   stevel 	quesarg = -1;
    528     0   stevel 	lastev = eventno;
    529     0   stevel 	hp = gethent(sc);
    530     0   stevel 	if (hp == 0)
    531     0   stevel 		return;
    532     0   stevel 	hadhist = 1;
    533     0   stevel 	dol = 0;
    534     0   stevel 	if (hp == alhistp)
    535     0   stevel 		for (ip = hp->next->next; ip != alhistt; ip = ip->next)
    536     0   stevel 			dol++;
    537     0   stevel 	else
    538     0   stevel 		for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
    539     0   stevel 			dol++;
    540     0   stevel 	left = 0, right = dol;
    541     0   stevel 	if (sc == HISTSUB) {
    542     0   stevel 		ungetC('s'), unreadc(HISTSUB), c = ':';
    543     0   stevel 		goto subst;
    544     0   stevel 	}
    545     0   stevel 	c = getC(0);
    546   559  nakanon 	/* if (!any(c, ":^$*-%")) */	/* change needed for char -> tchar */
    547     0   stevel 	if (! (c == ':' || c == '^' || c == '$' || c == '*' ||
    548   559  nakanon 	    c == '-' || c == '%'))
    549     0   stevel 		goto subst;
    550     0   stevel 	left = right = -1;
    551     0   stevel 	if (c == ':') {
    552     0   stevel 		c = getC(0);
    553     0   stevel 		unreadc(c);
    554     0   stevel 		if (letter(c) || c == '&') {
    555     0   stevel 			c = ':';
    556     0   stevel 			left = 0, right = dol;
    557     0   stevel 			goto subst;
    558     0   stevel 		}
    559     0   stevel 	} else
    560     0   stevel 		ungetC(c);
    561     0   stevel 	if (!getsel(&left, &right, dol))
    562     0   stevel 		return;
    563     0   stevel 	c = getC(0);
    564     0   stevel 	if (c == '*')
    565     0   stevel 		ungetC(c), c = '-';
    566     0   stevel 	if (c == '-') {
    567     0   stevel 		if (!getsel(&left, &right, dol))
    568     0   stevel 			return;
    569     0   stevel 		c = getC(0);
    570     0   stevel 	}
    571     0   stevel subst:
    572     0   stevel 	exclc = right - left + 1;
    573     0   stevel 	while (--left >= 0)
    574     0   stevel 		hp = hp->next;
    575     0   stevel 	if (sc == HISTSUB || c == ':') {
    576     0   stevel 		do {
    577     0   stevel 			hp = getsub(hp);
    578     0   stevel 			c = getC(0);
    579     0   stevel 		} while (c == ':');
    580     0   stevel 	}
    581     0   stevel 	unreadc(c);
    582     0   stevel 	if (sc == '{') {
    583     0   stevel 		c = getC(0);
    584     0   stevel 		if (c != '}')
    585     0   stevel 			seterr("Bad ! form");
    586     0   stevel 	}
    587     0   stevel 	exclnxt = hp;
    588     0   stevel }
    589     0   stevel 
    590     0   stevel struct wordent *
    591   356   muffin getsub(struct wordent *en)
    592     0   stevel {
    593   356   muffin 	tchar *cp;
    594     0   stevel 	int delim;
    595   356   muffin 	int c;
    596     0   stevel 	int sc;
    597     0   stevel 	bool global = 0;
    598     0   stevel 	tchar orhsb[(sizeof rhsb)/(sizeof rhsb[0])];
    599     0   stevel 
    600     0   stevel #ifdef TRACE
    601     0   stevel 	tprintf("TRACE- getsub()\n");
    602     0   stevel #endif
    603     0   stevel 	exclnxt = 0;
    604     0   stevel 	sc = c = getC(0);
    605     0   stevel 	if (c == 'g')
    606     0   stevel 		global++, c = getC(0);
    607     0   stevel 	switch (c) {
    608     0   stevel 
    609     0   stevel 	case 'p':
    610     0   stevel 		justpr++;
    611     0   stevel 		goto ret;
    612     0   stevel 
    613     0   stevel 	case 'x':
    614     0   stevel 	case 'q':
    615     0   stevel 		global++;
    616     0   stevel 		/* fall into ... */
    617     0   stevel 
    618     0   stevel 	case 'h':
    619     0   stevel 	case 'r':
    620     0   stevel 	case 't':
    621     0   stevel 	case 'e':
    622     0   stevel 		break;
    623     0   stevel 
    624     0   stevel 	case '&':
    625     0   stevel 		if (slhs[0] == 0) {
    626     0   stevel 			seterr("No prev sub");
    627     0   stevel 			goto ret;
    628     0   stevel 		}
    629     0   stevel 		(void) strcpy_(lhsb, slhs);
    630     0   stevel 		break;
    631     0   stevel 
    632   559  nakanon #if 0
    633     0   stevel 	case '~':
    634     0   stevel 		if (lhsb[0] == 0)
    635     0   stevel 			goto badlhs;
    636     0   stevel 		break;
    637   559  nakanon #endif
    638     0   stevel 
    639     0   stevel 	case 's':
    640     0   stevel 		delim = getC(0);
    641   559  nakanon 		if (alnum(delim) || isspnl(delim)) {
    642     0   stevel 			unreadc(delim);
    643     0   stevel bads:
    644     0   stevel 			lhsb[0] = 0;
    645     0   stevel 			seterr("Bad substitute");
    646     0   stevel 			goto ret;
    647     0   stevel 		}
    648     0   stevel 		cp = lhsb;
    649     0   stevel 		for (;;) {
    650     0   stevel 			c = getC(0);
    651     0   stevel 			if (c == '\n') {
    652     0   stevel 				unreadc(c);
    653     0   stevel 				break;
    654     0   stevel 			}
    655     0   stevel 			if (c == delim)
    656     0   stevel 				break;
    657     0   stevel 			if (cp > &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
    658     0   stevel 				goto bads;
    659     0   stevel 			if (c == '\\') {
    660     0   stevel 				c = getC(0);
    661     0   stevel 				if (c != delim && c != '\\')
    662     0   stevel 					*cp++ = '\\';
    663     0   stevel 			}
    664     0   stevel 			*cp++ = c;
    665     0   stevel 		}
    666     0   stevel 		if (cp != lhsb)
    667     0   stevel 			*cp++ = 0;
    668     0   stevel 		else if (lhsb[0] == 0) {
    669   559  nakanon /* badlhs: */
    670     0   stevel 			seterr("No prev lhs");
    671     0   stevel 			goto ret;
    672     0   stevel 		}
    673     0   stevel 		cp = rhsb;
    674     0   stevel 		(void) strcpy_(orhsb, cp);
    675     0   stevel 		for (;;) {
    676     0   stevel 			c = getC(0);
    677     0   stevel 			if (c == '\n') {
    678     0   stevel 				unreadc(c);
    679     0   stevel 				break;
    680     0   stevel 			}
    681     0   stevel 			if (c == delim)
    682     0   stevel 				break;
    683   559  nakanon #if 0
    684     0   stevel 			if (c == '~') {
    685   559  nakanon 				if (&cp[strlen_(orhsb)]
    686     0   stevel 				> &rhsb[(sizeof rhsb)/(sizeof rhsb[0]) - 2])
    687     0   stevel 					goto toorhs;
    688     0   stevel 				(void) strcpy_(cp, orhsb);
    689     0   stevel 				cp = strend(cp);
    690     0   stevel 				continue;
    691     0   stevel 			}
    692   559  nakanon #endif
    693     0   stevel 			if (cp > &rhsb[(sizeof rhsb)/(sizeof rhsb[0]) - 2]) {
    694   559  nakanon /* toorhs: */
    695     0   stevel 				seterr("Rhs too long");
    696     0   stevel 				goto ret;
    697     0   stevel 			}
    698     0   stevel 			if (c == '\\') {
    699     0   stevel 				c = getC(0);
    700     0   stevel 				if (c != delim /* && c != '~' */)
    701     0   stevel 					*cp++ = '\\';
    702     0   stevel 			}
    703     0   stevel 			*cp++ = c;
    704     0   stevel 		}
    705     0   stevel 		*cp++ = 0;
    706     0   stevel 		break;
    707     0   stevel 
    708     0   stevel 	default:
    709     0   stevel 		if (c == '\n')
    710     0   stevel 			unreadc(c);
    711     0   stevel 		seterrc(gettext("Bad ! modifier: "), c);
    712     0   stevel 		goto ret;
    713     0   stevel 	}
    714     0   stevel 	(void) strcpy_(slhs, lhsb);
    715     0   stevel 	if (exclc)
    716     0   stevel 		en = dosub(sc, en, global);
    717     0   stevel ret:
    718     0   stevel 	return (en);
    719     0   stevel }
    720     0   stevel 
    721     0   stevel struct wordent *
    722   356   muffin dosub(int sc, struct wordent *en, bool global)
    723     0   stevel {
    724     0   stevel 	struct wordent lex;
    725     0   stevel 	bool didsub = 0;
    726     0   stevel 	struct wordent *hp = &lex;
    727   356   muffin 	struct wordent *wdp;
    728   356   muffin 	int i = exclc;
    729     0   stevel 
    730     0   stevel #ifdef TRACE
    731     0   stevel 	tprintf("TRACE- dosub()\n");
    732     0   stevel #endif
    733     0   stevel 	wdp = hp;
    734     0   stevel 	while (--i >= 0) {
    735   559  nakanon 		struct wordent *new = (struct wordent *)xcalloc(1, sizeof *wdp);
    736     0   stevel 
    737     0   stevel 		new->prev = wdp;
    738     0   stevel 		new->next = hp;
    739     0   stevel 		wdp->next = new;
    740     0   stevel 		wdp = new;
    741     0   stevel 		en = en->next;
    742     0   stevel 		wdp->word = global || didsub == 0 ?
    743     0   stevel 		    subword(en->word, sc, &didsub) : savestr(en->word);
    744     0   stevel 	}
    745     0   stevel 	if (didsub == 0)
    746     0   stevel 		seterr("Modifier failed");
    747     0   stevel 	hp->prev = wdp;
    748     0   stevel 	return (&enthist(-1000, &lex, 0)->Hlex);
    749     0   stevel }
    750     0   stevel 
    751     0   stevel tchar *
    752   356   muffin subword(tchar *cp, int type, bool *adid)
    753     0   stevel {
    754     0   stevel 	tchar wbuf[BUFSIZ];
    755   356   muffin 	tchar *wp, *mp, *np;
    756   356   muffin 	int i;
    757     0   stevel 
    758     0   stevel #ifdef TRACE
    759     0   stevel 	tprintf("TRACE- subword()\n");
    760     0   stevel #endif
    761     0   stevel 	switch (type) {
    762     0   stevel 
    763     0   stevel 	case 'r':
    764     0   stevel 	case 'e':
    765     0   stevel 	case 'h':
    766     0   stevel 	case 't':
    767     0   stevel 	case 'q':
    768     0   stevel 	case 'x':
    769     0   stevel 		wp = domod(cp, type);
    770     0   stevel 		if (wp == 0)
    771     0   stevel 			return (savestr(cp));
    772     0   stevel 		*adid = 1;
    773     0   stevel 		return (wp);
    774     0   stevel 
    775     0   stevel 	default:
    776     0   stevel 		wp = wbuf;
    777     0   stevel 		i = BUFSIZ - 4;
    778     0   stevel 		for (mp = cp; *mp; mp++)
    779     0   stevel 			if (matchs(mp, lhsb)) {
    780   559  nakanon 				for (np = cp; np < mp; )
    781     0   stevel 					*wp++ = *np++, --i;
    782     0   stevel 				for (np = rhsb; *np; np++) switch (*np) {
    783     0   stevel 
    784     0   stevel 				case '\\':
    785     0   stevel 					if (np[1] == '&')
    786     0   stevel 						np++;
    787     0   stevel 					/* fall into ... */
    788     0   stevel 
    789     0   stevel 				default:
    790     0   stevel 					if (--i < 0)
    791     0   stevel 						goto ovflo;
    792     0   stevel 					*wp++ = *np;
    793     0   stevel 					continue;
    794     0   stevel 
    795     0   stevel 				case '&':
    796     0   stevel 					i -= strlen_(lhsb);
    797     0   stevel 					if (i < 0)
    798     0   stevel 						goto ovflo;
    799     0   stevel 					*wp = 0;
    800     0   stevel 					(void) strcat_(wp, lhsb);
    801     0   stevel 					wp = strend(wp);
    802     0   stevel 					continue;
    803     0   stevel 				}
    804     0   stevel 				mp += strlen_(lhsb);
    805     0   stevel 				i -= strlen_(mp);
    806     0   stevel 				if (i < 0) {
    807     0   stevel ovflo:
    808     0   stevel 					seterr("Subst buf ovflo");
    809   559  nakanon 					return (S_ /* "" */);
    810     0   stevel 				}
    811     0   stevel 				*wp = 0;
    812     0   stevel 				(void) strcat_(wp, mp);
    813     0   stevel 				*adid = 1;
    814     0   stevel 				return (savestr(wbuf));
    815     0   stevel 			}
    816     0   stevel 		return (savestr(cp));
    817     0   stevel 	}
    818     0   stevel }
    819     0   stevel 
    820     0   stevel tchar *
    821   356   muffin domod(tchar *cp, int type)
    822     0   stevel {
    823   356   muffin 	tchar *wp, *xp;
    824   356   muffin 	int c;
    825     0   stevel 
    826     0   stevel #ifdef TRACE
    827     0   stevel 	tprintf("TRACE- domod()\n");
    828     0   stevel #endif
    829     0   stevel 	switch (type) {
    830     0   stevel 
    831     0   stevel 	case 'x':
    832     0   stevel 	case 'q':
    833     0   stevel 		wp = savestr(cp);
    834     0   stevel 		for (xp = wp; c = *xp; xp++)
    835     0   stevel 			if (!issp(c) || type == 'q')
    836     0   stevel 				*xp |= QUOTE;
    837     0   stevel 		return (wp);
    838     0   stevel 
    839     0   stevel 	case 'h':
    840     0   stevel 	case 't':
    841     0   stevel 		if (!any('/', cp))
    842     0   stevel 			return (type == 't' ? savestr(cp) : 0);
    843     0   stevel 		wp = strend(cp);
    844     0   stevel 		while (*--wp != '/')
    845     0   stevel 			continue;
    846     0   stevel 		if (type == 'h')
    847     0   stevel 			xp = savestr(cp), xp[wp - cp] = 0;
    848     0   stevel 		else
    849     0   stevel 			xp = savestr(wp + 1);
    850     0   stevel 		return (xp);
    851     0   stevel 
    852     0   stevel 	case 'e':
    853     0   stevel 	case 'r':
    854     0   stevel 		wp = strend(cp);
    855     0   stevel 		for (wp--; wp >= cp && *wp != '/'; wp--)
    856     0   stevel 			if (*wp == '.') {
    857     0   stevel 				if (type == 'e')
    858     0   stevel 					xp = savestr(wp + 1);
    859     0   stevel 				else
    860     0   stevel 					xp = savestr(cp), xp[wp - cp] = 0;
    861     0   stevel 				return (xp);
    862     0   stevel 			}
    863   559  nakanon 		return (savestr(type == 'e' ? S_ /* "" */ : cp));
    864     0   stevel 	}
    865     0   stevel 	return (0);
    866     0   stevel }
    867     0   stevel 
    868   356   muffin int
    869   356   muffin matchs(tchar *str, tchar *pat)
    870     0   stevel {
    871     0   stevel 
    872     0   stevel #ifdef TRACE
    873     0   stevel 	tprintf("TRACE- matchs()\n");
    874     0   stevel #endif
    875     0   stevel 	while (*str && *pat && *str == *pat)
    876     0   stevel 		str++, pat++;
    877     0   stevel 	return (*pat == 0);
    878     0   stevel }
    879     0   stevel 
    880   356   muffin int
    881   356   muffin getsel(int *al, int *ar, int dol)
    882     0   stevel {
    883   356   muffin 	int c = getC(0);
    884   356   muffin 	int i;
    885     0   stevel 	bool first = *al < 0;
    886     0   stevel 
    887     0   stevel #ifdef TRACE
    888     0   stevel 	tprintf("TRACE- getsel()\n");
    889     0   stevel #endif
    890     0   stevel 	switch (c) {
    891     0   stevel 
    892     0   stevel 	case '%':
    893     0   stevel 		if (quesarg == -1)
    894     0   stevel 			goto bad;
    895     0   stevel 		if (*al < 0)
    896     0   stevel 			*al = quesarg;
    897     0   stevel 		*ar = quesarg;
    898     0   stevel 		break;
    899     0   stevel 
    900     0   stevel 	case '-':
    901     0   stevel 		if (*al < 0) {
    902     0   stevel 			*al = 0;
    903     0   stevel 			*ar = dol - 1;
    904     0   stevel 			unreadc(c);
    905     0   stevel 		}
    906     0   stevel 		return (1);
    907     0   stevel 
    908     0   stevel 	case '^':
    909     0   stevel 		if (*al < 0)
    910     0   stevel 			*al = 1;
    911     0   stevel 		*ar = 1;
    912     0   stevel 		break;
    913     0   stevel 
    914     0   stevel 	case '$':
    915     0   stevel 		if (*al < 0)
    916     0   stevel 			*al = dol;
    917     0   stevel 		*ar = dol;
    918     0   stevel 		break;
    919     0   stevel 
    920     0   stevel 	case '*':
    921     0   stevel 		if (*al < 0)
    922     0   stevel 			*al = 1;
    923     0   stevel 		*ar = dol;
    924     0   stevel 		if (*ar < *al) {
    925     0   stevel 			*ar = 0;
    926     0   stevel 			*al = 1;
    927     0   stevel 			return (1);
    928     0   stevel 		}
    929     0   stevel 		break;
    930     0   stevel 
    931     0   stevel 	default:
    932     0   stevel 		if (digit(c)) {
    933     0   stevel 			i = 0;
    934     0   stevel 			while (digit(c)) {
    935     0   stevel 				i = i * 10 + c - '0';
    936     0   stevel 				c = getC(0);
    937     0   stevel 			}
    938     0   stevel 			if (i < 0)
    939     0   stevel 				i = dol + 1;
    940     0   stevel 			if (*al < 0)
    941     0   stevel 				*al = i;
    942     0   stevel 			*ar = i;
    943     0   stevel 		} else
    944     0   stevel 			if (*al < 0)
    945     0   stevel 				*al = 0, *ar = dol;
    946     0   stevel 			else
    947     0   stevel 				*ar = dol - 1;
    948     0   stevel 		unreadc(c);
    949     0   stevel 		break;
    950     0   stevel 	}
    951     0   stevel 	if (first) {
    952     0   stevel 		c = getC(0);
    953     0   stevel 		unreadc(c);
    954     0   stevel 		/* if (any(c, "-$*")) */	/* char -> tchar */
    955     0   stevel 		if (c == '-' || c == '$' || c == '*')
    956     0   stevel 			return (1);
    957     0   stevel 	}
    958     0   stevel 	if (*al > *ar || *ar > dol) {
    959     0   stevel bad:
    960     0   stevel 		seterr("Bad ! arg selector");
    961     0   stevel 		return (0);
    962     0   stevel 	}
    963     0   stevel 	return (1);
    964     0   stevel 
    965     0   stevel }
    966     0   stevel 
    967     0   stevel struct wordent *
    968   356   muffin gethent(int sc)
    969     0   stevel {
    970   356   muffin 	struct Hist *hp;
    971   356   muffin 	tchar *np;
    972   356   muffin 	int c;
    973     0   stevel 	int event;
    974     0   stevel 	bool back = 0;
    975     0   stevel 
    976     0   stevel #ifdef TRACE
    977     0   stevel 	tprintf("TRACE- gethent()\n");
    978     0   stevel #endif
    979     0   stevel 	c = sc == HISTSUB ? HIST : getC(0);
    980     0   stevel 	if (c == HIST) {
    981     0   stevel 		if (alhistp)
    982     0   stevel 			return (alhistp);
    983     0   stevel 		event = eventno;
    984     0   stevel 		goto skip;
    985     0   stevel 	}
    986     0   stevel 	switch (c) {
    987     0   stevel 
    988     0   stevel 	case ':':
    989     0   stevel 	case '^':
    990     0   stevel 	case '$':
    991     0   stevel 	case '*':
    992     0   stevel 	case '%':
    993     0   stevel 		ungetC(c);
    994     0   stevel 		if (lastev == eventno && alhistp)
    995     0   stevel 			return (alhistp);
    996     0   stevel 		event = lastev;
    997     0   stevel 		break;
    998     0   stevel 
    999     0   stevel 	case '-':
   1000     0   stevel 		back = 1;
   1001     0   stevel 		c = getC(0);
   1002     0   stevel 		goto number;
   1003     0   stevel 
   1004     0   stevel 	case '#':			/* !# is command being typed in (mrh) */
   1005   559  nakanon 		return (&paraml);
   1006     0   stevel 
   1007     0   stevel 	default:
   1008   559  nakanon 		/* if (any(c, "(=~")) { */
   1009     0   stevel 		if (c == '(' || c == '=' || c == '~') {
   1010     0   stevel 			unreadc(c);
   1011     0   stevel 			ungetC(HIST);
   1012     0   stevel 			return (0);
   1013     0   stevel 		}
   1014     0   stevel 		if (digit(c))
   1015     0   stevel 			goto number;
   1016     0   stevel 		np = lhsb;
   1017     0   stevel 		/* while (!any(c, ": \t\\\n}")) { */
   1018     0   stevel 		while (! (c == ':' || c == '\\' || isspnl(c) || c == '}')) {
   1019     0   stevel 			if (np < &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
   1020     0   stevel 				*np++ = c;
   1021     0   stevel 			c = getC(0);
   1022     0   stevel 		}
   1023     0   stevel 		unreadc(c);
   1024     0   stevel 		if (np == lhsb) {
   1025     0   stevel 			ungetC(HIST);
   1026     0   stevel 			return (0);
   1027     0   stevel 		}
   1028     0   stevel 		*np++ = 0;
   1029     0   stevel 		hp = findev(lhsb, 0);
   1030     0   stevel 		if (hp)
   1031     0   stevel 			lastev = hp->Hnum;
   1032     0   stevel 		return (&hp->Hlex);
   1033     0   stevel 
   1034     0   stevel 	case '?':
   1035     0   stevel 		np = lhsb;
   1036     0   stevel 		for (;;) {
   1037     0   stevel 			c = getC(0);
   1038     0   stevel 			if (c == '\n') {
   1039     0   stevel 				unreadc(c);
   1040     0   stevel 				break;
   1041     0   stevel 			}
   1042     0   stevel 			if (c == '?')
   1043     0   stevel 				break;
   1044     0   stevel 			if (np < &lhsb[(sizeof lhsb)/(sizeof lhsb[0]) - 2])
   1045     0   stevel 				*np++ = c;
   1046     0   stevel 		}
   1047     0   stevel 		if (np == lhsb) {
   1048     0   stevel 			if (lhsb[0] == 0) {
   1049     0   stevel 				seterr("No prev search");
   1050     0   stevel 				return (0);
   1051     0   stevel 			}
   1052     0   stevel 		} else
   1053     0   stevel 			*np++ = 0;
   1054     0   stevel 		hp = findev(lhsb, 1);
   1055     0   stevel 		if (hp)
   1056     0   stevel 			lastev = hp->Hnum;
   1057     0   stevel 		return (&hp->Hlex);
   1058     0   stevel 
   1059     0   stevel 	number:
   1060     0   stevel 		event = 0;
   1061     0   stevel 		while (digit(c)) {
   1062     0   stevel 			event = event * 10 + c - '0';
   1063     0   stevel 			c = getC(0);
   1064     0   stevel 		}
   1065     0   stevel 		if (back)
   1066     0   stevel 			event = eventno + (alhistp == 0) - (event ? event : 0);
   1067     0   stevel 		unreadc(c);
   1068     0   stevel 		break;
   1069     0   stevel 	}
   1070     0   stevel skip:
   1071     0   stevel 	for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
   1072     0   stevel 		if (hp->Hnum == event) {
   1073     0   stevel 			hp->Href = eventno;
   1074     0   stevel 			lastev = hp->Hnum;
   1075     0   stevel 			return (&hp->Hlex);
   1076     0   stevel 		}
   1077     0   stevel 	np = putn(event);
   1078     0   stevel 	noev(np);
   1079     0   stevel 	return (0);
   1080     0   stevel }
   1081     0   stevel 
   1082     0   stevel struct Hist *
   1083   356   muffin findev(tchar *cp, bool anyarg)
   1084     0   stevel {
   1085   356   muffin 	struct Hist *hp;
   1086     0   stevel 
   1087     0   stevel #ifdef TRACE
   1088     0   stevel 	tprintf("TRACE- findev()\n");
   1089     0   stevel #endif
   1090     0   stevel 	for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
   1091   356   muffin 		tchar *dp;
   1092   356   muffin 		tchar *p, *q;
   1093   356   muffin 		struct wordent *lp = hp->Hlex.next;
   1094     0   stevel 		int argno = 0;
   1095     0   stevel 
   1096     0   stevel 		if (lp->word[0] == '\n')
   1097     0   stevel 			continue;
   1098     0   stevel 		if (!anyarg) {
   1099     0   stevel 			p = cp;
   1100     0   stevel 			q = lp->word;
   1101     0   stevel 			do
   1102     0   stevel 				if (!*p)
   1103     0   stevel 					return (hp);
   1104     0   stevel 			while (*p++ == *q++);
   1105     0   stevel 			continue;
   1106     0   stevel 		}
   1107     0   stevel 		do {
   1108     0   stevel 			for (dp = lp->word; *dp; dp++) {
   1109     0   stevel 				p = cp;
   1110     0   stevel 				q = dp;
   1111     0   stevel 				do
   1112     0   stevel 					if (!*p) {
   1113     0   stevel 						quesarg = argno;
   1114     0   stevel 						return (hp);
   1115     0   stevel 					}
   1116     0   stevel 				while (*p++ == *q++);
   1117     0   stevel 			}
   1118     0   stevel 			lp = lp->next;
   1119     0   stevel 			argno++;
   1120     0   stevel 		} while (lp->word[0] != '\n');
   1121     0   stevel 	}
   1122     0   stevel 	noev(cp);
   1123     0   stevel 	return (0);
   1124     0   stevel }
   1125     0   stevel 
   1126   356   muffin void
   1127   356   muffin noev(tchar *cp)
   1128     0   stevel {
   1129     0   stevel 
   1130     0   stevel #ifdef TRACE
   1131     0   stevel 	tprintf("TRACE- noev()\n");
   1132     0   stevel #endif
   1133     0   stevel 	seterr2(cp, ": Event not found");
   1134     0   stevel }
   1135     0   stevel 
   1136   356   muffin void
   1137   356   muffin setexclp(tchar *cp)
   1138     0   stevel {
   1139     0   stevel 
   1140     0   stevel #ifdef TRACE
   1141     0   stevel 	tprintf("TRACE- setexclp()\n");
   1142     0   stevel #endif
   1143     0   stevel 	if (cp && cp[0] == '\n')
   1144     0   stevel 		return;
   1145     0   stevel 	exclp = cp;
   1146     0   stevel }
   1147     0   stevel 
   1148   356   muffin void
   1149   356   muffin unreadc(tchar c)
   1150     0   stevel {
   1151     0   stevel 
   1152     0   stevel 	peekread = c;
   1153     0   stevel }
   1154     0   stevel 
   1155   356   muffin int
   1156   356   muffin readc(bool wanteof)
   1157     0   stevel {
   1158   356   muffin 	int c;
   1159   356   muffin 	static int sincereal;
   1160     0   stevel 
   1161     0   stevel 	if (c = peekread) {
   1162     0   stevel 		peekread = 0;
   1163     0   stevel 		return (c);
   1164     0   stevel 	}
   1165     0   stevel top:
   1166     0   stevel 	if (alvecp) {
   1167     0   stevel 		if (c = *alvecp++)
   1168     0   stevel 			return (c);
   1169     0   stevel 		if (*alvec) {
   1170     0   stevel 			alvecp = *alvec++;
   1171     0   stevel 			return (' ');
   1172     0   stevel 		}
   1173     0   stevel 	}
   1174     0   stevel 	if (alvec) {
   1175     0   stevel 		if (alvecp = *alvec) {
   1176     0   stevel 			alvec++;
   1177     0   stevel 			goto top;
   1178     0   stevel 		}
   1179     0   stevel 		/* Infinite source! */
   1180     0   stevel 		return ('\n');
   1181     0   stevel 	}
   1182     0   stevel 	if (evalp) {
   1183     0   stevel 		if (c = *evalp++)
   1184     0   stevel 			return (c);
   1185     0   stevel 		if (*evalvec) {
   1186     0   stevel 			evalp = *evalvec++;
   1187     0   stevel 			return (' ');
   1188     0   stevel 		}
   1189     0   stevel 		evalp = 0;
   1190     0   stevel 	}
   1191     0   stevel 	if (evalvec) {
   1192     0   stevel 		if (evalvec ==  (tchar **)1) {
   1193     0   stevel 			doneinp = 1;
   1194     0   stevel 			reset();
   1195     0   stevel 		}
   1196     0   stevel 		if (evalp = *evalvec) {
   1197     0   stevel 			evalvec++;
   1198     0   stevel 			goto top;
   1199     0   stevel 		}
   1200     0   stevel 		evalvec =  (tchar **)1;
   1201     0   stevel 		return ('\n');
   1202     0   stevel 	}
   1203     0   stevel 	do {
   1204     0   stevel 		if (arginp ==  (tchar *) 1 || onelflg == 1) {
   1205     0   stevel 			if (wanteof)
   1206     0   stevel 				return (-1);
   1207     0   stevel 			exitstat();
   1208     0   stevel 		}
   1209     0   stevel 		if (arginp) {
   1210     0   stevel 			if ((c = *arginp++) == 0) {
   1211     0   stevel 				arginp =  (tchar *) 1;
   1212     0   stevel 				return ('\n');
   1213     0   stevel 			}
   1214     0   stevel 			return (c);
   1215     0   stevel 		}
   1216     0   stevel reread:
   1217     0   stevel 		c = bgetc();
   1218     0   stevel 		if (c < 0) {
   1219     0   stevel 			struct sgttyb tty;
   1220     0   stevel 
   1221     0   stevel 			if (wanteof)
   1222     0   stevel 				return (-1);
   1223     0   stevel 			/* was isatty but raw with ignoreeof yields problems */
   1224     0   stevel 			if (ioctl(SHIN, TIOCGETP,  (char *)&tty) == 0 &&
   1225     0   stevel 			    (tty.sg_flags & RAW) == 0) {
   1226     0   stevel 				/* was 'short' for FILEC */
   1227     0   stevel 				int ctpgrp;
   1228     0   stevel 
   1229     0   stevel 				if (++sincereal > 25)
   1230     0   stevel 					goto oops;
   1231     0   stevel 				if (tpgrp != -1 &&
   1232   559  nakanon 				    ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp) == 0 &&
   1233     0   stevel 				    tpgrp != ctpgrp) {
   1234     0   stevel 					(void) ioctl(FSHTTY, TIOCSPGRP,
   1235   559  nakanon 						(char *)&tpgrp);
   1236     0   stevel 					(void) killpg(ctpgrp, SIGHUP);
   1237     0   stevel printf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp);
   1238     0   stevel 					goto reread;
   1239     0   stevel 				}
   1240   559  nakanon 				if (adrof(S_ignoreeof /* "ignoreeof" */)) {
   1241     0   stevel 					if (loginsh)
   1242   559  nakanon 				printf("\nUse \"logout\" to logout.\n");
   1243     0   stevel 					else
   1244   559  nakanon 				printf("\nUse \"exit\" to leave csh.\n");
   1245     0   stevel 					reset();
   1246     0   stevel 				}
   1247     0   stevel 				if (chkstop == 0) {
   1248     0   stevel 					panystop(1);
   1249     0   stevel 				}
   1250     0   stevel 			}
   1251     0   stevel oops:
   1252     0   stevel 			doneinp = 1;
   1253     0   stevel 			reset();
   1254     0   stevel 		}
   1255     0   stevel 		sincereal = 0;
   1256     0   stevel 		if (c == '\n' && onelflg)
   1257     0   stevel 			onelflg--;
   1258     0   stevel 	} while (c == 0);
   1259     0   stevel 	return (c);
   1260     0   stevel }
   1261     0   stevel 
   1262   559  nakanon static void
   1263   559  nakanon expand_fbuf(void)
   1264   559  nakanon {
   1265   559  nakanon 	tchar **nfbuf =
   1266   559  nakanon 	    (tchar **)xcalloc((unsigned)(fblocks + 2), sizeof (tchar **));
   1267   559  nakanon 
   1268   559  nakanon 	if (fbuf) {
   1269   559  nakanon 		(void) blkcpy(nfbuf, fbuf);
   1270   559  nakanon 		xfree((char *)fbuf);
   1271   559  nakanon 	}
   1272   559  nakanon 	fbuf = nfbuf;
   1273   559  nakanon 	fbuf[fblocks] = (tchar *)xcalloc(BUFSIZ + MB_LEN_MAX,
   1274   559  nakanon 		sizeof (tchar));
   1275   559  nakanon 	fblocks++;
   1276   559  nakanon }
   1277   559  nakanon 
   1278   356   muffin int
   1279   356   muffin bgetc(void)
   1280     0   stevel {
   1281   356   muffin 	int buf, off, c;
   1282     0   stevel #ifdef FILEC
   1283   559  nakanon 	tchar ttyline[BUFSIZ + MB_LEN_MAX]; /* read_() can return extra bytes */
   1284   559  nakanon 	int roomleft;
   1285     0   stevel #endif
   1286     0   stevel 
   1287     0   stevel #ifdef TELL
   1288     0   stevel 	if (cantell) {
   1289     0   stevel 		if (fseekp < fbobp || fseekp > feobp) {
   1290     0   stevel 			fbobp = feobp = fseekp;
   1291     0   stevel 			(void) lseek(SHIN, fseekp, 0);
   1292     0   stevel 		}
   1293     0   stevel 		if (fseekp == feobp) {
   1294     0   stevel 			fbobp = feobp;
   1295     0   stevel 			do
   1296     0   stevel 				c = read_(SHIN, fbuf[0], BUFSIZ);
   1297     0   stevel 			while (c < 0 && errno == EINTR);
   1298     0   stevel 			if (c <= 0)
   1299     0   stevel 				return (-1);
   1300     0   stevel 			feobp += c;
   1301     0   stevel 		}
   1302     0   stevel 		c = fbuf[0][fseekp - fbobp];
   1303     0   stevel 		fseekp++;
   1304     0   stevel 		return (c);
   1305     0   stevel 	}
   1306     0   stevel #endif
   1307     0   stevel again:
   1308   559  nakanon 	buf = (int)fseekp / BUFSIZ;
   1309     0   stevel 	if (buf >= fblocks) {
   1310   559  nakanon 		expand_fbuf();
   1311     0   stevel 		goto again;
   1312     0   stevel 	}
   1313     0   stevel 	if (fseekp >= feobp) {
   1314   559  nakanon 		buf = (int)feobp / BUFSIZ;
   1315   559  nakanon 		off = (int)feobp % BUFSIZ;
   1316     0   stevel #ifndef FILEC
   1317     0   stevel 		for (;;) {
   1318     0   stevel 			c = read_(SHIN, fbuf[buf] + off, BUFSIZ - off);
   1319     0   stevel #else
   1320     0   stevel 		roomleft = BUFSIZ - off;
   1321     0   stevel 		for (;;) {
   1322     0   stevel 			if (filec && intty) {
   1323   559  nakanon 				c = tenex(ttyline, BUFSIZ);
   1324     0   stevel 				if (c > roomleft) {
   1325   559  nakanon 					expand_fbuf();
   1326   559  nakanon 					copy(fbuf[buf] + off, ttyline,
   1327   559  nakanon 					    roomleft * sizeof (tchar));
   1328   559  nakanon 					copy(fbuf[buf + 1], ttyline + roomleft,
   1329   559  nakanon 					    (c - roomleft) * sizeof (tchar));
   1330   559  nakanon 				} else if (c > 0) {
   1331   559  nakanon 					copy(fbuf[buf] + off, ttyline,
   1332   559  nakanon 						c * sizeof (tchar));
   1333     0   stevel 				}
   1334   559  nakanon 			} else {
   1335     0   stevel 				c = read_(SHIN, fbuf[buf] + off, roomleft);
   1336   559  nakanon 				if (c > roomleft) {
   1337   559  nakanon 					expand_fbuf();
   1338   559  nakanon 					copy(fbuf[buf + 1],
   1339   559  nakanon 					    fbuf[buf] + off + roomleft,
   1340   559  nakanon 					    (c - roomleft) * sizeof (tchar));
   1341   559  nakanon 				}
   1342   559  nakanon 			}
   1343     0   stevel #endif
   1344     0   stevel 			if (c >= 0)
   1345     0   stevel 				break;
   1346     0   stevel 			if (errno == EWOULDBLOCK) {
   1347     0   stevel 				int off = 0;
   1348     0   stevel 
   1349     0   stevel 				(void) ioctl(SHIN, FIONBIO,  (char *)&off);
   1350     0   stevel 			} else if (errno != EINTR)
   1351     0   stevel 				break;
   1352     0   stevel 		}
   1353     0   stevel 		if (c <= 0)
   1354     0   stevel 			return (-1);
   1355     0   stevel 		feobp += c;
   1356     0   stevel #ifndef FILEC
   1357     0   stevel 		goto again;
   1358     0   stevel #else
   1359     0   stevel 		if (filec && !intty)
   1360     0   stevel 			goto again;
   1361     0   stevel #endif
   1362     0   stevel 	}
   1363   559  nakanon 	c = fbuf[buf][(int)fseekp % BUFSIZ];
   1364     0   stevel 	fseekp++;
   1365     0   stevel 	return (c);
   1366     0   stevel }
   1367     0   stevel 
   1368   559  nakanon void
   1369   356   muffin bfree(void)
   1370     0   stevel {
   1371   356   muffin 	int sb, i;
   1372     0   stevel 
   1373     0   stevel #ifdef TELL
   1374     0   stevel 	if (cantell)
   1375     0   stevel 		return;
   1376     0   stevel #endif
   1377     0   stevel 	if (whyles)
   1378     0   stevel 		return;
   1379   559  nakanon 	sb = (int)(fseekp - 1) / BUFSIZ;
   1380     0   stevel 	if (sb > 0) {
   1381     0   stevel 		for (i = 0; i < sb; i++)
   1382     0   stevel 			xfree(fbuf[i]);
   1383     0   stevel 		(void) blkcpy(fbuf, &fbuf[sb]);
   1384     0   stevel 		fseekp -= BUFSIZ * sb;
   1385     0   stevel 		feobp -= BUFSIZ * sb;
   1386     0   stevel 		fblocks -= sb;
   1387     0   stevel 	}
   1388     0   stevel }
   1389     0   stevel 
   1390   356   muffin void
   1391   356   muffin bseek(off_t l)
   1392     0   stevel {
   1393   356   muffin 	struct whyle *wp;
   1394     0   stevel 
   1395     0   stevel 	fseekp = l;
   1396     0   stevel #ifdef TELL
   1397     0   stevel 	if (!cantell) {
   1398     0   stevel #endif
   1399     0   stevel 		if (!whyles)
   1400     0   stevel 			return;
   1401     0   stevel 		for (wp = whyles; wp->w_next; wp = wp->w_next)
   1402     0   stevel 			continue;
   1403     0   stevel 		if (wp->w_start > l)
   1404     0   stevel 			l = wp->w_start;
   1405     0   stevel #ifdef TELL
   1406     0   stevel 	}
   1407     0   stevel #endif
   1408     0   stevel }
   1409     0   stevel 
   1410     0   stevel /* any similarity to bell telephone is purely accidental */
   1411     0   stevel #ifndef btell
   1412     0   stevel off_t
   1413   356   muffin btell(void)
   1414     0   stevel {
   1415     0   stevel 
   1416     0   stevel 	return (fseekp);
   1417     0   stevel }
   1418     0   stevel #endif
   1419     0   stevel 
   1420   356   muffin void
   1421   356   muffin btoeof(void)
   1422     0   stevel {
   1423     0   stevel 
   1424     0   stevel 	(void) lseek(SHIN, (off_t)0, 2);
   1425     0   stevel 	fseekp = feobp;
   1426     0   stevel 	wfree();
   1427     0   stevel 	bfree();
   1428     0   stevel }
   1429     0   stevel 
   1430     0   stevel #ifdef TELL
   1431   356   muffin void
   1432   356   muffin settell(void)
   1433     0   stevel {
   1434     0   stevel 
   1435     0   stevel 	cantell = 0;
   1436     0   stevel 	if (arginp || onelflg || intty)
   1437     0   stevel 		return;
   1438     0   stevel 	if (lseek(SHIN, (off_t)0, 1) < 0 || errno == ESPIPE)
   1439     0   stevel 		return;
   1440   559  nakanon 	fbuf = (tchar **)xcalloc(2, sizeof (tchar **));
   1441     0   stevel 	fblocks = 1;
   1442   559  nakanon 	fbuf[0] = (tchar *)xcalloc(BUFSIZ + MB_LEN_MAX, sizeof (tchar));
   1443     0   stevel 	fseekp = fbobp = feobp = lseek(SHIN, (off_t)0, 1);
   1444     0   stevel 	cantell = 1;
   1445     0   stevel }
   1446     0   stevel #endif
   1447