Home | History | Annotate | Line # | Download | only in ksh
lex.c revision 1.23.2.3
      1  1.23.2.3    martin /*	$NetBSD: lex.c,v 1.23.2.3 2020/04/21 19:37:32 martin Exp $	*/
      2       1.2       tls 
      3       1.1       jtc /*
      4       1.1       jtc  * lexical analysis and source input
      5       1.1       jtc  */
      6       1.9       agc #include <sys/cdefs.h>
      7       1.9       agc 
      8       1.9       agc #ifndef lint
      9  1.23.2.3    martin __RCSID("$NetBSD: lex.c,v 1.23.2.3 2020/04/21 19:37:32 martin Exp $");
     10       1.9       agc #endif
     11       1.9       agc 
     12       1.1       jtc 
     13       1.1       jtc #include "sh.h"
     14       1.1       jtc #include <ctype.h>
     15       1.1       jtc 
     16       1.6   hubertf 
     17       1.6   hubertf /* Structure to keep track of the lexing state and the various pieces of info
     18       1.6   hubertf  * needed for each particular state.
     19       1.6   hubertf  */
     20       1.6   hubertf typedef struct lex_state Lex_state;
     21       1.6   hubertf struct lex_state {
     22       1.6   hubertf 	int ls_state;
     23       1.6   hubertf 	union {
     24       1.6   hubertf 	    /* $(...) */
     25       1.6   hubertf 	    struct scsparen_info {
     26       1.6   hubertf 		    int nparen;		/* count open parenthesis */
     27       1.6   hubertf 		    int csstate; /* XXX remove */
     28       1.6   hubertf #define ls_scsparen ls_info.u_scsparen
     29       1.6   hubertf 	    } u_scsparen;
     30       1.6   hubertf 
     31       1.6   hubertf 	    /* $((...)) */
     32       1.6   hubertf 	    struct sasparen_info {
     33       1.6   hubertf 		    int nparen;		/* count open parenthesis */
     34       1.6   hubertf 		    int start;		/* marks start of $(( in output str */
     35       1.6   hubertf #define ls_sasparen ls_info.u_sasparen
     36       1.6   hubertf 	    } u_sasparen;
     37       1.6   hubertf 
     38       1.6   hubertf 	    /* ((...)) */
     39       1.6   hubertf 	    struct sletparen_info {
     40       1.6   hubertf 		    int nparen;		/* count open parenthesis */
     41       1.6   hubertf #define ls_sletparen ls_info.u_sletparen
     42       1.6   hubertf 	    } u_sletparen;
     43       1.6   hubertf 
     44       1.6   hubertf 	    /* `...` */
     45       1.6   hubertf 	    struct sbquote_info {
     46       1.6   hubertf 		    int indquotes;	/* true if in double quotes: "`...`" */
     47       1.6   hubertf #define ls_sbquote ls_info.u_sbquote
     48       1.6   hubertf 	    } u_sbquote;
     49       1.6   hubertf 
     50       1.6   hubertf 	    Lex_state *base;		/* used to point to next state block */
     51       1.6   hubertf 	} ls_info;
     52       1.6   hubertf };
     53       1.6   hubertf 
     54       1.6   hubertf typedef struct State_info State_info;
     55       1.6   hubertf struct State_info {
     56       1.6   hubertf 	Lex_state	*base;
     57       1.6   hubertf 	Lex_state	*end;
     58       1.6   hubertf };
     59       1.6   hubertf 
     60       1.6   hubertf 
     61       1.1       jtc static void	readhere ARGS((struct ioword *iop));
     62       1.2       tls static int	getsc__ ARGS((void));
     63       1.1       jtc static void	getsc_line ARGS((Source *s));
     64       1.6   hubertf static int	getsc_bn ARGS((void));
     65       1.1       jtc static char	*get_brace_var ARGS((XString *wsp, char *wp));
     66       1.1       jtc static int	arraysub ARGS((char **strp));
     67       1.2       tls static const char *ungetsc ARGS((int c));
     68       1.2       tls static void	gethere ARGS((void));
     69       1.6   hubertf static Lex_state *push_state_ ARGS((State_info *si, Lex_state *old_end));
     70       1.6   hubertf static Lex_state *pop_state_ ARGS((State_info *si, Lex_state *old_end));
     71       1.2       tls 
     72       1.2       tls static int backslash_skip;
     73       1.2       tls static int ignore_backslash_newline;
     74       1.2       tls 
     75       1.2       tls /* optimized getsc_bn() */
     76       1.2       tls #define getsc()		(*source->str != '\0' && *source->str != '\\' \
     77       1.2       tls 			 && !backslash_skip ? *source->str++ : getsc_bn())
     78       1.2       tls /* optimized getsc__() */
     79       1.2       tls #define	getsc_()	((*source->str != '\0') ? *source->str++ : getsc__())
     80       1.1       jtc 
     81       1.6   hubertf #define STATE_BSIZE	32
     82       1.6   hubertf 
     83       1.6   hubertf #define PUSH_STATE(s)	do { \
     84       1.6   hubertf 			    if (++statep == state_info.end) \
     85       1.6   hubertf 				statep = push_state_(&state_info, statep); \
     86       1.6   hubertf 			    state = statep->ls_state = (s); \
     87       1.6   hubertf 			} while (0)
     88       1.6   hubertf 
     89       1.6   hubertf #define POP_STATE()	do { \
     90       1.6   hubertf 			    if (--statep == state_info.base) \
     91       1.6   hubertf 				statep = pop_state_(&state_info, statep); \
     92       1.6   hubertf 			    state = statep->ls_state; \
     93       1.6   hubertf 			} while (0)
     94       1.6   hubertf 
     95       1.6   hubertf 
     96       1.1       jtc 
     97       1.1       jtc /*
     98       1.1       jtc  * Lexical analyzer
     99       1.1       jtc  *
    100       1.1       jtc  * tokens are not regular expressions, they are LL(1).
    101       1.1       jtc  * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
    102       1.1       jtc  * hence the state stack.
    103       1.1       jtc  */
    104       1.1       jtc 
    105       1.1       jtc int
    106       1.1       jtc yylex(cf)
    107       1.1       jtc 	int cf;
    108       1.1       jtc {
    109       1.6   hubertf 	Lex_state states[STATE_BSIZE], *statep;
    110       1.6   hubertf 	State_info state_info;
    111      1.23     kamil 	int c, state;
    112       1.1       jtc 	XString ws;		/* expandable output word */
    113      1.23     kamil 	char *wp;		/* output word pointer */
    114       1.6   hubertf 	char *sp, *dp;
    115       1.6   hubertf 	int c2;
    116       1.1       jtc 
    117       1.1       jtc 
    118       1.1       jtc   Again:
    119       1.6   hubertf 	states[0].ls_state = -1;
    120       1.6   hubertf 	states[0].ls_info.base = (Lex_state *) 0;
    121       1.6   hubertf 	statep = &states[1];
    122       1.6   hubertf 	state_info.base = states;
    123       1.6   hubertf 	state_info.end = &states[STATE_BSIZE];
    124       1.6   hubertf 
    125       1.1       jtc 	Xinit(ws, wp, 64, ATEMP);
    126       1.1       jtc 
    127       1.2       tls 	backslash_skip = 0;
    128       1.2       tls 	ignore_backslash_newline = 0;
    129       1.2       tls 
    130       1.1       jtc 	if (cf&ONEWORD)
    131       1.6   hubertf 		state = SWORD;
    132       1.2       tls #ifdef KSH
    133       1.1       jtc 	else if (cf&LETEXPR) {
    134       1.1       jtc 		*wp++ = OQUOTE;	 /* enclose arguments in (double) quotes */
    135       1.6   hubertf 		state = SLETPAREN;
    136       1.6   hubertf 		statep->ls_sletparen.nparen = 0;
    137       1.2       tls 	}
    138       1.2       tls #endif /* KSH */
    139       1.2       tls 	else {		/* normal lexing */
    140       1.6   hubertf 		state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
    141       1.1       jtc 		while ((c = getsc()) == ' ' || c == '\t')
    142       1.1       jtc 			;
    143       1.2       tls 		if (c == '#') {
    144       1.2       tls 			ignore_backslash_newline++;
    145       1.1       jtc 			while ((c = getsc()) != '\0' && c != '\n')
    146       1.1       jtc 				;
    147       1.2       tls 			ignore_backslash_newline--;
    148       1.2       tls 		}
    149       1.1       jtc 		ungetsc(c);
    150       1.1       jtc 	}
    151       1.1       jtc 	if (source->flags & SF_ALIAS) {	/* trailing ' ' in alias definition */
    152       1.1       jtc 		source->flags &= ~SF_ALIAS;
    153       1.1       jtc 		/* In POSIX mode, a trailing space only counts if we are
    154       1.1       jtc 		 * parsing a simple command
    155       1.1       jtc 		 */
    156       1.1       jtc 		if (!Flag(FPOSIX) || (cf & CMDWORD))
    157       1.1       jtc 			cf |= ALIAS;
    158       1.1       jtc 	}
    159       1.1       jtc 
    160       1.6   hubertf 	/* Initial state: one of SBASE SHEREDELIM SWORD SASPAREN */
    161       1.6   hubertf 	statep->ls_state = state;
    162       1.6   hubertf 
    163       1.1       jtc 	/* collect non-special or quoted characters to form word */
    164       1.6   hubertf 	while (!((c = getsc()) == 0
    165       1.6   hubertf 		 || ((state == SBASE || state == SHEREDELIM)
    166       1.6   hubertf 		     && ctype(c, C_LEX1))))
    167       1.1       jtc 	{
    168       1.1       jtc 		Xcheck(ws, wp);
    169       1.1       jtc 		switch (state) {
    170       1.1       jtc 		  case SBASE:
    171       1.1       jtc 			if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
    172       1.1       jtc 				*wp = EOS; /* temporary */
    173      1.21     kamil 				if (is_wdvarname(Xstring(ws, wp), false))
    174       1.1       jtc 				{
    175       1.1       jtc 					char *p, *tmp;
    176       1.1       jtc 
    177       1.1       jtc 					if (arraysub(&tmp)) {
    178       1.1       jtc 						*wp++ = CHAR;
    179       1.1       jtc 						*wp++ = c;
    180       1.1       jtc 						for (p = tmp; *p; ) {
    181       1.1       jtc 							Xcheck(ws, wp);
    182       1.1       jtc 							*wp++ = CHAR;
    183       1.1       jtc 							*wp++ = *p++;
    184       1.1       jtc 						}
    185       1.1       jtc 						afree(tmp, ATEMP);
    186       1.1       jtc 						break;
    187       1.1       jtc 					} else {
    188       1.1       jtc 						Source *s;
    189       1.1       jtc 
    190       1.1       jtc 						s = pushs(SREREAD,
    191       1.1       jtc 							  source->areap);
    192       1.1       jtc 						s->start = s->str
    193       1.1       jtc 							= s->u.freeme = tmp;
    194       1.1       jtc 						s->next = source;
    195       1.1       jtc 						source = s;
    196       1.1       jtc 					}
    197       1.1       jtc 				}
    198       1.1       jtc 				*wp++ = CHAR;
    199       1.1       jtc 				*wp++ = c;
    200       1.1       jtc 				break;
    201       1.1       jtc 			}
    202       1.1       jtc 			/* fall through.. */
    203       1.1       jtc 		  Sbase1:	/* includes *(...|...) pattern (*+?@!) */
    204       1.1       jtc #ifdef KSH
    205       1.1       jtc 			if (c == '*' || c == '@' || c == '+' || c == '?'
    206       1.1       jtc 			    || c == '!')
    207       1.1       jtc 			{
    208       1.1       jtc 				c2 = getsc();
    209       1.1       jtc 				if (c2 == '(' /*)*/ ) {
    210       1.1       jtc 					*wp++ = OPAT;
    211       1.1       jtc 					*wp++ = c;
    212       1.6   hubertf 					PUSH_STATE(SPATTERN);
    213       1.1       jtc 					break;
    214       1.1       jtc 				}
    215       1.1       jtc 				ungetsc(c2);
    216       1.1       jtc 			}
    217       1.1       jtc #endif /* KSH */
    218       1.1       jtc 			/* fall through.. */
    219       1.1       jtc 		  Sbase2:	/* doesn't include *(...|...) pattern (*+?@!) */
    220       1.1       jtc 			switch (c) {
    221       1.1       jtc 			  case '\\':
    222       1.1       jtc 				c = getsc();
    223       1.2       tls 				if (c) /* trailing \ is lost */
    224       1.2       tls 					*wp++ = QCHAR, *wp++ = c;
    225       1.1       jtc 				break;
    226       1.1       jtc 			  case '\'':
    227       1.1       jtc 				*wp++ = OQUOTE;
    228       1.2       tls 				ignore_backslash_newline++;
    229       1.6   hubertf 				PUSH_STATE(SSQUOTE);
    230       1.1       jtc 				break;
    231       1.1       jtc 			  case '"':
    232       1.1       jtc 				*wp++ = OQUOTE;
    233       1.6   hubertf 				PUSH_STATE(SDQUOTE);
    234       1.1       jtc 				break;
    235       1.1       jtc 			  default:
    236       1.1       jtc 				goto Subst;
    237       1.1       jtc 			}
    238       1.1       jtc 			break;
    239       1.1       jtc 
    240       1.1       jtc 		  Subst:
    241       1.1       jtc 			switch (c) {
    242      1.14     hauke 			  Lex_state *s;
    243      1.14     hauke 			  Lex_state *base;
    244      1.14     hauke 
    245       1.1       jtc 			  case '\\':
    246       1.1       jtc 				c = getsc();
    247       1.1       jtc 				switch (c) {
    248      1.12  christos 				  case '\\':
    249       1.1       jtc 				  case '$': case '`':
    250       1.1       jtc 					*wp++ = QCHAR, *wp++ = c;
    251       1.1       jtc 					break;
    252      1.12  christos 				  case '"':
    253      1.12  christos 					if ((cf & HEREDOC) == 0) {
    254      1.12  christos 						*wp++ = QCHAR, *wp++ = c;
    255      1.12  christos 						break;
    256      1.12  christos 					}
    257  1.23.2.1    martin 					/* FALLTHROUGH */
    258       1.1       jtc 				  default:
    259       1.1       jtc 					Xcheck(ws, wp);
    260       1.2       tls 					if (c) { /* trailing \ is lost */
    261       1.2       tls 						*wp++ = CHAR, *wp++ = '\\';
    262       1.2       tls 						*wp++ = CHAR, *wp++ = c;
    263       1.2       tls 					}
    264       1.1       jtc 					break;
    265       1.1       jtc 				}
    266       1.1       jtc 				break;
    267       1.1       jtc 			  case '$':
    268       1.1       jtc 				c = getsc();
    269       1.1       jtc 				if (c == '(') /*)*/ {
    270       1.1       jtc 					c = getsc();
    271       1.1       jtc 					if (c == '(') /*)*/ {
    272       1.6   hubertf 						PUSH_STATE(SASPAREN);
    273       1.6   hubertf 						statep->ls_sasparen.nparen = 2;
    274       1.6   hubertf 						statep->ls_sasparen.start =
    275       1.6   hubertf 							Xsavepos(ws, wp);
    276       1.1       jtc 						*wp++ = EXPRSUB;
    277       1.1       jtc 					} else {
    278       1.1       jtc 						ungetsc(c);
    279       1.6   hubertf 						PUSH_STATE(SCSPAREN);
    280       1.6   hubertf 						statep->ls_scsparen.nparen = 1;
    281       1.6   hubertf 						statep->ls_scsparen.csstate = 0;
    282       1.1       jtc 						*wp++ = COMSUB;
    283       1.1       jtc 					}
    284       1.1       jtc 				} else if (c == '{') /*}*/ {
    285       1.1       jtc 					*wp++ = OSUBST;
    286       1.6   hubertf 					*wp++ = '{'; /*}*/
    287       1.1       jtc 					wp = get_brace_var(&ws, wp);
    288       1.6   hubertf 					c = getsc();
    289       1.6   hubertf 					/* allow :# and :% (ksh88 compat) */
    290       1.6   hubertf 					if (c == ':') {
    291       1.6   hubertf 						*wp++ = CHAR, *wp++ = c;
    292       1.6   hubertf 						c = getsc();
    293       1.6   hubertf 					}
    294       1.1       jtc 					/* If this is a trim operation,
    295       1.6   hubertf 					 * treat (,|,) specially in STBRACE.
    296       1.1       jtc 					 */
    297       1.1       jtc 					if (c == '#' || c == '%') {
    298       1.6   hubertf 						ungetsc(c);
    299       1.6   hubertf 						PUSH_STATE(STBRACE);
    300       1.1       jtc 					} else {
    301       1.1       jtc 						ungetsc(c);
    302       1.6   hubertf 						PUSH_STATE(SBRACE);
    303       1.1       jtc 					}
    304       1.1       jtc 				} else if (ctype(c, C_ALPHA)) {
    305       1.1       jtc 					*wp++ = OSUBST;
    306       1.6   hubertf 					*wp++ = 'X';
    307       1.1       jtc 					do {
    308       1.1       jtc 						Xcheck(ws, wp);
    309       1.1       jtc 						*wp++ = c;
    310       1.1       jtc 						c = getsc();
    311       1.1       jtc 					} while (ctype(c, C_ALPHA|C_DIGIT));
    312       1.1       jtc 					*wp++ = '\0';
    313       1.1       jtc 					*wp++ = CSUBST;
    314       1.6   hubertf 					*wp++ = 'X';
    315       1.1       jtc 					ungetsc(c);
    316       1.1       jtc 				} else if (ctype(c, C_DIGIT|C_VAR1)) {
    317       1.1       jtc 					Xcheck(ws, wp);
    318       1.1       jtc 					*wp++ = OSUBST;
    319       1.6   hubertf 					*wp++ = 'X';
    320       1.1       jtc 					*wp++ = c;
    321       1.1       jtc 					*wp++ = '\0';
    322       1.1       jtc 					*wp++ = CSUBST;
    323       1.6   hubertf 					*wp++ = 'X';
    324       1.1       jtc 				} else {
    325       1.1       jtc 					*wp++ = CHAR, *wp++ = '$';
    326       1.1       jtc 					ungetsc(c);
    327       1.1       jtc 				}
    328       1.1       jtc 				break;
    329       1.1       jtc 			  case '`':
    330       1.6   hubertf 				PUSH_STATE(SBQUOTE);
    331       1.1       jtc 				*wp++ = COMSUB;
    332       1.1       jtc 				/* Need to know if we are inside double quotes
    333       1.1       jtc 				 * since sh/at&t-ksh translate the \" to " in
    334      1.13       apb 				 * "`..\"..`".  POSIX also requires this.
    335      1.13       apb 				 * An earlier version of ksh misinterpreted
    336      1.13       apb 				 * the POSIX specification and performed
    337      1.13       apb 				 * removal of backslash escapes only if
    338      1.13       apb 				 * posix mode was not in effect.
    339       1.1       jtc 				 */
    340       1.6   hubertf 				statep->ls_sbquote.indquotes = 0;
    341      1.14     hauke 				s = statep;
    342      1.14     hauke 				base = state_info.base;
    343      1.13       apb 				while (1) {
    344      1.13       apb 					for (; s != base; s--) {
    345      1.13       apb 						if (s->ls_state == SDQUOTE) {
    346      1.13       apb 							statep->ls_sbquote.indquotes = 1;
    347      1.13       apb 							break;
    348       1.6   hubertf 						}
    349       1.6   hubertf 					}
    350      1.13       apb 					if (s != base)
    351      1.13       apb 						break;
    352      1.13       apb 					if (!(s = s->ls_info.base))
    353      1.13       apb 						break;
    354      1.13       apb 					base = s-- - STATE_BSIZE;
    355       1.6   hubertf 				}
    356       1.1       jtc 				break;
    357       1.1       jtc 			  default:
    358       1.1       jtc 				*wp++ = CHAR, *wp++ = c;
    359       1.1       jtc 			}
    360       1.1       jtc 			break;
    361       1.1       jtc 
    362       1.1       jtc 		  case SSQUOTE:
    363       1.1       jtc 			if (c == '\'') {
    364       1.6   hubertf 				POP_STATE();
    365       1.1       jtc 				*wp++ = CQUOTE;
    366       1.2       tls 				ignore_backslash_newline--;
    367       1.1       jtc 			} else
    368       1.1       jtc 				*wp++ = QCHAR, *wp++ = c;
    369       1.1       jtc 			break;
    370       1.1       jtc 
    371       1.1       jtc 		  case SDQUOTE:
    372       1.1       jtc 			if (c == '"') {
    373       1.6   hubertf 				POP_STATE();
    374       1.1       jtc 				*wp++ = CQUOTE;
    375       1.1       jtc 			} else
    376       1.1       jtc 				goto Subst;
    377       1.1       jtc 			break;
    378       1.1       jtc 
    379       1.6   hubertf 		  case SCSPAREN: /* $( .. ) */
    380       1.1       jtc 			/* todo: deal with $(...) quoting properly
    381       1.1       jtc 			 * kludge to partly fake quoting inside $(..): doesn't
    382       1.1       jtc 			 * really work because nested $(..) or ${..} inside
    383       1.1       jtc 			 * double quotes aren't dealt with.
    384       1.1       jtc 			 */
    385       1.6   hubertf 			switch (statep->ls_scsparen.csstate) {
    386       1.1       jtc 			  case 0: /* normal */
    387       1.1       jtc 				switch (c) {
    388       1.1       jtc 				  case '(':
    389       1.6   hubertf 					statep->ls_scsparen.nparen++;
    390       1.1       jtc 					break;
    391       1.1       jtc 				  case ')':
    392       1.6   hubertf 					statep->ls_scsparen.nparen--;
    393       1.1       jtc 					break;
    394       1.1       jtc 				  case '\\':
    395       1.6   hubertf 					statep->ls_scsparen.csstate = 1;
    396       1.1       jtc 					break;
    397       1.1       jtc 				  case '"':
    398       1.6   hubertf 					statep->ls_scsparen.csstate = 2;
    399       1.1       jtc 					break;
    400       1.1       jtc 				  case '\'':
    401       1.6   hubertf 					statep->ls_scsparen.csstate = 4;
    402       1.2       tls 					ignore_backslash_newline++;
    403       1.1       jtc 					break;
    404       1.1       jtc 				}
    405       1.1       jtc 				break;
    406       1.1       jtc 
    407       1.1       jtc 			  case 1: /* backslash in normal mode */
    408       1.1       jtc 			  case 3: /* backslash in double quotes */
    409       1.6   hubertf 				--statep->ls_scsparen.csstate;
    410       1.1       jtc 				break;
    411       1.1       jtc 
    412       1.1       jtc 			  case 2: /* double quotes */
    413       1.1       jtc 				if (c == '"')
    414       1.6   hubertf 					statep->ls_scsparen.csstate = 0;
    415       1.1       jtc 				else if (c == '\\')
    416       1.6   hubertf 					statep->ls_scsparen.csstate = 3;
    417       1.1       jtc 				break;
    418       1.1       jtc 
    419       1.1       jtc 			  case 4: /* single quotes */
    420       1.2       tls 				if (c == '\'') {
    421       1.6   hubertf 					statep->ls_scsparen.csstate = 0;
    422       1.2       tls 					ignore_backslash_newline--;
    423       1.2       tls 				}
    424       1.1       jtc 				break;
    425       1.1       jtc 			}
    426       1.6   hubertf 			if (statep->ls_scsparen.nparen == 0) {
    427       1.6   hubertf 				POP_STATE();
    428       1.1       jtc 				*wp++ = 0; /* end of COMSUB */
    429       1.1       jtc 			} else
    430       1.1       jtc 				*wp++ = c;
    431       1.1       jtc 			break;
    432       1.1       jtc 
    433       1.6   hubertf 		  case SASPAREN: /* $(( .. )) */
    434       1.1       jtc 			/* todo: deal with $((...); (...)) properly */
    435       1.1       jtc 			/* XXX should nest using existing state machine
    436       1.1       jtc 			 *     (embed "..", $(...), etc.) */
    437       1.1       jtc 			if (c == '(')
    438       1.6   hubertf 				statep->ls_sasparen.nparen++;
    439       1.1       jtc 			else if (c == ')') {
    440       1.6   hubertf 				statep->ls_sasparen.nparen--;
    441       1.6   hubertf 				if (statep->ls_sasparen.nparen == 1) {
    442       1.1       jtc 					/*(*/
    443       1.1       jtc 					if ((c2 = getsc()) == ')') {
    444       1.6   hubertf 						POP_STATE();
    445       1.1       jtc 						*wp++ = 0; /* end of EXPRSUB */
    446       1.1       jtc 						break;
    447       1.1       jtc 					} else {
    448       1.6   hubertf 						char *s;
    449       1.6   hubertf 
    450       1.1       jtc 						ungetsc(c2);
    451       1.1       jtc 						/* mismatched parenthesis -
    452       1.1       jtc 						 * assume we were really
    453       1.1       jtc 						 * parsing a $(..) expression
    454       1.1       jtc 						 */
    455       1.6   hubertf 						s = Xrestpos(ws, wp,
    456       1.6   hubertf 						     statep->ls_sasparen.start);
    457       1.6   hubertf 						memmove(s + 1, s, wp - s);
    458       1.6   hubertf 						*s++ = COMSUB;
    459       1.6   hubertf 						*s = '('; /*)*/
    460       1.1       jtc 						wp++;
    461       1.6   hubertf 						statep->ls_scsparen.nparen = 1;
    462       1.6   hubertf 						statep->ls_scsparen.csstate = 0;
    463       1.6   hubertf 						state = statep->ls_state
    464       1.6   hubertf 							= SCSPAREN;
    465       1.6   hubertf 
    466       1.1       jtc 					}
    467       1.1       jtc 				}
    468       1.1       jtc 			}
    469       1.1       jtc 			*wp++ = c;
    470       1.1       jtc 			break;
    471       1.1       jtc 
    472       1.1       jtc 		  case SBRACE:
    473       1.1       jtc 			/*{*/
    474       1.1       jtc 			if (c == '}') {
    475       1.6   hubertf 				POP_STATE();
    476       1.1       jtc 				*wp++ = CSUBST;
    477       1.6   hubertf 				*wp++ = /*{*/ '}';
    478       1.1       jtc 			} else
    479       1.1       jtc 				goto Sbase1;
    480       1.1       jtc 			break;
    481       1.1       jtc 
    482       1.1       jtc 		  case STBRACE:
    483       1.6   hubertf 			/* Same as SBRACE, except (,|,) treated specially */
    484       1.1       jtc 			/*{*/
    485       1.1       jtc 			if (c == '}') {
    486       1.6   hubertf 				POP_STATE();
    487       1.1       jtc 				*wp++ = CSUBST;
    488       1.6   hubertf 				*wp++ = /*{*/ '}';
    489       1.1       jtc 			} else if (c == '|') {
    490       1.1       jtc 				*wp++ = SPAT;
    491       1.6   hubertf 			} else if (c == '(') {
    492       1.6   hubertf 				*wp++ = OPAT;
    493       1.6   hubertf 				*wp++ = ' ';	/* simile for @ */
    494       1.6   hubertf 				PUSH_STATE(SPATTERN);
    495       1.1       jtc 			} else
    496       1.1       jtc 				goto Sbase1;
    497       1.1       jtc 			break;
    498       1.1       jtc 
    499       1.1       jtc 		  case SBQUOTE:
    500       1.1       jtc 			if (c == '`') {
    501       1.1       jtc 				*wp++ = 0;
    502       1.6   hubertf 				POP_STATE();
    503       1.1       jtc 			} else if (c == '\\') {
    504       1.1       jtc 				switch (c = getsc()) {
    505       1.1       jtc 				  case '\\':
    506       1.1       jtc 				  case '$': case '`':
    507       1.1       jtc 					*wp++ = c;
    508       1.1       jtc 					break;
    509       1.1       jtc 				  case '"':
    510       1.6   hubertf 					if (statep->ls_sbquote.indquotes) {
    511       1.1       jtc 						*wp++ = c;
    512       1.1       jtc 						break;
    513       1.1       jtc 					}
    514       1.1       jtc 					/* fall through.. */
    515       1.1       jtc 				  default:
    516       1.2       tls 					if (c) { /* trailing \ is lost */
    517       1.2       tls 						*wp++ = '\\';
    518       1.2       tls 						*wp++ = c;
    519       1.2       tls 					}
    520       1.1       jtc 					break;
    521       1.1       jtc 				}
    522       1.1       jtc 			} else
    523       1.1       jtc 				*wp++ = c;
    524       1.1       jtc 			break;
    525       1.1       jtc 
    526       1.1       jtc 		  case SWORD:	/* ONEWORD */
    527       1.1       jtc 			goto Subst;
    528       1.1       jtc 
    529       1.2       tls #ifdef KSH
    530       1.6   hubertf 		  case SLETPAREN:	/* LETEXPR: (( ... )) */
    531       1.1       jtc 			/*(*/
    532       1.1       jtc 			if (c == ')') {
    533       1.6   hubertf 				if (statep->ls_sletparen.nparen > 0)
    534       1.6   hubertf 				    --statep->ls_sletparen.nparen;
    535       1.1       jtc 				/*(*/
    536       1.1       jtc 				else if ((c2 = getsc()) == ')') {
    537       1.1       jtc 					c = 0;
    538       1.1       jtc 					*wp++ = CQUOTE;
    539       1.1       jtc 					goto Done;
    540       1.1       jtc 				} else
    541       1.1       jtc 					ungetsc(c2);
    542       1.1       jtc 			} else if (c == '(')
    543       1.1       jtc 				/* parenthesis inside quotes and backslashes
    544       1.1       jtc 				 * are lost, but at&t ksh doesn't count them
    545       1.1       jtc 				 * either
    546       1.1       jtc 				 */
    547       1.6   hubertf 				++statep->ls_sletparen.nparen;
    548       1.1       jtc 			goto Sbase2;
    549       1.2       tls #endif /* KSH */
    550       1.1       jtc 
    551       1.1       jtc 		  case SHEREDELIM:	/* <<,<<- delimiter */
    552       1.1       jtc 			/* XXX chuck this state (and the next) - use
    553       1.1       jtc 			 * the existing states ($ and \`..` should be
    554       1.1       jtc 			 * stripped of their specialness after the
    555       1.1       jtc 			 * fact).
    556       1.1       jtc 			 */
    557       1.1       jtc 			/* here delimiters need a special case since
    558       1.1       jtc 			 * $ and `..` are not to be treated specially
    559       1.1       jtc 			 */
    560       1.1       jtc 			if (c == '\\') {
    561       1.1       jtc 				c = getsc();
    562       1.2       tls 				if (c) { /* trailing \ is lost */
    563       1.1       jtc 					*wp++ = QCHAR;
    564       1.1       jtc 					*wp++ = c;
    565       1.1       jtc 				}
    566       1.1       jtc 			} else if (c == '\'') {
    567       1.6   hubertf 				PUSH_STATE(SSQUOTE);
    568       1.1       jtc 				*wp++ = OQUOTE;
    569       1.2       tls 				ignore_backslash_newline++;
    570       1.1       jtc 			} else if (c == '"') {
    571       1.6   hubertf 				state = statep->ls_state = SHEREDQUOTE;
    572       1.1       jtc 				*wp++ = OQUOTE;
    573       1.1       jtc 			} else {
    574       1.1       jtc 				*wp++ = CHAR;
    575       1.1       jtc 				*wp++ = c;
    576       1.1       jtc 			}
    577       1.1       jtc 			break;
    578       1.1       jtc 
    579       1.1       jtc 		  case SHEREDQUOTE:	/* " in <<,<<- delimiter */
    580       1.1       jtc 			if (c == '"') {
    581       1.1       jtc 				*wp++ = CQUOTE;
    582       1.6   hubertf 				state = statep->ls_state = SHEREDELIM;
    583       1.1       jtc 			} else {
    584       1.2       tls 				if (c == '\\') {
    585       1.2       tls 					switch (c = getsc()) {
    586       1.2       tls 					  case '\\': case '"':
    587       1.2       tls 					  case '$': case '`':
    588       1.2       tls 						break;
    589       1.2       tls 					  default:
    590       1.2       tls 						if (c) { /* trailing \ lost */
    591       1.2       tls 							*wp++ = CHAR;
    592       1.2       tls 							*wp++ = '\\';
    593       1.2       tls 						}
    594       1.2       tls 						break;
    595       1.2       tls 					}
    596       1.2       tls 				}
    597       1.1       jtc 				*wp++ = CHAR;
    598       1.1       jtc 				*wp++ = c;
    599       1.1       jtc 			}
    600       1.1       jtc 			break;
    601       1.1       jtc 
    602       1.1       jtc 		  case SPATTERN:	/* in *(...|...) pattern (*+?@!) */
    603       1.1       jtc 			if ( /*(*/ c == ')') {
    604       1.1       jtc 				*wp++ = CPAT;
    605       1.6   hubertf 				POP_STATE();
    606       1.6   hubertf 			} else if (c == '|') {
    607       1.1       jtc 				*wp++ = SPAT;
    608       1.6   hubertf 			} else if (c == '(') {
    609       1.6   hubertf 				*wp++ = OPAT;
    610       1.6   hubertf 				*wp++ = ' ';	/* simile for @ */
    611       1.6   hubertf 				PUSH_STATE(SPATTERN);
    612       1.6   hubertf 			} else
    613       1.1       jtc 				goto Sbase1;
    614       1.1       jtc 			break;
    615       1.1       jtc 		}
    616       1.1       jtc 	}
    617       1.1       jtc Done:
    618       1.1       jtc 	Xcheck(ws, wp);
    619       1.6   hubertf 	if (statep != &states[1])
    620       1.6   hubertf 		/* XXX figure out what is missing */
    621       1.1       jtc 		yyerror("no closing quote\n");
    622       1.1       jtc 
    623       1.1       jtc 	/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
    624       1.1       jtc 	if (state == SHEREDELIM)
    625       1.1       jtc 		state = SBASE;
    626       1.1       jtc 
    627       1.6   hubertf 	dp = Xstring(ws, wp);
    628       1.6   hubertf 	if ((c == '<' || c == '>') && state == SBASE
    629       1.6   hubertf 	    && ((c2 = Xlength(ws, wp)) == 0
    630       1.6   hubertf 	        || (c2 == 2 && dp[0] == CHAR && digit(dp[1]))))
    631       1.6   hubertf 	{
    632       1.6   hubertf 		struct ioword *iop =
    633       1.6   hubertf 				(struct ioword *) alloc(sizeof(*iop), ATEMP);
    634       1.6   hubertf 
    635       1.6   hubertf 		if (c2 == 2)
    636       1.6   hubertf 			iop->unit = dp[1] - '0';
    637       1.6   hubertf 		else
    638       1.6   hubertf 			iop->unit = c == '>'; /* 0 for <, 1 for > */
    639       1.6   hubertf 
    640       1.6   hubertf 		c2 = getsc();
    641       1.6   hubertf 		/* <<, >>, <> are ok, >< is not */
    642       1.6   hubertf 		if (c == c2 || (c == '<' && c2 == '>')) {
    643       1.6   hubertf 			iop->flag = c == c2 ?
    644       1.6   hubertf 				  (c == '>' ? IOCAT : IOHERE) : IORDWR;
    645       1.7   hubertf 			if (iop->flag == IOHERE) {
    646       1.7   hubertf 				if ((c2 = getsc()) == '-') {
    647       1.6   hubertf 					iop->flag |= IOSKIP;
    648       1.7   hubertf 				} else {
    649       1.6   hubertf 					ungetsc(c2);
    650       1.7   hubertf 				}
    651       1.7   hubertf 			}
    652       1.6   hubertf 		} else if (c2 == '&')
    653       1.6   hubertf 			iop->flag = IODUP | (c == '<' ? IORDUP : 0);
    654       1.6   hubertf 		else {
    655       1.6   hubertf 			iop->flag = c == '>' ? IOWRITE : IOREAD;
    656       1.6   hubertf 			if (c == '>' && c2 == '|')
    657       1.6   hubertf 				iop->flag |= IOCLOB;
    658       1.6   hubertf 			else
    659       1.6   hubertf 				ungetsc(c2);
    660       1.6   hubertf 		}
    661       1.6   hubertf 
    662       1.6   hubertf 		iop->name = (char *) 0;
    663       1.6   hubertf 		iop->delim = (char *) 0;
    664       1.6   hubertf 		iop->heredoc = (char *) 0;
    665       1.6   hubertf 		Xfree(ws, wp);	/* free word */
    666       1.6   hubertf 		yylval.iop = iop;
    667       1.6   hubertf 		return REDIR;
    668       1.1       jtc 	}
    669       1.1       jtc 
    670       1.6   hubertf 	if (wp == dp && state == SBASE) {
    671       1.1       jtc 		Xfree(ws, wp);	/* free word */
    672       1.1       jtc 		/* no word, process LEX1 character */
    673       1.1       jtc 		switch (c) {
    674       1.1       jtc 		  default:
    675       1.1       jtc 			return c;
    676       1.1       jtc 
    677       1.1       jtc 		  case '|':
    678       1.1       jtc 		  case '&':
    679       1.1       jtc 		  case ';':
    680       1.1       jtc 			if ((c2 = getsc()) == c)
    681       1.1       jtc 				c = (c == ';') ? BREAK :
    682       1.1       jtc 				    (c == '|') ? LOGOR :
    683       1.1       jtc 				    (c == '&') ? LOGAND :
    684       1.1       jtc 				    YYERRCODE;
    685       1.1       jtc #ifdef KSH
    686       1.1       jtc 			else if (c == '|' && c2 == '&')
    687       1.1       jtc 				c = COPROC;
    688       1.1       jtc #endif /* KSH */
    689       1.1       jtc 			else
    690       1.1       jtc 				ungetsc(c2);
    691       1.1       jtc 			return c;
    692       1.1       jtc 
    693       1.1       jtc 		  case '\n':
    694       1.1       jtc 			gethere();
    695       1.1       jtc 			if (cf & CONTIN)
    696       1.1       jtc 				goto Again;
    697       1.1       jtc 			return c;
    698       1.1       jtc 
    699       1.1       jtc 		  case '(':  /*)*/
    700       1.2       tls #ifdef KSH
    701       1.1       jtc 			if ((c2 = getsc()) == '(') /*)*/
    702       1.6   hubertf 				/* XXX need to handle ((...); (...)) */
    703       1.1       jtc 				c = MDPAREN;
    704       1.1       jtc 			else
    705       1.1       jtc 				ungetsc(c2);
    706       1.2       tls #endif /* KSH */
    707       1.1       jtc 			return c;
    708       1.1       jtc 		  /*(*/
    709       1.1       jtc 		  case ')':
    710       1.1       jtc 			return c;
    711       1.1       jtc 		}
    712       1.1       jtc 	}
    713       1.1       jtc 
    714       1.1       jtc 	*wp++ = EOS;		/* terminate word */
    715       1.1       jtc 	yylval.cp = Xclose(ws, wp);
    716       1.2       tls 	if (state == SWORD
    717       1.2       tls #ifdef KSH
    718       1.6   hubertf 		|| state == SLETPAREN
    719       1.2       tls #endif /* KSH */
    720       1.2       tls 		)	/* ONEWORD? */
    721       1.1       jtc 		return LWORD;
    722       1.1       jtc 	ungetsc(c);		/* unget terminator */
    723       1.1       jtc 
    724       1.1       jtc 	/* copy word to unprefixed string ident */
    725       1.1       jtc 	for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
    726       1.1       jtc 		*dp++ = *sp++;
    727      1.10   mycroft 	/* Make sure the ident array stays '\0' padded */
    728       1.1       jtc 	memset(dp, 0, (ident+IDENT) - dp + 1);
    729       1.1       jtc 	if (c != EOS)
    730       1.1       jtc 		*ident = '\0';	/* word is not unquoted */
    731       1.1       jtc 
    732       1.1       jtc 	if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) {
    733       1.1       jtc 		struct tbl *p;
    734       1.1       jtc 		int h = hash(ident);
    735       1.1       jtc 
    736       1.1       jtc 		/* { */
    737      1.22     kamil 		if ((cf & KEYWORD) && (p = mytsearch(&keywords, ident, h))
    738       1.1       jtc 		    && (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}'))
    739       1.1       jtc 		{
    740       1.1       jtc 			afree(yylval.cp, ATEMP);
    741       1.1       jtc 			return p->val.i;
    742       1.1       jtc 		}
    743      1.22     kamil 		if ((cf & ALIAS) && (p = mytsearch(&aliases, ident, h))
    744       1.1       jtc 		    && (p->flag & ISSET))
    745       1.1       jtc 		{
    746      1.23     kamil 			Source *s;
    747       1.1       jtc 
    748       1.1       jtc 			for (s = source; s->type == SALIAS; s = s->next)
    749       1.1       jtc 				if (s->u.tblp == p)
    750       1.1       jtc 					return LWORD;
    751       1.1       jtc 			/* push alias expansion */
    752       1.1       jtc 			s = pushs(SALIAS, source->areap);
    753       1.1       jtc 			s->start = s->str = p->val.s;
    754       1.1       jtc 			s->u.tblp = p;
    755       1.1       jtc 			s->next = source;
    756       1.1       jtc 			source = s;
    757       1.1       jtc 			afree(yylval.cp, ATEMP);
    758       1.1       jtc 			goto Again;
    759       1.1       jtc 		}
    760       1.1       jtc 	}
    761       1.1       jtc 
    762       1.1       jtc 	return LWORD;
    763       1.1       jtc }
    764       1.1       jtc 
    765       1.1       jtc static void
    766       1.1       jtc gethere()
    767       1.1       jtc {
    768      1.23     kamil 	struct ioword **p;
    769       1.1       jtc 
    770       1.1       jtc 	for (p = heres; p < herep; p++)
    771       1.1       jtc 		readhere(*p);
    772       1.1       jtc 	herep = heres;
    773       1.1       jtc }
    774       1.1       jtc 
    775       1.1       jtc /*
    776       1.1       jtc  * read "<<word" text into temp file
    777       1.1       jtc  */
    778       1.1       jtc 
    779       1.1       jtc static void
    780       1.1       jtc readhere(iop)
    781       1.6   hubertf 	struct ioword *iop;
    782       1.1       jtc {
    783      1.23     kamil 	int c;
    784       1.1       jtc 	char *volatile eof;
    785       1.1       jtc 	char *eofp;
    786       1.2       tls 	int skiptabs;
    787       1.6   hubertf 	XString xs;
    788       1.6   hubertf 	char *xp;
    789       1.6   hubertf 	int xpos;
    790       1.1       jtc 
    791       1.1       jtc 	eof = evalstr(iop->delim, 0);
    792       1.1       jtc 
    793       1.2       tls 	if (!(iop->flag & IOEVAL))
    794       1.2       tls 		ignore_backslash_newline++;
    795       1.2       tls 
    796       1.6   hubertf 	Xinit(xs, xp, 256, ATEMP);
    797       1.6   hubertf 
    798       1.1       jtc 	for (;;) {
    799       1.1       jtc 		eofp = eof;
    800       1.1       jtc 		skiptabs = iop->flag & IOSKIP;
    801       1.6   hubertf 		xpos = Xsavepos(xs, xp);
    802       1.2       tls 		while ((c = getsc()) != 0) {
    803       1.1       jtc 			if (skiptabs) {
    804       1.1       jtc 				if (c == '\t')
    805       1.1       jtc 					continue;
    806       1.1       jtc 				skiptabs = 0;
    807       1.1       jtc 			}
    808       1.1       jtc 			if (c != *eofp)
    809       1.1       jtc 				break;
    810       1.6   hubertf 			Xcheck(xs, xp);
    811       1.6   hubertf 			Xput(xs, xp, c);
    812       1.1       jtc 			eofp++;
    813       1.1       jtc 		}
    814       1.1       jtc 		/* Allow EOF here so commands with out trailing newlines
    815       1.1       jtc 		 * will work (eg, ksh -c '...', $(...), etc).
    816       1.1       jtc 		 */
    817       1.6   hubertf 		if (*eofp == '\0' && (c == 0 || c == '\n')) {
    818       1.6   hubertf 			xp = Xrestpos(xs, xp, xpos);
    819       1.1       jtc 			break;
    820       1.6   hubertf 		}
    821       1.1       jtc 		ungetsc(c);
    822       1.2       tls 		while ((c = getsc()) != '\n') {
    823       1.1       jtc 			if (c == 0)
    824       1.1       jtc 				yyerror("here document `%s' unclosed\n", eof);
    825       1.6   hubertf 			Xcheck(xs, xp);
    826       1.6   hubertf 			Xput(xs, xp, c);
    827       1.1       jtc 		}
    828       1.6   hubertf 		Xcheck(xs, xp);
    829       1.6   hubertf 		Xput(xs, xp, c);
    830       1.1       jtc 	}
    831       1.6   hubertf 	Xput(xs, xp, '\0');
    832       1.6   hubertf 	iop->heredoc = Xclose(xs, xp);
    833       1.6   hubertf 
    834       1.2       tls 	if (!(iop->flag & IOEVAL))
    835       1.2       tls 		ignore_backslash_newline--;
    836       1.1       jtc }
    837       1.1       jtc 
    838       1.1       jtc void
    839       1.1       jtc yyerror(const char *fmt, ...)
    840       1.1       jtc {
    841       1.1       jtc 	va_list va;
    842       1.1       jtc 
    843       1.1       jtc 	/* pop aliases and re-reads */
    844       1.1       jtc 	while (source->type == SALIAS || source->type == SREREAD)
    845       1.1       jtc 		source = source->next;
    846       1.1       jtc 	source->str = null;	/* zap pending input */
    847       1.1       jtc 
    848      1.21     kamil 	error_prefix(true);
    849      1.19     kamil 	va_start(va, fmt);
    850       1.1       jtc 	shf_vfprintf(shl_out, fmt, va);
    851       1.1       jtc 	va_end(va);
    852      1.15     joerg 	errorf("%s", null);
    853       1.1       jtc }
    854       1.1       jtc 
    855       1.1       jtc /*
    856       1.1       jtc  * input for yylex with alias expansion
    857       1.1       jtc  */
    858       1.1       jtc 
    859       1.1       jtc Source *
    860       1.1       jtc pushs(type, areap)
    861       1.1       jtc 	int type;
    862       1.1       jtc 	Area *areap;
    863       1.1       jtc {
    864      1.23     kamil 	Source *s;
    865       1.1       jtc 
    866       1.1       jtc 	s = (Source *) alloc(sizeof(Source), areap);
    867       1.1       jtc 	s->type = type;
    868       1.1       jtc 	s->str = null;
    869       1.1       jtc 	s->start = NULL;
    870       1.1       jtc 	s->line = 0;
    871       1.1       jtc 	s->errline = 0;
    872       1.1       jtc 	s->file = NULL;
    873       1.1       jtc 	s->flags = 0;
    874       1.1       jtc 	s->next = NULL;
    875       1.1       jtc 	s->areap = areap;
    876       1.1       jtc 	if (type == SFILE || type == SSTDIN) {
    877       1.1       jtc 		char *dummy;
    878       1.1       jtc 		Xinit(s->xs, dummy, 256, s->areap);
    879       1.1       jtc 	} else
    880       1.1       jtc 		memset(&s->xs, 0, sizeof(s->xs));
    881       1.1       jtc 	return s;
    882       1.1       jtc }
    883       1.1       jtc 
    884       1.1       jtc static int
    885       1.2       tls getsc__()
    886       1.1       jtc {
    887      1.23     kamil 	Source *s = source;
    888      1.23     kamil 	int c;
    889       1.1       jtc 
    890       1.1       jtc 	while ((c = *s->str++) == 0) {
    891       1.1       jtc 		s->str = NULL;		/* return 0 for EOF by default */
    892       1.1       jtc 		switch (s->type) {
    893       1.1       jtc 		  case SEOF:
    894       1.1       jtc 			s->str = null;
    895       1.1       jtc 			return 0;
    896       1.1       jtc 
    897       1.1       jtc 		  case SSTDIN:
    898       1.1       jtc 		  case SFILE:
    899       1.1       jtc 			getsc_line(s);
    900       1.1       jtc 			break;
    901       1.1       jtc 
    902       1.1       jtc 		  case SWSTR:
    903       1.1       jtc 			break;
    904       1.1       jtc 
    905       1.1       jtc 		  case SSTRING:
    906       1.1       jtc 			break;
    907       1.1       jtc 
    908       1.1       jtc 		  case SWORDS:
    909       1.1       jtc 			s->start = s->str = *s->u.strv++;
    910       1.1       jtc 			s->type = SWORDSEP;
    911       1.1       jtc 			break;
    912       1.1       jtc 
    913       1.1       jtc 		  case SWORDSEP:
    914       1.1       jtc 			if (*s->u.strv == NULL) {
    915       1.1       jtc 				s->start = s->str = newline;
    916       1.1       jtc 				s->type = SEOF;
    917       1.1       jtc 			} else {
    918       1.1       jtc 				s->start = s->str = space;
    919       1.1       jtc 				s->type = SWORDS;
    920       1.1       jtc 			}
    921       1.1       jtc 			break;
    922       1.1       jtc 
    923       1.1       jtc 		  case SALIAS:
    924       1.1       jtc 			if (s->flags & SF_ALIASEND) {
    925       1.1       jtc 				/* pass on an unused SF_ALIAS flag */
    926       1.1       jtc 				source = s->next;
    927       1.1       jtc 				source->flags |= s->flags & SF_ALIAS;
    928       1.1       jtc 				s = source;
    929       1.1       jtc 			} else if (*s->u.tblp->val.s
    930       1.5  christos 				 && isspace((unsigned char)strchr(s->u.tblp->val.s, 0)[-1]))
    931       1.1       jtc 			{
    932       1.1       jtc 				source = s = s->next;	/* pop source stack */
    933       1.2       tls 				/* Note that this alias ended with a space,
    934       1.2       tls 				 * enabling alias expansion on the following
    935       1.2       tls 				 * word.
    936       1.2       tls 				 */
    937       1.1       jtc 				s->flags |= SF_ALIAS;
    938       1.1       jtc 			} else {
    939       1.2       tls 				/* At this point, we need to keep the current
    940       1.2       tls 				 * alias in the source list so recursive
    941       1.2       tls 				 * aliases can be detected and we also need
    942       1.2       tls 				 * to return the next character.  Do this
    943       1.2       tls 				 * by temporarily popping the alias to get
    944       1.2       tls 				 * the next character and then put it back
    945       1.2       tls 				 * in the source list with the SF_ALIASEND
    946       1.2       tls 				 * flag set.
    947       1.1       jtc 				 */
    948       1.2       tls 				source = s->next;	/* pop source stack */
    949       1.2       tls 				source->flags |= s->flags & SF_ALIAS;
    950       1.2       tls 				c = getsc__();
    951       1.2       tls 				if (c) {
    952       1.2       tls 					s->flags |= SF_ALIASEND;
    953       1.2       tls 					s->ugbuf[0] = c; s->ugbuf[1] = '\0';
    954       1.2       tls 					s->start = s->str = s->ugbuf;
    955       1.2       tls 					s->next = source;
    956       1.2       tls 					source = s;
    957       1.2       tls 				} else {
    958       1.2       tls 					s = source;
    959       1.2       tls 					/* avoid reading eof twice */
    960       1.2       tls 					s->str = NULL;
    961       1.2       tls 					break;
    962       1.2       tls 				}
    963       1.1       jtc 			}
    964       1.1       jtc 			continue;
    965       1.1       jtc 
    966       1.1       jtc 		  case SREREAD:
    967       1.2       tls 			if (s->start != s->ugbuf) /* yuck */
    968       1.1       jtc 				afree(s->u.freeme, ATEMP);
    969       1.1       jtc 			source = s = s->next;
    970       1.1       jtc 			continue;
    971       1.1       jtc 		}
    972       1.1       jtc 		if (s->str == NULL) {
    973       1.1       jtc 			s->type = SEOF;
    974       1.1       jtc 			s->start = s->str = null;
    975       1.1       jtc 			return '\0';
    976       1.1       jtc 		}
    977       1.1       jtc 		if (s->flags & SF_ECHO) {
    978       1.1       jtc 			shf_puts(s->str, shl_out);
    979       1.1       jtc 			shf_flush(shl_out);
    980       1.1       jtc 		}
    981       1.1       jtc 	}
    982       1.1       jtc 	return c;
    983       1.1       jtc }
    984       1.1       jtc 
    985       1.1       jtc static void
    986       1.1       jtc getsc_line(s)
    987       1.1       jtc 	Source *s;
    988       1.1       jtc {
    989       1.1       jtc 	char *xp = Xstring(s->xs, xp);
    990       1.1       jtc 	int interactive = Flag(FTALKING) && s->type == SSTDIN;
    991       1.1       jtc 	int have_tty = interactive && (s->flags & SF_TTY);
    992       1.1       jtc 
    993       1.1       jtc 	/* Done here to ensure nothing odd happens when a timeout occurs */
    994       1.1       jtc 	XcheckN(s->xs, xp, LINE);
    995       1.1       jtc 	*xp = '\0';
    996       1.1       jtc 	s->start = s->str = xp;
    997       1.1       jtc 
    998       1.1       jtc #ifdef KSH
    999       1.1       jtc 	if (have_tty && ksh_tmout) {
   1000       1.1       jtc 		ksh_tmout_state = TMOUT_READING;
   1001       1.1       jtc 		alarm(ksh_tmout);
   1002       1.1       jtc 	}
   1003       1.1       jtc #endif /* KSH */
   1004       1.1       jtc #ifdef EDIT
   1005       1.1       jtc 	if (have_tty && (0
   1006       1.1       jtc # ifdef VI
   1007       1.1       jtc 			 || Flag(FVI)
   1008       1.1       jtc # endif /* VI */
   1009       1.1       jtc # ifdef EMACS
   1010       1.1       jtc 			 || Flag(FEMACS) || Flag(FGMACS)
   1011       1.1       jtc # endif /* EMACS */
   1012       1.1       jtc 		))
   1013       1.1       jtc 	{
   1014       1.1       jtc 		int nread;
   1015       1.1       jtc 
   1016       1.1       jtc 		nread = x_read(xp, LINE);
   1017       1.1       jtc 		if (nread < 0)	/* read error */
   1018       1.1       jtc 			nread = 0;
   1019       1.1       jtc 		xp[nread] = '\0';
   1020       1.1       jtc 		xp += nread;
   1021       1.1       jtc 	}
   1022       1.1       jtc 	else
   1023       1.1       jtc #endif /* EDIT */
   1024       1.1       jtc 	{
   1025       1.1       jtc 		if (interactive) {
   1026       1.1       jtc 			pprompt(prompt, 0);
   1027       1.1       jtc 		} else
   1028       1.1       jtc 			s->line++;
   1029       1.1       jtc 
   1030       1.1       jtc 		while (1) {
   1031       1.1       jtc 			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
   1032       1.1       jtc 
   1033       1.1       jtc 			if (!p && shf_error(s->u.shf)
   1034       1.1       jtc 			    && shf_errno(s->u.shf) == EINTR)
   1035       1.1       jtc 			{
   1036       1.1       jtc 				shf_clearerr(s->u.shf);
   1037       1.1       jtc 				if (trap)
   1038       1.1       jtc 					runtraps(0);
   1039       1.1       jtc 				continue;
   1040       1.1       jtc 			}
   1041       1.1       jtc 			if (!p || (xp = p, xp[-1] == '\n'))
   1042       1.1       jtc 				break;
   1043       1.1       jtc 			/* double buffer size */
   1044       1.1       jtc 			xp++; /* move past null so doubling works... */
   1045       1.1       jtc 			XcheckN(s->xs, xp, Xlength(s->xs, xp));
   1046       1.1       jtc 			xp--; /* ...and move back again */
   1047       1.1       jtc 		}
   1048       1.1       jtc 		/* flush any unwanted input so other programs/builtins
   1049       1.1       jtc 		 * can read it.  Not very optimal, but less error prone
   1050       1.1       jtc 		 * than flushing else where, dealing with redirections,
   1051       1.1       jtc 		 * etc..
   1052       1.1       jtc 		 * todo: reduce size of shf buffer (~128?) if SSTDIN
   1053       1.1       jtc 		 */
   1054       1.1       jtc 		if (s->type == SSTDIN)
   1055       1.1       jtc 			shf_flush(s->u.shf);
   1056       1.1       jtc 	}
   1057       1.1       jtc 	/* XXX: temporary kludge to restore source after a
   1058       1.1       jtc 	 * trap may have been executed.
   1059       1.1       jtc 	 */
   1060       1.1       jtc 	source = s;
   1061       1.1       jtc #ifdef KSH
   1062       1.1       jtc 	if (have_tty && ksh_tmout)
   1063       1.1       jtc 	{
   1064       1.1       jtc 		ksh_tmout_state = TMOUT_EXECUTING;
   1065       1.1       jtc 		alarm(0);
   1066       1.1       jtc 	}
   1067       1.1       jtc #endif /* KSH */
   1068       1.1       jtc 	s->start = s->str = Xstring(s->xs, xp);
   1069       1.1       jtc 	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
   1070       1.1       jtc 	/* Note: if input is all nulls, this is not eof */
   1071       1.1       jtc 	if (Xlength(s->xs, xp) == 0) { /* EOF */
   1072       1.1       jtc 		if (s->type == SFILE)
   1073       1.1       jtc 			shf_fdclose(s->u.shf);
   1074       1.1       jtc 		s->str = NULL;
   1075       1.1       jtc 	} else if (interactive) {
   1076       1.1       jtc #ifdef HISTORY
   1077       1.1       jtc 		char *p = Xstring(s->xs, xp);
   1078       1.1       jtc 		if (cur_prompt == PS1)
   1079       1.1       jtc 			while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS))
   1080       1.1       jtc 				p++;
   1081       1.1       jtc 		if (*p) {
   1082       1.1       jtc # ifdef EASY_HISTORY
   1083       1.1       jtc 			if (cur_prompt == PS2)
   1084       1.1       jtc 				histappend(Xstring(s->xs, xp), 1);
   1085       1.1       jtc 			else
   1086       1.1       jtc # endif /* EASY_HISTORY */
   1087       1.1       jtc 			{
   1088       1.1       jtc 				s->line++;
   1089       1.1       jtc 				histsave(s->line, s->str, 1);
   1090       1.1       jtc 			}
   1091       1.1       jtc 		}
   1092       1.1       jtc #endif /* HISTORY */
   1093       1.1       jtc 	}
   1094       1.1       jtc 	if (interactive)
   1095       1.1       jtc 		set_prompt(PS2, (Source *) 0);
   1096       1.1       jtc }
   1097       1.1       jtc 
   1098       1.1       jtc void
   1099       1.1       jtc set_prompt(to, s)
   1100       1.1       jtc 	int to;
   1101       1.1       jtc 	Source *s;
   1102       1.1       jtc {
   1103       1.1       jtc 	cur_prompt = to;
   1104       1.1       jtc 
   1105       1.1       jtc 	switch (to) {
   1106       1.1       jtc 	case PS1: /* command */
   1107       1.1       jtc #ifdef KSH
   1108       1.1       jtc 		/* Substitute ! and !! here, before substitutions are done
   1109       1.1       jtc 		 * so ! in expanded variables are not expanded.
   1110       1.1       jtc 		 * NOTE: this is not what at&t ksh does (it does it after
   1111       1.1       jtc 		 * substitutions, POSIX doesn't say which is to be done.
   1112       1.1       jtc 		 */
   1113       1.1       jtc 		{
   1114       1.1       jtc 			struct shf *shf;
   1115      1.10   mycroft 			char * volatile ps1;
   1116       1.1       jtc 			Area *saved_atemp;
   1117       1.1       jtc 
   1118       1.1       jtc 			ps1 = str_val(global("PS1"));
   1119       1.1       jtc 			shf = shf_sopen((char *) 0, strlen(ps1) * 2,
   1120       1.1       jtc 				SHF_WR | SHF_DYNAMIC, (struct shf *) 0);
   1121       1.1       jtc 			while (*ps1) {
   1122       1.1       jtc 				if (*ps1 != '!' || *++ps1 == '!')
   1123       1.1       jtc 					shf_putchar(*ps1++, shf);
   1124       1.1       jtc 				else
   1125       1.1       jtc 					shf_fprintf(shf, "%d",
   1126       1.1       jtc 						s ? s->line + 1 : 0);
   1127       1.1       jtc 			}
   1128       1.1       jtc 			ps1 = shf_sclose(shf);
   1129       1.1       jtc 			saved_atemp = ATEMP;
   1130       1.1       jtc 			newenv(E_ERRH);
   1131       1.1       jtc 			if (ksh_sigsetjmp(e->jbuf, 0)) {
   1132       1.1       jtc 				prompt = safe_prompt;
   1133       1.1       jtc 				/* Don't print an error - assume it has already
   1134       1.1       jtc 				 * been printed.  Reason is we may have forked
   1135       1.1       jtc 				 * to run a command and the child may be
   1136       1.1       jtc 				 * unwinding its stack through this code as it
   1137       1.1       jtc 				 * exits.
   1138       1.1       jtc 				 */
   1139       1.1       jtc 			} else
   1140       1.1       jtc 				prompt = str_save(substitute(ps1, 0),
   1141       1.1       jtc 						 saved_atemp);
   1142       1.1       jtc 			quitenv();
   1143       1.1       jtc 		}
   1144       1.1       jtc #else /* KSH */
   1145       1.1       jtc 		prompt = str_val(global("PS1"));
   1146       1.1       jtc #endif /* KSH */
   1147       1.1       jtc 		break;
   1148       1.1       jtc 
   1149       1.1       jtc 	case PS2: /* command continuation */
   1150       1.1       jtc 		prompt = str_val(global("PS2"));
   1151       1.1       jtc 		break;
   1152       1.1       jtc 	}
   1153       1.1       jtc }
   1154       1.1       jtc 
   1155       1.1       jtc /* See also related routine, promptlen() in edit.c */
   1156       1.1       jtc void
   1157       1.1       jtc pprompt(cp, ntruncate)
   1158       1.1       jtc 	const char *cp;
   1159       1.1       jtc 	int ntruncate;
   1160       1.1       jtc {
   1161       1.1       jtc #if 0
   1162       1.1       jtc 	char nbuf[32];
   1163       1.1       jtc 	int c;
   1164       1.1       jtc 
   1165       1.1       jtc 	while (*cp != 0) {
   1166       1.1       jtc 		if (*cp != '!')
   1167       1.1       jtc 			c = *cp++;
   1168       1.1       jtc 		else if (*++cp == '!')
   1169       1.1       jtc 			c = *cp++;
   1170       1.1       jtc 		else {
   1171       1.1       jtc 			int len;
   1172       1.1       jtc 			char *p;
   1173       1.1       jtc 
   1174       1.1       jtc 			shf_snprintf(p = nbuf, sizeof(nbuf), "%d",
   1175       1.1       jtc 				source->line + 1);
   1176       1.1       jtc 			len = strlen(nbuf);
   1177       1.1       jtc 			if (ntruncate) {
   1178       1.1       jtc 				if (ntruncate >= len) {
   1179       1.1       jtc 					ntruncate -= len;
   1180       1.1       jtc 					continue;
   1181       1.1       jtc 				}
   1182       1.1       jtc 				p += ntruncate;
   1183       1.1       jtc 				len -= ntruncate;
   1184       1.1       jtc 				ntruncate = 0;
   1185       1.1       jtc 			}
   1186       1.1       jtc 			shf_write(p, len, shl_out);
   1187       1.1       jtc 			continue;
   1188       1.1       jtc 		}
   1189       1.1       jtc 		if (ntruncate)
   1190       1.1       jtc 			--ntruncate;
   1191       1.1       jtc 		else
   1192       1.1       jtc 			shf_putc(c, shl_out);
   1193       1.1       jtc 	}
   1194       1.1       jtc #endif /* 0 */
   1195       1.2       tls 	shf_puts(cp + ntruncate, shl_out);
   1196       1.2       tls 	shf_flush(shl_out);
   1197       1.1       jtc }
   1198       1.1       jtc 
   1199       1.1       jtc /* Read the variable part of a ${...} expression (ie, up to but not including
   1200       1.1       jtc  * the :[-+?=#%] or close-brace.
   1201       1.1       jtc  */
   1202       1.1       jtc static char *
   1203       1.1       jtc get_brace_var(wsp, wp)
   1204       1.1       jtc 	XString *wsp;
   1205       1.1       jtc 	char *wp;
   1206       1.1       jtc {
   1207       1.1       jtc 	enum parse_state {
   1208       1.1       jtc 			   PS_INITIAL, PS_SAW_HASH, PS_IDENT,
   1209       1.1       jtc 			   PS_NUMBER, PS_VAR1, PS_END
   1210       1.1       jtc 			 }
   1211       1.1       jtc 		state;
   1212       1.1       jtc 	char c;
   1213       1.1       jtc 
   1214       1.1       jtc 	state = PS_INITIAL;
   1215       1.1       jtc 	while (1) {
   1216       1.2       tls 		c = getsc();
   1217       1.1       jtc 		/* State machine to figure out where the variable part ends. */
   1218       1.1       jtc 		switch (state) {
   1219       1.1       jtc 		  case PS_INITIAL:
   1220       1.1       jtc 			if (c == '#') {
   1221       1.1       jtc 				state = PS_SAW_HASH;
   1222       1.1       jtc 				break;
   1223       1.1       jtc 			}
   1224       1.1       jtc 			/* fall through.. */
   1225       1.1       jtc 		  case PS_SAW_HASH:
   1226       1.1       jtc 			if (letter(c))
   1227       1.1       jtc 				state = PS_IDENT;
   1228       1.1       jtc 			else if (digit(c))
   1229       1.1       jtc 				state = PS_NUMBER;
   1230       1.1       jtc 			else if (ctype(c, C_VAR1))
   1231       1.1       jtc 				state = PS_VAR1;
   1232       1.1       jtc 			else
   1233       1.1       jtc 				state = PS_END;
   1234       1.1       jtc 			break;
   1235       1.1       jtc 		  case PS_IDENT:
   1236       1.1       jtc 			if (!letnum(c)) {
   1237       1.1       jtc 				state = PS_END;
   1238       1.1       jtc 				if (c == '[') {
   1239       1.1       jtc 					char *tmp, *p;
   1240       1.1       jtc 
   1241       1.1       jtc 					if (!arraysub(&tmp))
   1242       1.1       jtc 						yyerror("missing ]\n");
   1243       1.1       jtc 					*wp++ = c;
   1244       1.1       jtc 					for (p = tmp; *p; ) {
   1245       1.1       jtc 						Xcheck(*wsp, wp);
   1246       1.1       jtc 						*wp++ = *p++;
   1247       1.1       jtc 					}
   1248       1.1       jtc 					afree(tmp, ATEMP);
   1249       1.2       tls 					c = getsc(); /* the ] */
   1250       1.1       jtc 				}
   1251       1.1       jtc 			}
   1252       1.1       jtc 			break;
   1253       1.1       jtc 		  case PS_NUMBER:
   1254       1.1       jtc 			if (!digit(c))
   1255       1.1       jtc 				state = PS_END;
   1256       1.1       jtc 			break;
   1257       1.1       jtc 		  case PS_VAR1:
   1258       1.1       jtc 			state = PS_END;
   1259       1.1       jtc 			break;
   1260       1.1       jtc 		  case PS_END: /* keep gcc happy */
   1261       1.1       jtc 			break;
   1262       1.1       jtc 		}
   1263       1.1       jtc 		if (state == PS_END) {
   1264       1.1       jtc 			*wp++ = '\0';	/* end of variable part */
   1265       1.1       jtc 			ungetsc(c);
   1266       1.1       jtc 			break;
   1267       1.1       jtc 		}
   1268       1.1       jtc 		Xcheck(*wsp, wp);
   1269       1.1       jtc 		*wp++ = c;
   1270       1.1       jtc 	}
   1271       1.1       jtc 	return wp;
   1272       1.1       jtc }
   1273       1.1       jtc 
   1274       1.1       jtc /*
   1275       1.1       jtc  * Save an array subscript - returns true if matching bracket found, false
   1276       1.1       jtc  * if eof or newline was found.
   1277       1.1       jtc  * (Returned string double null terminated)
   1278       1.1       jtc  */
   1279       1.1       jtc static int
   1280       1.1       jtc arraysub(strp)
   1281       1.1       jtc 	char **strp;
   1282       1.1       jtc {
   1283       1.1       jtc 	XString ws;
   1284       1.1       jtc 	char	*wp;
   1285       1.1       jtc 	char	c;
   1286       1.1       jtc 	int 	depth = 1;	/* we are just past the initial [ */
   1287       1.1       jtc 
   1288       1.1       jtc 	Xinit(ws, wp, 32, ATEMP);
   1289       1.1       jtc 
   1290       1.1       jtc 	do {
   1291       1.2       tls 		c = getsc();
   1292       1.1       jtc 		Xcheck(ws, wp);
   1293       1.1       jtc 		*wp++ = c;
   1294       1.1       jtc 		if (c == '[')
   1295       1.1       jtc 			depth++;
   1296       1.1       jtc 		else if (c == ']')
   1297       1.1       jtc 			depth--;
   1298       1.1       jtc 	} while (depth > 0 && c && c != '\n');
   1299       1.1       jtc 
   1300       1.1       jtc 	*wp++ = '\0';
   1301       1.1       jtc 	*strp = Xclose(ws, wp);
   1302       1.1       jtc 
   1303       1.1       jtc 	return depth == 0 ? 1 : 0;
   1304       1.1       jtc }
   1305       1.1       jtc 
   1306       1.1       jtc /* Unget a char: handles case when we are already at the start of the buffer */
   1307       1.1       jtc static const char *
   1308       1.2       tls ungetsc(c)
   1309       1.1       jtc 	int c;
   1310       1.1       jtc {
   1311       1.2       tls 	if (backslash_skip)
   1312       1.2       tls 		backslash_skip--;
   1313       1.1       jtc 	/* Don't unget eof... */
   1314       1.1       jtc 	if (source->str == null && c == '\0')
   1315       1.1       jtc 		return source->str;
   1316       1.1       jtc 	if (source->str > source->start)
   1317       1.1       jtc 		source->str--;
   1318       1.1       jtc 	else {
   1319       1.1       jtc 		Source *s;
   1320       1.1       jtc 
   1321       1.1       jtc 		s = pushs(SREREAD, source->areap);
   1322       1.2       tls 		s->ugbuf[0] = c; s->ugbuf[1] = '\0';
   1323       1.2       tls 		s->start = s->str = s->ugbuf;
   1324       1.1       jtc 		s->next = source;
   1325       1.1       jtc 		source = s;
   1326       1.1       jtc 	}
   1327       1.1       jtc 	return source->str;
   1328       1.1       jtc }
   1329       1.1       jtc 
   1330       1.2       tls 
   1331       1.1       jtc /* Called to get a char that isn't a \newline sequence. */
   1332       1.1       jtc static int
   1333       1.2       tls getsc_bn ARGS((void))
   1334       1.1       jtc {
   1335       1.2       tls 	int c, c2;
   1336       1.2       tls 
   1337       1.2       tls 	if (ignore_backslash_newline)
   1338       1.2       tls 		return getsc_();
   1339       1.2       tls 
   1340       1.2       tls 	if (backslash_skip == 1) {
   1341       1.2       tls 		backslash_skip = 2;
   1342       1.2       tls 		return getsc_();
   1343       1.2       tls 	}
   1344       1.2       tls 
   1345       1.2       tls 	backslash_skip = 0;
   1346       1.1       jtc 
   1347       1.1       jtc 	while (1) {
   1348       1.1       jtc 		c = getsc_();
   1349       1.2       tls 		if (c == '\\') {
   1350       1.2       tls 			if ((c2 = getsc_()) == '\n')
   1351       1.2       tls 				/* ignore the \newline; get the next char... */
   1352       1.2       tls 				continue;
   1353       1.2       tls 			ungetsc(c2);
   1354       1.2       tls 			backslash_skip = 1;
   1355       1.1       jtc 		}
   1356       1.2       tls 		return c;
   1357       1.1       jtc 	}
   1358       1.6   hubertf }
   1359       1.6   hubertf 
   1360       1.6   hubertf static Lex_state *
   1361       1.6   hubertf push_state_(si, old_end)
   1362       1.6   hubertf 	State_info *si;
   1363       1.6   hubertf 	Lex_state *old_end;
   1364       1.6   hubertf {
   1365       1.6   hubertf 	Lex_state	*new = alloc(sizeof(Lex_state) * STATE_BSIZE, ATEMP);
   1366       1.6   hubertf 
   1367       1.6   hubertf 	new[0].ls_info.base = old_end;
   1368       1.6   hubertf 	si->base = &new[0];
   1369       1.6   hubertf 	si->end = &new[STATE_BSIZE];
   1370       1.6   hubertf 	return &new[1];
   1371       1.6   hubertf }
   1372       1.6   hubertf 
   1373       1.6   hubertf static Lex_state *
   1374       1.6   hubertf pop_state_(si, old_end)
   1375       1.6   hubertf 	State_info *si;
   1376       1.6   hubertf 	Lex_state *old_end;
   1377       1.6   hubertf {
   1378       1.6   hubertf 	Lex_state *old_base = si->base;
   1379       1.6   hubertf 
   1380       1.6   hubertf 	si->base = old_end->ls_info.base - STATE_BSIZE;
   1381       1.6   hubertf 	si->end = old_end->ls_info.base;
   1382       1.6   hubertf 
   1383       1.6   hubertf 	afree(old_base, ATEMP);
   1384       1.6   hubertf 
   1385       1.8    simonb 	return si->base + STATE_BSIZE - 1;
   1386       1.1       jtc }
   1387