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