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