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