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