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