Blame lex.c

Packit Service 95ac19
/*	$OpenBSD: lex.c,v 1.51 2015/09/10 22:48:58 nicm Exp $	*/
Packit Service 95ac19
Packit Service 95ac19
/*-
Packit Service 95ac19
 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
Packit Service 95ac19
 *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
Packit Service 95ac19
 *	mirabilos <m@mirbsd.org>
Packit Service 95ac19
 *
Packit Service 95ac19
 * Provided that these terms and disclaimer and all copyright notices
Packit Service 95ac19
 * are retained or reproduced in an accompanying document, permission
Packit Service 95ac19
 * is granted to deal in this work without restriction, including un-
Packit Service 95ac19
 * limited rights to use, publicly perform, distribute, sell, modify,
Packit Service 95ac19
 * merge, give away, or sublicence.
Packit Service 95ac19
 *
Packit Service 95ac19
 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
Packit Service 95ac19
 * the utmost extent permitted by applicable law, neither express nor
Packit Service 95ac19
 * implied; without malicious intent or gross negligence. In no event
Packit Service 95ac19
 * may a licensor, author or contributor be held liable for indirect,
Packit Service 95ac19
 * direct, other damage, loss, or other issues arising in any way out
Packit Service 95ac19
 * of dealing in the work, even if advised of the possibility of such
Packit Service 95ac19
 * damage or existence of a defect, except proven that it results out
Packit Service 95ac19
 * of said person's immediate fault when using the work as intended.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
#include "sh.h"
Packit Service 95ac19
Packit Service 95ac19
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.247 2018/01/14 01:44:01 tg Exp $");
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * states while lexing word
Packit Service 95ac19
 */
Packit Service 95ac19
#define SBASE		0	/* outside any lexical constructs */
Packit Service 95ac19
#define SWORD		1	/* implicit quoting for substitute() */
Packit Service 95ac19
#define SLETPAREN	2	/* inside (( )), implicit quoting */
Packit Service 95ac19
#define SSQUOTE		3	/* inside '' */
Packit Service 95ac19
#define SDQUOTE		4	/* inside "" */
Packit Service 95ac19
#define SEQUOTE		5	/* inside $'' */
Packit Service 95ac19
#define SBRACE		6	/* inside ${} */
Packit Service 95ac19
#define SQBRACE		7	/* inside "${}" */
Packit Service 95ac19
#define SBQUOTE		8	/* inside `` */
Packit Service 95ac19
#define SASPAREN	9	/* inside $(( )) */
Packit Service 95ac19
#define SHEREDELIM	10	/* parsing << or <<- delimiter */
Packit Service 95ac19
#define SHEREDQUOTE	11	/* parsing " in << or <<- delimiter */
Packit Service 95ac19
#define SPATTERN	12	/* parsing *(...|...) pattern (*+?@!) */
Packit Service 95ac19
#define SADELIM		13	/* like SBASE, looking for delimiter */
Packit Service 95ac19
#define STBRACEKORN	14	/* parsing ${...[#%]...} !FSH */
Packit Service 95ac19
#define STBRACEBOURNE	15	/* parsing ${...[#%]...} FSH */
Packit Service 95ac19
#define SINVALID	255	/* invalid state */
Packit Service 95ac19
Packit Service 95ac19
struct sretrace_info {
Packit Service 95ac19
	struct sretrace_info *next;
Packit Service 95ac19
	XString xs;
Packit Service 95ac19
	char *xp;
Packit Service 95ac19
};
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Structure to keep track of the lexing state and the various pieces of info
Packit Service 95ac19
 * needed for each particular state.
Packit Service 95ac19
 */
Packit Service 95ac19
typedef struct lex_state {
Packit Service 95ac19
	union {
Packit Service 95ac19
		/* point to the next state block */
Packit Service 95ac19
		struct lex_state *base;
Packit Service 95ac19
		/* marks start of state output in output string */
Packit Service 95ac19
		size_t start;
Packit Service 95ac19
		/* SBQUOTE: true if in double quotes: "`...`" */
Packit Service 95ac19
		/* SEQUOTE: got NUL, ignore rest of string */
Packit Service 95ac19
		bool abool;
Packit Service 95ac19
		/* SADELIM information */
Packit Service 95ac19
		struct {
Packit Service 95ac19
			/* character to search for */
Packit Service 95ac19
			unsigned char delimiter;
Packit Service 95ac19
			/* max. number of delimiters */
Packit Service 95ac19
			unsigned char num;
Packit Service 95ac19
		} adelim;
Packit Service 95ac19
	} u;
Packit Service 95ac19
	/* count open parentheses */
Packit Service 95ac19
	short nparen;
Packit Service 95ac19
	/* type of this state */
Packit Service 95ac19
	uint8_t type;
Packit Service 95ac19
} Lex_state;
Packit Service 95ac19
#define ls_base		u.base
Packit Service 95ac19
#define ls_start	u.start
Packit Service 95ac19
#define ls_bool		u.abool
Packit Service 95ac19
#define ls_adelim	u.adelim
Packit Service 95ac19
Packit Service 95ac19
typedef struct {
Packit Service 95ac19
	Lex_state *base;
Packit Service 95ac19
	Lex_state *end;
Packit Service 95ac19
} State_info;
Packit Service 95ac19
Packit Service 95ac19
static void readhere(struct ioword *);
Packit Service 95ac19
static void ungetsc(int);
Packit Service 95ac19
static void ungetsc_i(int);
Packit Service 95ac19
static int getsc_uu(void);
Packit Service 95ac19
static void getsc_line(Source *);
Packit Service 95ac19
static int getsc_bn(void);
Packit Service 95ac19
static int getsc_i(void);
Packit Service 95ac19
static char *get_brace_var(XString *, char *);
Packit Service 95ac19
static bool arraysub(char **);
Packit Service 95ac19
static void gethere(void);
Packit Service 95ac19
static Lex_state *push_state_i(State_info *, Lex_state *);
Packit Service 95ac19
static Lex_state *pop_state_i(State_info *, Lex_state *);
Packit Service 95ac19
Packit Service 95ac19
static int backslash_skip;
Packit Service 95ac19
static int ignore_backslash_newline;
Packit Service 95ac19
Packit Service 95ac19
/* optimised getsc_bn() */
Packit Service 95ac19
#define o_getsc()	(*source->str != '\0' && *source->str != '\\' && \
Packit Service 95ac19
			    !backslash_skip ? *source->str++ : getsc_bn())
Packit Service 95ac19
/* optimised getsc_uu() */
Packit Service 95ac19
#define	o_getsc_u()	((*source->str != '\0') ? *source->str++ : getsc_uu())
Packit Service 95ac19
Packit Service 95ac19
/* retrace helper */
Packit Service 95ac19
#define o_getsc_r(carg)					\
Packit Service 95ac19
	int cev = (carg);				\
Packit Service 95ac19
	struct sretrace_info *rp = retrace_info;	\
Packit Service 95ac19
							\
Packit Service 95ac19
	while (rp) {					\
Packit Service 95ac19
		Xcheck(rp->xs, rp->xp);			\
Packit Service 95ac19
		*rp->xp++ = cev;			\
Packit Service 95ac19
		rp = rp->next;				\
Packit Service 95ac19
	}						\
Packit Service 95ac19
							\
Packit Service 95ac19
	return (cev);
Packit Service 95ac19
Packit Service 95ac19
/* callback */
Packit Service 95ac19
static int
Packit Service 95ac19
getsc_i(void)
Packit Service 95ac19
{
Packit Service 95ac19
	o_getsc_r((unsigned int)(unsigned char)o_getsc());
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
Packit Service 95ac19
#define getsc()		getsc_i()
Packit Service 95ac19
#else
Packit Service 95ac19
static int getsc_r(int);
Packit Service 95ac19
Packit Service 95ac19
static int
Packit Service 95ac19
getsc_r(int c)
Packit Service 95ac19
{
Packit Service 95ac19
	o_getsc_r(c);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
#define getsc()		getsc_r((unsigned int)(unsigned char)o_getsc())
Packit Service 95ac19
#endif
Packit Service 95ac19
Packit Service 95ac19
#define STATE_BSIZE	8
Packit Service 95ac19
Packit Service 95ac19
#define PUSH_STATE(s)	do {					\
Packit Service 95ac19
	if (++statep == state_info.end)				\
Packit Service 95ac19
		statep = push_state_i(&state_info, statep);	\
Packit Service 95ac19
	state = statep->type = (s);				\
Packit Service 95ac19
} while (/* CONSTCOND */ 0)
Packit Service 95ac19
Packit Service 95ac19
#define POP_STATE()	do {					\
Packit Service 95ac19
	if (--statep == state_info.base)			\
Packit Service 95ac19
		statep = pop_state_i(&state_info, statep);	\
Packit Service 95ac19
	state = statep->type;					\
Packit Service 95ac19
} while (/* CONSTCOND */ 0)
Packit Service 95ac19
Packit Service 95ac19
#define PUSH_SRETRACE(s) do {					\
Packit Service 95ac19
	struct sretrace_info *ri;				\
Packit Service 95ac19
								\
Packit Service 95ac19
	PUSH_STATE(s);						\
Packit Service 95ac19
	statep->ls_start = Xsavepos(ws, wp);			\
Packit Service 95ac19
	ri = alloc(sizeof(struct sretrace_info), ATEMP);	\
Packit Service 95ac19
	Xinit(ri->xs, ri->xp, 64, ATEMP);			\
Packit Service 95ac19
	ri->next = retrace_info;				\
Packit Service 95ac19
	retrace_info = ri;					\
Packit Service 95ac19
} while (/* CONSTCOND */ 0)
Packit Service 95ac19
Packit Service 95ac19
#define POP_SRETRACE()	do {					\
Packit Service 95ac19
	wp = Xrestpos(ws, wp, statep->ls_start);		\
Packit Service 95ac19
	*retrace_info->xp = '\0';				\
Packit Service 95ac19
	sp = Xstring(retrace_info->xs, retrace_info->xp);	\
Packit Service 95ac19
	dp = (void *)retrace_info;				\
Packit Service 95ac19
	retrace_info = retrace_info->next;			\
Packit Service 95ac19
	afree(dp, ATEMP);					\
Packit Service 95ac19
	POP_STATE();						\
Packit Service 95ac19
} while (/* CONSTCOND */ 0)
Packit Service 95ac19
Packit Service 95ac19
/**
Packit Service 95ac19
 * Lexical analyser
Packit Service 95ac19
 *
Packit Service 95ac19
 * tokens are not regular expressions, they are LL(1).
Packit Service 95ac19
 * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
Packit Service 95ac19
 * hence the state stack. Note "$(...)" are now parsed recursively.
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
int
Packit Service 95ac19
yylex(int cf)
Packit Service 95ac19
{
Packit Service 95ac19
	Lex_state states[STATE_BSIZE], *statep, *s2, *base;
Packit Service 95ac19
	State_info state_info;
Packit Service 95ac19
	int c, c2, state;
Packit Service 95ac19
	size_t cz;
Packit Service 95ac19
	XString ws;		/* expandable output word */
Packit Service 95ac19
	char *wp;		/* output word pointer */
Packit Service 95ac19
	char *sp, *dp;
Packit Service 95ac19
Packit Service 95ac19
 Again:
Packit Service 95ac19
	states[0].type = SINVALID;
Packit Service 95ac19
	states[0].ls_base = NULL;
Packit Service 95ac19
	statep = &states[1];
Packit Service 95ac19
	state_info.base = states;
Packit Service 95ac19
	state_info.end = &state_info.base[STATE_BSIZE];
Packit Service 95ac19
Packit Service 95ac19
	Xinit(ws, wp, 64, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	backslash_skip = 0;
Packit Service 95ac19
	ignore_backslash_newline = 0;
Packit Service 95ac19
Packit Service 95ac19
	if (cf & ONEWORD)
Packit Service 95ac19
		state = SWORD;
Packit Service 95ac19
	else if (cf & LETEXPR) {
Packit Service 95ac19
		/* enclose arguments in (double) quotes */
Packit Service 95ac19
		*wp++ = OQUOTE;
Packit Service 95ac19
		state = SLETPAREN;
Packit Service 95ac19
		statep->nparen = 0;
Packit Service 95ac19
	} else {
Packit Service 95ac19
		/* normal lexing */
Packit Service 95ac19
		state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
Packit Service 95ac19
		do {
Packit Service 95ac19
			c = getsc();
Packit Service 95ac19
		} while (ctype(c, C_BLANK));
Packit Service 95ac19
		if (c == '#') {
Packit Service 95ac19
			ignore_backslash_newline++;
Packit Service 95ac19
			do {
Packit Service 95ac19
				c = getsc();
Packit Service 95ac19
			} while (!ctype(c, C_NUL | C_LF));
Packit Service 95ac19
			ignore_backslash_newline--;
Packit Service 95ac19
		}
Packit Service 95ac19
		ungetsc(c);
Packit Service 95ac19
	}
Packit Service 95ac19
	if (source->flags & SF_ALIAS) {
Packit Service 95ac19
		/* trailing ' ' in alias definition */
Packit Service 95ac19
		source->flags &= ~SF_ALIAS;
Packit Service 95ac19
		/* POSIX: trailing space only counts if parsing simple cmd */
Packit Service 95ac19
		if (!Flag(FPOSIX) || (cf & CMDWORD))
Packit Service 95ac19
			cf |= ALIAS;
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* Initial state: one of SWORD SLETPAREN SHEREDELIM SBASE */
Packit Service 95ac19
	statep->type = state;
Packit Service 95ac19
Packit Service 95ac19
	/* collect non-special or quoted characters to form word */
Packit Service 95ac19
	while (!((c = getsc()) == 0 ||
Packit Service 95ac19
	    ((state == SBASE || state == SHEREDELIM) && ctype(c, C_LEX1)))) {
Packit Service 95ac19
		if (state == SBASE &&
Packit Service 95ac19
		    subshell_nesting_type == ORD(/*{*/ '}') &&
Packit Service 95ac19
		    (unsigned int)c == ORD(/*{*/ '}'))
Packit Service 95ac19
			/* possibly end ${ :;} */
Packit Service 95ac19
			break;
Packit Service 95ac19
		Xcheck(ws, wp);
Packit Service 95ac19
		switch (state) {
Packit Service 95ac19
		case SADELIM:
Packit Service 95ac19
			if ((unsigned int)c == ORD('('))
Packit Service 95ac19
				statep->nparen++;
Packit Service 95ac19
			else if ((unsigned int)c == ORD(')'))
Packit Service 95ac19
				statep->nparen--;
Packit Service 95ac19
			else if (statep->nparen == 0 &&
Packit Service 95ac19
			    ((unsigned int)c == ORD(/*{*/ '}') ||
Packit Service 95ac19
			    c == (int)statep->ls_adelim.delimiter)) {
Packit Service 95ac19
				*wp++ = ADELIM;
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
				if ((unsigned int)c == ORD(/*{*/ '}') ||
Packit Service 95ac19
				    --statep->ls_adelim.num == 0)
Packit Service 95ac19
					POP_STATE();
Packit Service 95ac19
				if ((unsigned int)c == ORD(/*{*/ '}'))
Packit Service 95ac19
					POP_STATE();
Packit Service 95ac19
				break;
Packit Service 95ac19
			}
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
		case SBASE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('[') && (cf & CMDASN)) {
Packit Service 95ac19
				/* temporary */
Packit Service 95ac19
				*wp = EOS;
Packit Service 95ac19
				if (is_wdvarname(Xstring(ws, wp), false)) {
Packit Service 95ac19
					char *p, *tmp;
Packit Service 95ac19
Packit Service 95ac19
					if (arraysub(&tmp)) {
Packit Service 95ac19
						*wp++ = CHAR;
Packit Service 95ac19
						*wp++ = c;
Packit Service 95ac19
						for (p = tmp; *p; ) {
Packit Service 95ac19
							Xcheck(ws, wp);
Packit Service 95ac19
							*wp++ = CHAR;
Packit Service 95ac19
							*wp++ = *p++;
Packit Service 95ac19
						}
Packit Service 95ac19
						afree(tmp, ATEMP);
Packit Service 95ac19
						break;
Packit Service 95ac19
					}
Packit Service 95ac19
				}
Packit Service 95ac19
				*wp++ = CHAR;
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
				break;
Packit Service 95ac19
			}
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
 Sbase1:		/* includes *(...|...) pattern (*+?@!) */
Packit Service 95ac19
			if (ctype(c, C_PATMO)) {
Packit Service 95ac19
				c2 = getsc();
Packit Service 95ac19
				if ((unsigned int)c2 == ORD('(' /*)*/)) {
Packit Service 95ac19
					*wp++ = OPAT;
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
					PUSH_STATE(SPATTERN);
Packit Service 95ac19
					break;
Packit Service 95ac19
				}
Packit Service 95ac19
				ungetsc(c2);
Packit Service 95ac19
			}
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
 Sbase2:		/* doesn't include *(...|...) pattern (*+?@!) */
Packit Service 95ac19
			switch (c) {
Packit Service 95ac19
			case ORD('\\'):
Packit Service 95ac19
 getsc_qchar:
Packit Service 95ac19
				if ((c = getsc())) {
Packit Service 95ac19
					/* trailing \ is lost */
Packit Service 95ac19
					*wp++ = QCHAR;
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
				}
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('\''):
Packit Service 95ac19
 open_ssquote_unless_heredoc:
Packit Service 95ac19
				if ((cf & HEREDOC))
Packit Service 95ac19
					goto store_char;
Packit Service 95ac19
				*wp++ = OQUOTE;
Packit Service 95ac19
				ignore_backslash_newline++;
Packit Service 95ac19
				PUSH_STATE(SSQUOTE);
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('"'):
Packit Service 95ac19
 open_sdquote:
Packit Service 95ac19
				*wp++ = OQUOTE;
Packit Service 95ac19
				PUSH_STATE(SDQUOTE);
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('$'):
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * processing of dollar sign belongs into
Packit Service 95ac19
				 * Subst, except for those which can open
Packit Service 95ac19
				 * a string: $'…' and $"…"
Packit Service 95ac19
				 */
Packit Service 95ac19
 subst_dollar_ex:
Packit Service 95ac19
				c = getsc();
Packit Service 95ac19
				switch (c) {
Packit Service 95ac19
				case ORD('"'):
Packit Service 95ac19
					goto open_sdquote;
Packit Service 95ac19
				case ORD('\''):
Packit Service 95ac19
					goto open_sequote;
Packit Service 95ac19
				default:
Packit Service 95ac19
					goto SubstS;
Packit Service 95ac19
				}
Packit Service 95ac19
			default:
Packit Service 95ac19
				goto Subst;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
 Subst:
Packit Service 95ac19
			switch (c) {
Packit Service 95ac19
			case ORD('\\'):
Packit Service 95ac19
				c = getsc();
Packit Service 95ac19
				switch (c) {
Packit Service 95ac19
				case ORD('"'):
Packit Service 95ac19
					if ((cf & HEREDOC))
Packit Service 95ac19
						goto heredocquote;
Packit Service 95ac19
					/* FALLTHROUGH */
Packit Service 95ac19
				case ORD('\\'):
Packit Service 95ac19
				case ORD('$'):
Packit Service 95ac19
				case ORD('`'):
Packit Service 95ac19
 store_qchar:
Packit Service 95ac19
					*wp++ = QCHAR;
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
					break;
Packit Service 95ac19
				default:
Packit Service 95ac19
 heredocquote:
Packit Service 95ac19
					Xcheck(ws, wp);
Packit Service 95ac19
					if (c) {
Packit Service 95ac19
						/* trailing \ is lost */
Packit Service 95ac19
						*wp++ = CHAR;
Packit Service 95ac19
						*wp++ = '\\';
Packit Service 95ac19
						*wp++ = CHAR;
Packit Service 95ac19
						*wp++ = c;
Packit Service 95ac19
					}
Packit Service 95ac19
					break;
Packit Service 95ac19
				}
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('$'):
Packit Service 95ac19
				c = getsc();
Packit Service 95ac19
 SubstS:
Packit Service 95ac19
				if ((unsigned int)c == ORD('(' /*)*/)) {
Packit Service 95ac19
					c = getsc();
Packit Service 95ac19
					if ((unsigned int)c == ORD('(' /*)*/)) {
Packit Service 95ac19
						*wp++ = EXPRSUB;
Packit Service 95ac19
						PUSH_SRETRACE(SASPAREN);
Packit Service 95ac19
						statep->nparen = 2;
Packit Service 95ac19
						*retrace_info->xp++ = '(';
Packit Service 95ac19
					} else {
Packit Service 95ac19
						ungetsc(c);
Packit Service 95ac19
 subst_command:
Packit Service 95ac19
						c = COMSUB;
Packit Service 95ac19
 subst_command2:
Packit Service 95ac19
						sp = yyrecursive(c);
Packit Service 95ac19
						cz = strlen(sp) + 1;
Packit Service 95ac19
						XcheckN(ws, wp, cz);
Packit Service 95ac19
						*wp++ = c;
Packit Service 95ac19
						memcpy(wp, sp, cz);
Packit Service 95ac19
						wp += cz;
Packit Service 95ac19
					}
Packit Service 95ac19
				} else if ((unsigned int)c == ORD('{' /*}*/)) {
Packit Service 95ac19
					if ((unsigned int)(c = getsc()) == ORD('|')) {
Packit Service 95ac19
						/*
Packit Service 95ac19
						 * non-subenvironment
Packit Service 95ac19
						 * value substitution
Packit Service 95ac19
						 */
Packit Service 95ac19
						c = VALSUB;
Packit Service 95ac19
						goto subst_command2;
Packit Service 95ac19
					} else if (ctype(c, C_IFSWS)) {
Packit Service 95ac19
						/*
Packit Service 95ac19
						 * non-subenvironment
Packit Service 95ac19
						 * "command" substitution
Packit Service 95ac19
						 */
Packit Service 95ac19
						c = FUNSUB;
Packit Service 95ac19
						goto subst_command2;
Packit Service 95ac19
					}
Packit Service 95ac19
					ungetsc(c);
Packit Service 95ac19
					*wp++ = OSUBST;
Packit Service 95ac19
					*wp++ = '{' /*}*/;
Packit Service 95ac19
					wp = get_brace_var(&ws, wp);
Packit Service 95ac19
					c = getsc();
Packit Service 95ac19
					/* allow :# and :% (ksh88 compat) */
Packit Service 95ac19
					if ((unsigned int)c == ORD(':')) {
Packit Service 95ac19
						*wp++ = CHAR;
Packit Service 95ac19
						*wp++ = c;
Packit Service 95ac19
						c = getsc();
Packit Service 95ac19
						if ((unsigned int)c == ORD(':')) {
Packit Service 95ac19
							*wp++ = CHAR;
Packit Service 95ac19
							*wp++ = '0';
Packit Service 95ac19
							*wp++ = ADELIM;
Packit Service 95ac19
							*wp++ = ':';
Packit Service 95ac19
							PUSH_STATE(SBRACE);
Packit Service 95ac19
							PUSH_STATE(SADELIM);
Packit Service 95ac19
							statep->ls_adelim.delimiter = ':';
Packit Service 95ac19
							statep->ls_adelim.num = 1;
Packit Service 95ac19
							statep->nparen = 0;
Packit Service 95ac19
							break;
Packit Service 95ac19
						} else if (ctype(c, C_DIGIT | C_DOLAR | C_SPC) ||
Packit Service 95ac19
						    /*XXX what else? */
Packit Service 95ac19
						    c == '(' /*)*/) {
Packit Service 95ac19
							/* substring subst. */
Packit Service 95ac19
							if (c != ' ') {
Packit Service 95ac19
								*wp++ = CHAR;
Packit Service 95ac19
								*wp++ = ' ';
Packit Service 95ac19
							}
Packit Service 95ac19
							ungetsc(c);
Packit Service 95ac19
							PUSH_STATE(SBRACE);
Packit Service 95ac19
							PUSH_STATE(SADELIM);
Packit Service 95ac19
							statep->ls_adelim.delimiter = ':';
Packit Service 95ac19
							statep->ls_adelim.num = 2;
Packit Service 95ac19
							statep->nparen = 0;
Packit Service 95ac19
							break;
Packit Service 95ac19
						}
Packit Service 95ac19
					} else if (c == '/') {
Packit Service 95ac19
						c2 = ADELIM;
Packit Service 95ac19
 parse_adelim_slash:
Packit Service 95ac19
						*wp++ = CHAR;
Packit Service 95ac19
						*wp++ = c;
Packit Service 95ac19
						if ((unsigned int)(c = getsc()) == ORD('/')) {
Packit Service 95ac19
							*wp++ = c2;
Packit Service 95ac19
							*wp++ = c;
Packit Service 95ac19
						} else
Packit Service 95ac19
							ungetsc(c);
Packit Service 95ac19
						PUSH_STATE(SBRACE);
Packit Service 95ac19
						PUSH_STATE(SADELIM);
Packit Service 95ac19
						statep->ls_adelim.delimiter = '/';
Packit Service 95ac19
						statep->ls_adelim.num = 1;
Packit Service 95ac19
						statep->nparen = 0;
Packit Service 95ac19
						break;
Packit Service 95ac19
					} else if (c == '@') {
Packit Service 95ac19
						c2 = getsc();
Packit Service 95ac19
						ungetsc(c2);
Packit Service 95ac19
						if ((unsigned int)c2 == ORD('/')) {
Packit Service 95ac19
							c2 = CHAR;
Packit Service 95ac19
							goto parse_adelim_slash;
Packit Service 95ac19
						}
Packit Service 95ac19
					}
Packit Service 95ac19
					/*
Packit Service 95ac19
					 * If this is a trim operation,
Packit Service 95ac19
					 * treat (,|,) specially in STBRACE.
Packit Service 95ac19
					 */
Packit Service 95ac19
					if (ctype(c, C_SUB2)) {
Packit Service 95ac19
						ungetsc(c);
Packit Service 95ac19
						if (Flag(FSH))
Packit Service 95ac19
							PUSH_STATE(STBRACEBOURNE);
Packit Service 95ac19
						else
Packit Service 95ac19
							PUSH_STATE(STBRACEKORN);
Packit Service 95ac19
					} else {
Packit Service 95ac19
						ungetsc(c);
Packit Service 95ac19
						if (state == SDQUOTE ||
Packit Service 95ac19
						    state == SQBRACE)
Packit Service 95ac19
							PUSH_STATE(SQBRACE);
Packit Service 95ac19
						else
Packit Service 95ac19
							PUSH_STATE(SBRACE);
Packit Service 95ac19
					}
Packit Service 95ac19
				} else if (ctype(c, C_ALPHX)) {
Packit Service 95ac19
					*wp++ = OSUBST;
Packit Service 95ac19
					*wp++ = 'X';
Packit Service 95ac19
					do {
Packit Service 95ac19
						Xcheck(ws, wp);
Packit Service 95ac19
						*wp++ = c;
Packit Service 95ac19
						c = getsc();
Packit Service 95ac19
					} while (ctype(c, C_ALNUX));
Packit Service 95ac19
					*wp++ = '\0';
Packit Service 95ac19
					*wp++ = CSUBST;
Packit Service 95ac19
					*wp++ = 'X';
Packit Service 95ac19
					ungetsc(c);
Packit Service 95ac19
				} else if (ctype(c, C_VAR1 | C_DIGIT)) {
Packit Service 95ac19
					Xcheck(ws, wp);
Packit Service 95ac19
					*wp++ = OSUBST;
Packit Service 95ac19
					*wp++ = 'X';
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
					*wp++ = '\0';
Packit Service 95ac19
					*wp++ = CSUBST;
Packit Service 95ac19
					*wp++ = 'X';
Packit Service 95ac19
				} else {
Packit Service 95ac19
					*wp++ = CHAR;
Packit Service 95ac19
					*wp++ = '$';
Packit Service 95ac19
					ungetsc(c);
Packit Service 95ac19
				}
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('`'):
Packit Service 95ac19
 subst_gravis:
Packit Service 95ac19
				PUSH_STATE(SBQUOTE);
Packit Service 95ac19
				*wp++ = COMASUB;
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * We need to know whether we are within double
Packit Service 95ac19
				 * quotes in order to translate \" to " within
Packit Service 95ac19
				 * "…`…\"…`…" because, unlike for COMSUBs, the
Packit Service 95ac19
				 * outer double quoteing changes the backslash
Packit Service 95ac19
				 * meaning for the inside. For more details:
Packit Service 95ac19
				 * http://austingroupbugs.net/view.php?id=1015
Packit Service 95ac19
				 */
Packit Service 95ac19
				statep->ls_bool = false;
Packit Service 95ac19
				s2 = statep;
Packit Service 95ac19
				base = state_info.base;
Packit Service 95ac19
				while (/* CONSTCOND */ 1) {
Packit Service 95ac19
					for (; s2 != base; s2--) {
Packit Service 95ac19
						if (s2->type == SDQUOTE) {
Packit Service 95ac19
							statep->ls_bool = true;
Packit Service 95ac19
							break;
Packit Service 95ac19
						}
Packit Service 95ac19
					}
Packit Service 95ac19
					if (s2 != base)
Packit Service 95ac19
						break;
Packit Service 95ac19
					if (!(s2 = s2->ls_base))
Packit Service 95ac19
						break;
Packit Service 95ac19
					base = s2-- - STATE_BSIZE;
Packit Service 95ac19
				}
Packit Service 95ac19
				break;
Packit Service 95ac19
			case QCHAR:
Packit Service 95ac19
				if (cf & LQCHAR) {
Packit Service 95ac19
					*wp++ = QCHAR;
Packit Service 95ac19
					*wp++ = getsc();
Packit Service 95ac19
					break;
Packit Service 95ac19
				}
Packit Service 95ac19
				/* FALLTHROUGH */
Packit Service 95ac19
			default:
Packit Service 95ac19
 store_char:
Packit Service 95ac19
				*wp++ = CHAR;
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SEQUOTE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('\'')) {
Packit Service 95ac19
				POP_STATE();
Packit Service 95ac19
				*wp++ = CQUOTE;
Packit Service 95ac19
				ignore_backslash_newline--;
Packit Service 95ac19
			} else if ((unsigned int)c == ORD('\\')) {
Packit Service 95ac19
				if ((c2 = unbksl(true, getsc_i, ungetsc)) == -1)
Packit Service 95ac19
					c2 = getsc();
Packit Service 95ac19
				if (c2 == 0)
Packit Service 95ac19
					statep->ls_bool = true;
Packit Service 95ac19
				if (!statep->ls_bool) {
Packit Service 95ac19
					char ts[4];
Packit Service 95ac19
Packit Service 95ac19
					if ((unsigned int)c2 < 0x100) {
Packit Service 95ac19
						*wp++ = QCHAR;
Packit Service 95ac19
						*wp++ = c2;
Packit Service 95ac19
					} else {
Packit Service 95ac19
						cz = utf_wctomb(ts, c2 - 0x100);
Packit Service 95ac19
						ts[cz] = 0;
Packit Service 95ac19
						cz = 0;
Packit Service 95ac19
						do {
Packit Service 95ac19
							*wp++ = QCHAR;
Packit Service 95ac19
							*wp++ = ts[cz];
Packit Service 95ac19
						} while (ts[++cz]);
Packit Service 95ac19
					}
Packit Service 95ac19
				}
Packit Service 95ac19
			} else if (!statep->ls_bool) {
Packit Service 95ac19
				*wp++ = QCHAR;
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SSQUOTE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('\'')) {
Packit Service 95ac19
				POP_STATE();
Packit Service 95ac19
				if ((cf & HEREDOC) || state == SQBRACE)
Packit Service 95ac19
					goto store_char;
Packit Service 95ac19
				*wp++ = CQUOTE;
Packit Service 95ac19
				ignore_backslash_newline--;
Packit Service 95ac19
			} else {
Packit Service 95ac19
				*wp++ = QCHAR;
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SDQUOTE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('"')) {
Packit Service 95ac19
				POP_STATE();
Packit Service 95ac19
				*wp++ = CQUOTE;
Packit Service 95ac19
			} else
Packit Service 95ac19
				goto Subst;
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		/* $(( ... )) */
Packit Service 95ac19
		case SASPAREN:
Packit Service 95ac19
			if ((unsigned int)c == ORD('('))
Packit Service 95ac19
				statep->nparen++;
Packit Service 95ac19
			else if ((unsigned int)c == ORD(')')) {
Packit Service 95ac19
				statep->nparen--;
Packit Service 95ac19
				if (statep->nparen == 1) {
Packit Service 95ac19
					/* end of EXPRSUB */
Packit Service 95ac19
					POP_SRETRACE();
Packit Service 95ac19
Packit Service 95ac19
					if ((unsigned int)(c2 = getsc()) == ORD(/*(*/ ')')) {
Packit Service 95ac19
						cz = strlen(sp) - 2;
Packit Service 95ac19
						XcheckN(ws, wp, cz);
Packit Service 95ac19
						memcpy(wp, sp + 1, cz);
Packit Service 95ac19
						wp += cz;
Packit Service 95ac19
						afree(sp, ATEMP);
Packit Service 95ac19
						*wp++ = '\0';
Packit Service 95ac19
						break;
Packit Service 95ac19
					} else {
Packit Service 95ac19
						Source *s;
Packit Service 95ac19
Packit Service 95ac19
						ungetsc(c2);
Packit Service 95ac19
						/*
Packit Service 95ac19
						 * mismatched parenthesis -
Packit Service 95ac19
						 * assume we were really
Packit Service 95ac19
						 * parsing a $(...) expression
Packit Service 95ac19
						 */
Packit Service 95ac19
						--wp;
Packit Service 95ac19
						s = pushs(SREREAD,
Packit Service 95ac19
						    source->areap);
Packit Service 95ac19
						s->start = s->str =
Packit Service 95ac19
						    s->u.freeme = sp;
Packit Service 95ac19
						s->next = source;
Packit Service 95ac19
						source = s;
Packit Service 95ac19
						goto subst_command;
Packit Service 95ac19
					}
Packit Service 95ac19
				}
Packit Service 95ac19
			}
Packit Service 95ac19
			/* reuse existing state machine */
Packit Service 95ac19
			goto Sbase2;
Packit Service 95ac19
Packit Service 95ac19
		case SQBRACE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('\\')) {
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * perform POSIX "quote removal" if the back-
Packit Service 95ac19
				 * slash is "special", i.e. same cases as the
Packit Service 95ac19
				 * {case '\\':} in Subst: plus closing brace;
Packit Service 95ac19
				 * in mksh code "quote removal" on '\c' means
Packit Service 95ac19
				 * write QCHAR+c, otherwise CHAR+\+CHAR+c are
Packit Service 95ac19
				 * emitted (in heredocquote:)
Packit Service 95ac19
				 */
Packit Service 95ac19
				if ((unsigned int)(c = getsc()) == ORD('"') ||
Packit Service 95ac19
				    (unsigned int)c == ORD('\\') ||
Packit Service 95ac19
				    ctype(c, C_DOLAR | C_GRAVE) ||
Packit Service 95ac19
				    (unsigned int)c == ORD(/*{*/ '}'))
Packit Service 95ac19
					goto store_qchar;
Packit Service 95ac19
				goto heredocquote;
Packit Service 95ac19
			}
Packit Service 95ac19
			goto common_SQBRACE;
Packit Service 95ac19
Packit Service 95ac19
		case SBRACE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('\''))
Packit Service 95ac19
				goto open_ssquote_unless_heredoc;
Packit Service 95ac19
			else if ((unsigned int)c == ORD('\\'))
Packit Service 95ac19
				goto getsc_qchar;
Packit Service 95ac19
 common_SQBRACE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('"'))
Packit Service 95ac19
				goto open_sdquote;
Packit Service 95ac19
			else if ((unsigned int)c == ORD('$'))
Packit Service 95ac19
				goto subst_dollar_ex;
Packit Service 95ac19
			else if ((unsigned int)c == ORD('`'))
Packit Service 95ac19
				goto subst_gravis;
Packit Service 95ac19
			else if ((unsigned int)c != ORD(/*{*/ '}'))
Packit Service 95ac19
				goto store_char;
Packit Service 95ac19
			POP_STATE();
Packit Service 95ac19
			*wp++ = CSUBST;
Packit Service 95ac19
			*wp++ = /*{*/ '}';
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		/* Same as SBASE, except (,|,) treated specially */
Packit Service 95ac19
		case STBRACEKORN:
Packit Service 95ac19
			if ((unsigned int)c == ORD('|'))
Packit Service 95ac19
				*wp++ = SPAT;
Packit Service 95ac19
			else if ((unsigned int)c == ORD('(')) {
Packit Service 95ac19
				*wp++ = OPAT;
Packit Service 95ac19
				/* simile for @ */
Packit Service 95ac19
				*wp++ = ' ';
Packit Service 95ac19
				PUSH_STATE(SPATTERN);
Packit Service 95ac19
			} else /* FALLTHROUGH */
Packit Service 95ac19
		case STBRACEBOURNE:
Packit Service 95ac19
			  if ((unsigned int)c == ORD(/*{*/ '}')) {
Packit Service 95ac19
				POP_STATE();
Packit Service 95ac19
				*wp++ = CSUBST;
Packit Service 95ac19
				*wp++ = /*{*/ '}';
Packit Service 95ac19
			} else
Packit Service 95ac19
				goto Sbase1;
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SBQUOTE:
Packit Service 95ac19
			if ((unsigned int)c == ORD('`')) {
Packit Service 95ac19
				*wp++ = 0;
Packit Service 95ac19
				POP_STATE();
Packit Service 95ac19
			} else if ((unsigned int)c == ORD('\\')) {
Packit Service 95ac19
				switch (c = getsc()) {
Packit Service 95ac19
				case 0:
Packit Service 95ac19
					/* trailing \ is lost */
Packit Service 95ac19
					break;
Packit Service 95ac19
				case ORD('$'):
Packit Service 95ac19
				case ORD('`'):
Packit Service 95ac19
				case ORD('\\'):
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
					break;
Packit Service 95ac19
				case ORD('"'):
Packit Service 95ac19
					if (statep->ls_bool) {
Packit Service 95ac19
						*wp++ = c;
Packit Service 95ac19
						break;
Packit Service 95ac19
					}
Packit Service 95ac19
					/* FALLTHROUGH */
Packit Service 95ac19
				default:
Packit Service 95ac19
					*wp++ = '\\';
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
					break;
Packit Service 95ac19
				}
Packit Service 95ac19
			} else
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		/* ONEWORD */
Packit Service 95ac19
		case SWORD:
Packit Service 95ac19
			goto Subst;
Packit Service 95ac19
Packit Service 95ac19
		/* LETEXPR: (( ... )) */
Packit Service 95ac19
		case SLETPAREN:
Packit Service 95ac19
			if ((unsigned int)c == ORD(/*(*/ ')')) {
Packit Service 95ac19
				if (statep->nparen > 0)
Packit Service 95ac19
					--statep->nparen;
Packit Service 95ac19
				else if ((unsigned int)(c2 = getsc()) == ORD(/*(*/ ')')) {
Packit Service 95ac19
					c = 0;
Packit Service 95ac19
					*wp++ = CQUOTE;
Packit Service 95ac19
					goto Done;
Packit Service 95ac19
				} else {
Packit Service 95ac19
					Source *s;
Packit Service 95ac19
Packit Service 95ac19
					ungetsc(c2);
Packit Service 95ac19
					ungetsc(c);
Packit Service 95ac19
					/*
Packit Service 95ac19
					 * mismatched parenthesis -
Packit Service 95ac19
					 * assume we were really
Packit Service 95ac19
					 * parsing a (...) expression
Packit Service 95ac19
					 */
Packit Service 95ac19
					*wp = EOS;
Packit Service 95ac19
					sp = Xstring(ws, wp);
Packit Service 95ac19
					dp = wdstrip(sp + 1, WDS_TPUTS);
Packit Service 95ac19
					s = pushs(SREREAD, source->areap);
Packit Service 95ac19
					s->start = s->str = s->u.freeme = dp;
Packit Service 95ac19
					s->next = source;
Packit Service 95ac19
					source = s;
Packit Service 95ac19
					ungetsc('(' /*)*/);
Packit Service 95ac19
					return (ORD('(' /*)*/));
Packit Service 95ac19
				}
Packit Service 95ac19
			} else if ((unsigned int)c == ORD('('))
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * parentheses inside quotes and
Packit Service 95ac19
				 * backslashes are lost, but AT&T ksh
Packit Service 95ac19
				 * doesn't count them either
Packit Service 95ac19
				 */
Packit Service 95ac19
				++statep->nparen;
Packit Service 95ac19
			goto Sbase2;
Packit Service 95ac19
Packit Service 95ac19
		/* << or <<- delimiter */
Packit Service 95ac19
		case SHEREDELIM:
Packit Service 95ac19
			/*
Packit Service 95ac19
			 * here delimiters need a special case since
Packit Service 95ac19
			 * $ and `...` are not to be treated specially
Packit Service 95ac19
			 */
Packit Service 95ac19
			switch (c) {
Packit Service 95ac19
			case ORD('\\'):
Packit Service 95ac19
				if ((c = getsc())) {
Packit Service 95ac19
					/* trailing \ is lost */
Packit Service 95ac19
					*wp++ = QCHAR;
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
				}
Packit Service 95ac19
				break;
Packit Service 95ac19
			case ORD('\''):
Packit Service 95ac19
				goto open_ssquote_unless_heredoc;
Packit Service 95ac19
			case ORD('$'):
Packit Service 95ac19
				if ((unsigned int)(c2 = getsc()) == ORD('\'')) {
Packit Service 95ac19
 open_sequote:
Packit Service 95ac19
					*wp++ = OQUOTE;
Packit Service 95ac19
					ignore_backslash_newline++;
Packit Service 95ac19
					PUSH_STATE(SEQUOTE);
Packit Service 95ac19
					statep->ls_bool = false;
Packit Service 95ac19
					break;
Packit Service 95ac19
				} else if ((unsigned int)c2 == ORD('"')) {
Packit Service 95ac19
					/* FALLTHROUGH */
Packit Service 95ac19
			case ORD('"'):
Packit Service 95ac19
					PUSH_SRETRACE(SHEREDQUOTE);
Packit Service 95ac19
					break;
Packit Service 95ac19
				}
Packit Service 95ac19
				ungetsc(c2);
Packit Service 95ac19
				/* FALLTHROUGH */
Packit Service 95ac19
			default:
Packit Service 95ac19
				*wp++ = CHAR;
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		/* " in << or <<- delimiter */
Packit Service 95ac19
		case SHEREDQUOTE:
Packit Service 95ac19
			if ((unsigned int)c != ORD('"'))
Packit Service 95ac19
				goto Subst;
Packit Service 95ac19
			POP_SRETRACE();
Packit Service 95ac19
			dp = strnul(sp) - 1;
Packit Service 95ac19
			/* remove the trailing double quote */
Packit Service 95ac19
			*dp = '\0';
Packit Service 95ac19
			/* store the quoted string */
Packit Service 95ac19
			*wp++ = OQUOTE;
Packit Service 95ac19
			XcheckN(ws, wp, (dp - sp) * 2);
Packit Service 95ac19
			dp = sp;
Packit Service 95ac19
			while ((c = *dp++)) {
Packit Service 95ac19
				if (c == '\\') {
Packit Service 95ac19
					switch ((c = *dp++)) {
Packit Service 95ac19
					case ORD('\\'):
Packit Service 95ac19
					case ORD('"'):
Packit Service 95ac19
					case ORD('$'):
Packit Service 95ac19
					case ORD('`'):
Packit Service 95ac19
						break;
Packit Service 95ac19
					default:
Packit Service 95ac19
						*wp++ = CHAR;
Packit Service 95ac19
						*wp++ = '\\';
Packit Service 95ac19
						break;
Packit Service 95ac19
					}
Packit Service 95ac19
				}
Packit Service 95ac19
				*wp++ = CHAR;
Packit Service 95ac19
				*wp++ = c;
Packit Service 95ac19
			}
Packit Service 95ac19
			afree(sp, ATEMP);
Packit Service 95ac19
			*wp++ = CQUOTE;
Packit Service 95ac19
			state = statep->type = SHEREDELIM;
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		/* in *(...|...) pattern (*+?@!) */
Packit Service 95ac19
		case SPATTERN:
Packit Service 95ac19
			if ((unsigned int)c == ORD(/*(*/ ')')) {
Packit Service 95ac19
				*wp++ = CPAT;
Packit Service 95ac19
				POP_STATE();
Packit Service 95ac19
			} else if ((unsigned int)c == ORD('|')) {
Packit Service 95ac19
				*wp++ = SPAT;
Packit Service 95ac19
			} else if ((unsigned int)c == ORD('(')) {
Packit Service 95ac19
				*wp++ = OPAT;
Packit Service 95ac19
				/* simile for @ */
Packit Service 95ac19
				*wp++ = ' ';
Packit Service 95ac19
				PUSH_STATE(SPATTERN);
Packit Service 95ac19
			} else
Packit Service 95ac19
				goto Sbase1;
Packit Service 95ac19
			break;
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
 Done:
Packit Service 95ac19
	Xcheck(ws, wp);
Packit Service 95ac19
	if (statep != &states[1])
Packit Service 95ac19
		/* XXX figure out what is missing */
Packit Service 95ac19
		yyerror("no closing quote");
Packit Service 95ac19
Packit Service 95ac19
	/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
Packit Service 95ac19
	if (state == SHEREDELIM)
Packit Service 95ac19
		state = SBASE;
Packit Service 95ac19
Packit Service 95ac19
	dp = Xstring(ws, wp);
Packit Service 95ac19
	if (state == SBASE && (
Packit Service 95ac19
	    (c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
Packit Service 95ac19
	    ctype(c, C_ANGLE)) && ((c2 = Xlength(ws, wp)) == 0 ||
Packit Service 95ac19
	    (c2 == 2 && dp[0] == CHAR && ctype(dp[1], C_DIGIT)))) {
Packit Service 95ac19
		struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
Packit Service 95ac19
Packit Service 95ac19
		iop->unit = c2 == 2 ? ksh_numdig(dp[1]) : c == '<' ? 0 : 1;
Packit Service 95ac19
Packit Service 95ac19
		if (c == '&') {
Packit Service 95ac19
			if ((unsigned int)(c2 = getsc()) != ORD('>')) {
Packit Service 95ac19
				ungetsc(c2);
Packit Service 95ac19
				goto no_iop;
Packit Service 95ac19
			}
Packit Service 95ac19
			c = c2;
Packit Service 95ac19
			iop->ioflag = IOBASH;
Packit Service 95ac19
		} else
Packit Service 95ac19
			iop->ioflag = 0;
Packit Service 95ac19
Packit Service 95ac19
		c2 = getsc();
Packit Service 95ac19
		/* <<, >>, <> are ok, >< is not */
Packit Service 95ac19
		if (c == c2 || ((unsigned int)c == ORD('<') &&
Packit Service 95ac19
		    (unsigned int)c2 == ORD('>'))) {
Packit Service 95ac19
			iop->ioflag |= c == c2 ?
Packit Service 95ac19
			    ((unsigned int)c == ORD('>') ? IOCAT : IOHERE) : IORDWR;
Packit Service 95ac19
			if (iop->ioflag == IOHERE) {
Packit Service 95ac19
				if ((unsigned int)(c2 = getsc()) == ORD('-'))
Packit Service 95ac19
					iop->ioflag |= IOSKIP;
Packit Service 95ac19
				else if ((unsigned int)c2 == ORD('<'))
Packit Service 95ac19
					iop->ioflag |= IOHERESTR;
Packit Service 95ac19
				else
Packit Service 95ac19
					ungetsc(c2);
Packit Service 95ac19
			}
Packit Service 95ac19
		} else if ((unsigned int)c2 == ORD('&'))
Packit Service 95ac19
			iop->ioflag |= IODUP | ((unsigned int)c == ORD('<') ? IORDUP : 0);
Packit Service 95ac19
		else {
Packit Service 95ac19
			iop->ioflag |= (unsigned int)c == ORD('>') ? IOWRITE : IOREAD;
Packit Service 95ac19
			if ((unsigned int)c == ORD('>') && (unsigned int)c2 == ORD('|'))
Packit Service 95ac19
				iop->ioflag |= IOCLOB;
Packit Service 95ac19
			else
Packit Service 95ac19
				ungetsc(c2);
Packit Service 95ac19
		}
Packit Service 95ac19
Packit Service 95ac19
		iop->ioname = NULL;
Packit Service 95ac19
		iop->delim = NULL;
Packit Service 95ac19
		iop->heredoc = NULL;
Packit Service 95ac19
		/* free word */
Packit Service 95ac19
		Xfree(ws, wp);
Packit Service 95ac19
		yylval.iop = iop;
Packit Service 95ac19
		return (REDIR);
Packit Service 95ac19
 no_iop:
Packit Service 95ac19
		afree(iop, ATEMP);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	if (wp == dp && state == SBASE) {
Packit Service 95ac19
		/* free word */
Packit Service 95ac19
		Xfree(ws, wp);
Packit Service 95ac19
		/* no word, process LEX1 character */
Packit Service 95ac19
		if (((unsigned int)c == ORD('|')) ||
Packit Service 95ac19
		    ((unsigned int)c == ORD('&')) ||
Packit Service 95ac19
		    ((unsigned int)c == ORD(';')) ||
Packit Service 95ac19
		    ((unsigned int)c == ORD('(' /*)*/))) {
Packit Service 95ac19
			if ((c2 = getsc()) == c)
Packit Service 95ac19
				c = ((unsigned int)c == ORD(';')) ? BREAK :
Packit Service 95ac19
				    ((unsigned int)c == ORD('|')) ? LOGOR :
Packit Service 95ac19
				    ((unsigned int)c == ORD('&')) ? LOGAND :
Packit Service 95ac19
				    /* (unsigned int)c == ORD('(' )) */ MDPAREN;
Packit Service 95ac19
			else if ((unsigned int)c == ORD('|') && (unsigned int)c2 == ORD('&'))
Packit Service 95ac19
				c = COPROC;
Packit Service 95ac19
			else if ((unsigned int)c == ORD(';') && (unsigned int)c2 == ORD('|'))
Packit Service 95ac19
				c = BRKEV;
Packit Service 95ac19
			else if ((unsigned int)c == ORD(';') && (unsigned int)c2 == ORD('&'))
Packit Service 95ac19
				c = BRKFT;
Packit Service 95ac19
			else
Packit Service 95ac19
				ungetsc(c2);
Packit Service 95ac19
#ifndef MKSH_SMALL
Packit Service 95ac19
			if (c == BREAK) {
Packit Service 95ac19
				if ((unsigned int)(c2 = getsc()) == ORD('&'))
Packit Service 95ac19
					c = BRKEV;
Packit Service 95ac19
				else
Packit Service 95ac19
					ungetsc(c2);
Packit Service 95ac19
			}
Packit Service 95ac19
#endif
Packit Service 95ac19
		} else if ((unsigned int)c == ORD('\n')) {
Packit Service 95ac19
			if (cf & HEREDELIM)
Packit Service 95ac19
				ungetsc(c);
Packit Service 95ac19
			else {
Packit Service 95ac19
				gethere();
Packit Service 95ac19
				if (cf & CONTIN)
Packit Service 95ac19
					goto Again;
Packit Service 95ac19
			}
Packit Service 95ac19
		} else if (c == '\0' && !(cf & HEREDELIM)) {
Packit Service 95ac19
			struct ioword **p = heres;
Packit Service 95ac19
Packit Service 95ac19
			while (p < herep)
Packit Service 95ac19
				if ((*p)->ioflag & IOHERESTR)
Packit Service 95ac19
					++p;
Packit Service 95ac19
				else
Packit Service 95ac19
					/* ksh -c 'cat <
Packit Service 95ac19
					yyerror(Tf_heredoc,
Packit Service 95ac19
					    evalstr((*p)->delim, 0));
Packit Service 95ac19
		}
Packit Service 95ac19
		return (c);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	/* terminate word */
Packit Service 95ac19
	*wp++ = EOS;
Packit Service 95ac19
	yylval.cp = Xclose(ws, wp);
Packit Service 95ac19
	if (state == SWORD || state == SLETPAREN
Packit Service 95ac19
	    /* XXX ONEWORD? */)
Packit Service 95ac19
		return (LWORD);
Packit Service 95ac19
Packit Service 95ac19
	/* unget terminator */
Packit Service 95ac19
	ungetsc(c);
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * note: the alias-vs-function code below depends on several
Packit Service 95ac19
	 * interna: starting from here, source->str is not modified;
Packit Service 95ac19
	 * the way getsc() and ungetsc() operate; etc.
Packit Service 95ac19
	 */
Packit Service 95ac19
Packit Service 95ac19
	/* copy word to unprefixed string ident */
Packit Service 95ac19
	sp = yylval.cp;
Packit Service 95ac19
	dp = ident;
Packit Service 95ac19
	while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
Packit Service 95ac19
		*dp++ = *sp++;
Packit Service 95ac19
	if (c != EOS)
Packit Service 95ac19
		/* word is not unquoted, or space ran out */
Packit Service 95ac19
		dp = ident;
Packit Service 95ac19
	/* make sure the ident array stays NUL padded */
Packit Service 95ac19
	memset(dp, 0, (ident + IDENT) - dp + 1);
Packit Service 95ac19
Packit Service 95ac19
	if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
Packit Service 95ac19
		struct tbl *p;
Packit Service 95ac19
		uint32_t h = hash(ident);
Packit Service 95ac19
Packit Service 95ac19
		if ((cf & KEYWORD) && (p = ktsearch(&keywords, ident, h)) &&
Packit Service 95ac19
		    (!(cf & ESACONLY) || p->val.i == ESAC ||
Packit Service 95ac19
		    (unsigned int)p->val.i == ORD(/*{*/ '}'))) {
Packit Service 95ac19
			afree(yylval.cp, ATEMP);
Packit Service 95ac19
			return (p->val.i);
Packit Service 95ac19
		}
Packit Service 95ac19
		if ((cf & ALIAS) && (p = ktsearch(&aliases, ident, h)) &&
Packit Service 95ac19
		    (p->flag & ISSET)) {
Packit Service 95ac19
			/*
Packit Service 95ac19
			 * this still points to the same character as the
Packit Service 95ac19
			 * ungetsc'd terminator from above
Packit Service 95ac19
			 */
Packit Service 95ac19
			const char *cp = source->str;
Packit Service 95ac19
Packit Service 95ac19
			/* prefer POSIX but not Korn functions over aliases */
Packit Service 95ac19
			while (ctype(*cp, C_BLANK))
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * this is like getsc() without skipping
Packit Service 95ac19
				 * over Source boundaries (including not
Packit Service 95ac19
				 * parsing ungetsc'd characters that got
Packit Service 95ac19
				 * pushed into an SREREAD) which is what
Packit Service 95ac19
				 * we want here anyway: find out whether
Packit Service 95ac19
				 * the alias name is followed by a POSIX
Packit Service 95ac19
				 * function definition
Packit Service 95ac19
				 */
Packit Service 95ac19
				++cp;
Packit Service 95ac19
			/* prefer functions over aliases */
Packit Service 95ac19
			if (cp[0] != '(' || cp[1] != ')') {
Packit Service 95ac19
				Source *s = source;
Packit Service 95ac19
Packit Service 95ac19
				while (s && (s->flags & SF_HASALIAS))
Packit Service 95ac19
					if (s->u.tblp == p)
Packit Service 95ac19
						return (LWORD);
Packit Service 95ac19
					else
Packit Service 95ac19
						s = s->next;
Packit Service 95ac19
				/* push alias expansion */
Packit Service 95ac19
				s = pushs(SALIAS, source->areap);
Packit Service 95ac19
				s->start = s->str = p->val.s;
Packit Service 95ac19
				s->u.tblp = p;
Packit Service 95ac19
				s->flags |= SF_HASALIAS;
Packit Service 95ac19
				s->line = source->line;
Packit Service 95ac19
				s->next = source;
Packit Service 95ac19
				if (source->type == SEOF) {
Packit Service 95ac19
					/* prevent infinite recursion at EOS */
Packit Service 95ac19
					source->u.tblp = p;
Packit Service 95ac19
					source->flags |= SF_HASALIAS;
Packit Service 95ac19
				}
Packit Service 95ac19
				source = s;
Packit Service 95ac19
				afree(yylval.cp, ATEMP);
Packit Service 95ac19
				goto Again;
Packit Service 95ac19
			}
Packit Service 95ac19
		}
Packit Service 95ac19
	} else if (*ident == '\0') {
Packit Service 95ac19
		/* retain typeset et al. even when quoted */
Packit Service 95ac19
		struct tbl *tt = get_builtin((dp = wdstrip(yylval.cp, 0)));
Packit Service 95ac19
		uint32_t flag = tt ? tt->flag : 0;
Packit Service 95ac19
Packit Service 95ac19
		if (flag & (DECL_UTIL | DECL_FWDR))
Packit Service 95ac19
			strlcpy(ident, dp, sizeof(ident));
Packit Service 95ac19
		afree(dp, ATEMP);
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	return (LWORD);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
gethere(void)
Packit Service 95ac19
{
Packit Service 95ac19
	struct ioword **p;
Packit Service 95ac19
Packit Service 95ac19
	for (p = heres; p < herep; p++)
Packit Service 95ac19
		if (!((*p)->ioflag & IOHERESTR))
Packit Service 95ac19
			readhere(*p);
Packit Service 95ac19
	herep = heres;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * read "<
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
readhere(struct ioword *iop)
Packit Service 95ac19
{
Packit Service 95ac19
	int c;
Packit Service 95ac19
	const char *eof, *eofp;
Packit Service 95ac19
	XString xs;
Packit Service 95ac19
	char *xp;
Packit Service 95ac19
	size_t xpos;
Packit Service 95ac19
Packit Service 95ac19
	eof = evalstr(iop->delim, 0);
Packit Service 95ac19
Packit Service 95ac19
	if (!(iop->ioflag & IOEVAL))
Packit Service 95ac19
		ignore_backslash_newline++;
Packit Service 95ac19
Packit Service 95ac19
	Xinit(xs, xp, 256, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
 heredoc_read_line:
Packit Service 95ac19
	/* beginning of line */
Packit Service 95ac19
	eofp = eof;
Packit Service 95ac19
	xpos = Xsavepos(xs, xp);
Packit Service 95ac19
	if (iop->ioflag & IOSKIP) {
Packit Service 95ac19
		/* skip over leading tabs */
Packit Service 95ac19
		while ((c = getsc()) == '\t')
Packit Service 95ac19
			;	/* nothing */
Packit Service 95ac19
		goto heredoc_parse_char;
Packit Service 95ac19
	}
Packit Service 95ac19
 heredoc_read_char:
Packit Service 95ac19
	c = getsc();
Packit Service 95ac19
 heredoc_parse_char:
Packit Service 95ac19
	/* compare with here document marker */
Packit Service 95ac19
	if (!*eofp) {
Packit Service 95ac19
		/* end of here document marker, what to do? */
Packit Service 95ac19
		switch (c) {
Packit Service 95ac19
		case ORD(/*(*/ ')'):
Packit Service 95ac19
			if (!subshell_nesting_type)
Packit Service 95ac19
				/*-
Packit Service 95ac19
				 * not allowed outside $(...) or (...)
Packit Service 95ac19
				 * => mismatch
Packit Service 95ac19
				 */
Packit Service 95ac19
				break;
Packit Service 95ac19
			/* allow $(...) or (...) to close here */
Packit Service 95ac19
			ungetsc(/*(*/ ')');
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
		case 0:
Packit Service 95ac19
			/*
Packit Service 95ac19
			 * Allow EOF here to commands without trailing
Packit Service 95ac19
			 * newlines (mksh -c '...') will work as well.
Packit Service 95ac19
			 */
Packit Service 95ac19
		case ORD('\n'):
Packit Service 95ac19
			/* Newline terminates here document marker */
Packit Service 95ac19
			goto heredoc_found_terminator;
Packit Service 95ac19
		}
Packit Service 95ac19
	} else if (c == *eofp++)
Packit Service 95ac19
		/* store; then read and compare next character */
Packit Service 95ac19
		goto heredoc_store_and_loop;
Packit Service 95ac19
	/* nope, mismatch; read until end of line */
Packit Service 95ac19
	while (c != '\n') {
Packit Service 95ac19
		if (!c)
Packit Service 95ac19
			/* oops, reached EOF */
Packit Service 95ac19
			yyerror(Tf_heredoc, eof);
Packit Service 95ac19
		/* store character */
Packit Service 95ac19
		Xcheck(xs, xp);
Packit Service 95ac19
		Xput(xs, xp, c);
Packit Service 95ac19
		/* read next character */
Packit Service 95ac19
		c = getsc();
Packit Service 95ac19
	}
Packit Service 95ac19
	/* we read a newline as last character */
Packit Service 95ac19
 heredoc_store_and_loop:
Packit Service 95ac19
	/* store character */
Packit Service 95ac19
	Xcheck(xs, xp);
Packit Service 95ac19
	Xput(xs, xp, c);
Packit Service 95ac19
	if (c == '\n')
Packit Service 95ac19
		goto heredoc_read_line;
Packit Service 95ac19
	goto heredoc_read_char;
Packit Service 95ac19
Packit Service 95ac19
 heredoc_found_terminator:
Packit Service 95ac19
	/* jump back to saved beginning of line */
Packit Service 95ac19
	xp = Xrestpos(xs, xp, xpos);
Packit Service 95ac19
	/* terminate, close and store */
Packit Service 95ac19
	Xput(xs, xp, '\0');
Packit Service 95ac19
	iop->heredoc = Xclose(xs, xp);
Packit Service 95ac19
Packit Service 95ac19
	if (!(iop->ioflag & IOEVAL))
Packit Service 95ac19
		ignore_backslash_newline--;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
yyerror(const char *fmt, ...)
Packit Service 95ac19
{
Packit Service 95ac19
	va_list va;
Packit Service 95ac19
Packit Service 95ac19
	/* pop aliases and re-reads */
Packit Service 95ac19
	while (source->type == SALIAS || source->type == SREREAD)
Packit Service 95ac19
		source = source->next;
Packit Service 95ac19
	/* zap pending input */
Packit Service 95ac19
	source->str = null;
Packit Service 95ac19
Packit Service 95ac19
	error_prefix(true);
Packit Service 95ac19
	va_start(va, fmt);
Packit Service 95ac19
	shf_vfprintf(shl_out, fmt, va);
Packit Service 95ac19
	shf_putc('\n', shl_out);
Packit Service 95ac19
	va_end(va);
Packit Service 95ac19
	errorfz();
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * input for yylex with alias expansion
Packit Service 95ac19
 */
Packit Service 95ac19
Packit Service 95ac19
Source *
Packit Service 95ac19
pushs(int type, Area *areap)
Packit Service 95ac19
{
Packit Service 95ac19
	Source *s;
Packit Service 95ac19
Packit Service 95ac19
	s = alloc(sizeof(Source), areap);
Packit Service 95ac19
	memset(s, 0, sizeof(Source));
Packit Service 95ac19
	s->type = type;
Packit Service 95ac19
	s->str = null;
Packit Service 95ac19
	s->areap = areap;
Packit Service 95ac19
	if (type == SFILE || type == SSTDIN)
Packit Service 95ac19
		XinitN(s->xs, 256, s->areap);
Packit Service 95ac19
	return (s);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static int
Packit Service 95ac19
getsc_uu(void)
Packit Service 95ac19
{
Packit Service 95ac19
	Source *s = source;
Packit Service 95ac19
	int c;
Packit Service 95ac19
Packit Service 95ac19
	while ((c = ord(*s->str++)) == 0) {
Packit Service 95ac19
		/* return 0 for EOF by default */
Packit Service 95ac19
		s->str = NULL;
Packit Service 95ac19
		switch (s->type) {
Packit Service 95ac19
		case SEOF:
Packit Service 95ac19
			s->str = null;
Packit Service 95ac19
			return (0);
Packit Service 95ac19
Packit Service 95ac19
		case SSTDIN:
Packit Service 95ac19
		case SFILE:
Packit Service 95ac19
			getsc_line(s);
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SWSTR:
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SSTRING:
Packit Service 95ac19
		case SSTRINGCMDLINE:
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SWORDS:
Packit Service 95ac19
			s->start = s->str = *s->u.strv++;
Packit Service 95ac19
			s->type = SWORDSEP;
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SWORDSEP:
Packit Service 95ac19
			if (*s->u.strv == NULL) {
Packit Service 95ac19
				s->start = s->str = "\n";
Packit Service 95ac19
				s->type = SEOF;
Packit Service 95ac19
			} else {
Packit Service 95ac19
				s->start = s->str = T1space;
Packit Service 95ac19
				s->type = SWORDS;
Packit Service 95ac19
			}
Packit Service 95ac19
			break;
Packit Service 95ac19
Packit Service 95ac19
		case SALIAS:
Packit Service 95ac19
			if (s->flags & SF_ALIASEND) {
Packit Service 95ac19
				/* pass on an unused SF_ALIAS flag */
Packit Service 95ac19
				source = s->next;
Packit Service 95ac19
				source->flags |= s->flags & SF_ALIAS;
Packit Service 95ac19
				s = source;
Packit Service 95ac19
			} else if (*s->u.tblp->val.s &&
Packit Service 95ac19
			    ctype((c = strnul(s->u.tblp->val.s)[-1]), C_SPACE)) {
Packit Service 95ac19
				/* pop source stack */
Packit Service 95ac19
				source = s = s->next;
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * Note that this alias ended with a
Packit Service 95ac19
				 * space, enabling alias expansion on
Packit Service 95ac19
				 * the following word.
Packit Service 95ac19
				 */
Packit Service 95ac19
				s->flags |= SF_ALIAS;
Packit Service 95ac19
			} else {
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * At this point, we need to keep the current
Packit Service 95ac19
				 * alias in the source list so recursive
Packit Service 95ac19
				 * aliases can be detected and we also need to
Packit Service 95ac19
				 * return the next character. Do this by
Packit Service 95ac19
				 * temporarily popping the alias to get the
Packit Service 95ac19
				 * next character and then put it back in the
Packit Service 95ac19
				 * source list with the SF_ALIASEND flag set.
Packit Service 95ac19
				 */
Packit Service 95ac19
				/* pop source stack */
Packit Service 95ac19
				source = s->next;
Packit Service 95ac19
				source->flags |= s->flags & SF_ALIAS;
Packit Service 95ac19
				c = getsc_uu();
Packit Service 95ac19
				if (c) {
Packit Service 95ac19
					s->flags |= SF_ALIASEND;
Packit Service 95ac19
					s->ugbuf[0] = c; s->ugbuf[1] = '\0';
Packit Service 95ac19
					s->start = s->str = s->ugbuf;
Packit Service 95ac19
					s->next = source;
Packit Service 95ac19
					source = s;
Packit Service 95ac19
				} else {
Packit Service 95ac19
					s = source;
Packit Service 95ac19
					/* avoid reading EOF twice */
Packit Service 95ac19
					s->str = NULL;
Packit Service 95ac19
					break;
Packit Service 95ac19
				}
Packit Service 95ac19
			}
Packit Service 95ac19
			continue;
Packit Service 95ac19
Packit Service 95ac19
		case SREREAD:
Packit Service 95ac19
			if (s->start != s->ugbuf)
Packit Service 95ac19
				/* yuck */
Packit Service 95ac19
				afree(s->u.freeme, ATEMP);
Packit Service 95ac19
			source = s = s->next;
Packit Service 95ac19
			continue;
Packit Service 95ac19
		}
Packit Service 95ac19
		if (s->str == NULL) {
Packit Service 95ac19
			s->type = SEOF;
Packit Service 95ac19
			s->start = s->str = null;
Packit Service 95ac19
			return ('\0');
Packit Service 95ac19
		}
Packit Service 95ac19
		if (s->flags & SF_ECHO) {
Packit Service 95ac19
			shf_puts(s->str, shl_out);
Packit Service 95ac19
			shf_flush(shl_out);
Packit Service 95ac19
		}
Packit Service 95ac19
	}
Packit Service 95ac19
	return (c);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static void
Packit Service 95ac19
getsc_line(Source *s)
Packit Service 95ac19
{
Packit Service 95ac19
	char *xp = Xstring(s->xs, xp), *cp;
Packit Service 95ac19
	bool interactive = Flag(FTALKING) && s->type == SSTDIN;
Packit Service 95ac19
	bool have_tty = tobool(interactive && (s->flags & SF_TTY));
Packit Service 95ac19
Packit Service 95ac19
	/* Done here to ensure nothing odd happens when a timeout occurs */
Packit Service 95ac19
	XcheckN(s->xs, xp, LINE);
Packit Service 95ac19
	*xp = '\0';
Packit Service 95ac19
	s->start = s->str = xp;
Packit Service 95ac19
Packit Service 95ac19
	if (have_tty && ksh_tmout) {
Packit Service 95ac19
		ksh_tmout_state = TMOUT_READING;
Packit Service 95ac19
		alarm(ksh_tmout);
Packit Service 95ac19
	}
Packit Service 95ac19
	if (interactive) {
Packit Service 95ac19
		if (cur_prompt == PS1)
Packit Service 95ac19
			histsave(&s->line, NULL, HIST_FLUSH, true);
Packit Service 95ac19
		change_winsz();
Packit Service 95ac19
	}
Packit Service 95ac19
#ifndef MKSH_NO_CMDLINE_EDITING
Packit Service 95ac19
	if (have_tty && (
Packit Service 95ac19
#if !MKSH_S_NOVI
Packit Service 95ac19
	    Flag(FVI) ||
Packit Service 95ac19
#endif
Packit Service 95ac19
	    Flag(FEMACS) || Flag(FGMACS))) {
Packit Service 95ac19
		int nread;
Packit Service 95ac19
Packit Service 95ac19
		nread = x_read(xp);
Packit Service 95ac19
		if (nread < 0)
Packit Service 95ac19
			/* read error */
Packit Service 95ac19
			nread = 0;
Packit Service 95ac19
		xp[nread] = '\0';
Packit Service 95ac19
		xp += nread;
Packit Service 95ac19
	} else
Packit Service 95ac19
#endif
Packit Service 95ac19
	  {
Packit Service 95ac19
		if (interactive)
Packit Service 95ac19
			pprompt(prompt, 0);
Packit Service 95ac19
		else
Packit Service 95ac19
			s->line++;
Packit Service 95ac19
Packit Service 95ac19
		while (/* CONSTCOND */ 1) {
Packit Service 95ac19
			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
Packit Service 95ac19
Packit Service 95ac19
			if (!p && shf_error(s->u.shf) &&
Packit Service 95ac19
			    shf_errno(s->u.shf) == EINTR) {
Packit Service 95ac19
				shf_clearerr(s->u.shf);
Packit Service 95ac19
				if (trap)
Packit Service 95ac19
					runtraps(0);
Packit Service 95ac19
				continue;
Packit Service 95ac19
			}
Packit Service 95ac19
			if (!p || (xp = p, xp[-1] == '\n'))
Packit Service 95ac19
				break;
Packit Service 95ac19
			/* double buffer size */
Packit Service 95ac19
			/* move past NUL so doubling works... */
Packit Service 95ac19
			xp++;
Packit Service 95ac19
			XcheckN(s->xs, xp, Xlength(s->xs, xp));
Packit Service 95ac19
			/* ...and move back again */
Packit Service 95ac19
			xp--;
Packit Service 95ac19
		}
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * flush any unwanted input so other programs/builtins
Packit Service 95ac19
		 * can read it. Not very optimal, but less error prone
Packit Service 95ac19
		 * than flushing else where, dealing with redirections,
Packit Service 95ac19
		 * etc.
Packit Service 95ac19
		 * TODO: reduce size of shf buffer (~128?) if SSTDIN
Packit Service 95ac19
		 */
Packit Service 95ac19
		if (s->type == SSTDIN)
Packit Service 95ac19
			shf_flush(s->u.shf);
Packit Service 95ac19
	}
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * XXX: temporary kludge to restore source after a
Packit Service 95ac19
	 * trap may have been executed.
Packit Service 95ac19
	 */
Packit Service 95ac19
	source = s;
Packit Service 95ac19
	if (have_tty && ksh_tmout) {
Packit Service 95ac19
		ksh_tmout_state = TMOUT_EXECUTING;
Packit Service 95ac19
		alarm(0);
Packit Service 95ac19
	}
Packit Service 95ac19
	cp = Xstring(s->xs, xp);
Packit Service 95ac19
	rndpush(cp);
Packit Service 95ac19
	s->start = s->str = cp;
Packit Service 95ac19
	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
Packit Service 95ac19
	/* Note: if input is all nulls, this is not eof */
Packit Service 95ac19
	if (Xlength(s->xs, xp) == 0) {
Packit Service 95ac19
		/* EOF */
Packit Service 95ac19
		if (s->type == SFILE)
Packit Service 95ac19
			shf_fdclose(s->u.shf);
Packit Service 95ac19
		s->str = NULL;
Packit Service 95ac19
	} else if (interactive && *s->str) {
Packit Service 95ac19
		if (cur_prompt != PS1)
Packit Service 95ac19
			histsave(&s->line, s->str, HIST_APPEND, true);
Packit Service 95ac19
		else if (!ctype(*s->str, C_IFS | C_IFSWS))
Packit Service 95ac19
			histsave(&s->line, s->str, HIST_QUEUE, true);
Packit Service 95ac19
#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
Packit Service 95ac19
		else
Packit Service 95ac19
			goto check_for_sole_return;
Packit Service 95ac19
	} else if (interactive && cur_prompt == PS1) {
Packit Service 95ac19
 check_for_sole_return:
Packit Service 95ac19
		cp = Xstring(s->xs, xp);
Packit Service 95ac19
		while (ctype(*cp, C_IFSWS))
Packit Service 95ac19
			++cp;
Packit Service 95ac19
		if (!*cp) {
Packit Service 95ac19
			histsave(&s->line, NULL, HIST_FLUSH, true);
Packit Service 95ac19
			histsync();
Packit Service 95ac19
		}
Packit Service 95ac19
#endif
Packit Service 95ac19
	}
Packit Service 95ac19
	if (interactive)
Packit Service 95ac19
		set_prompt(PS2, NULL);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
set_prompt(int to, Source *s)
Packit Service 95ac19
{
Packit Service 95ac19
	cur_prompt = (uint8_t)to;
Packit Service 95ac19
Packit Service 95ac19
	switch (to) {
Packit Service 95ac19
	/* command */
Packit Service 95ac19
	case PS1:
Packit Service 95ac19
		/*
Packit Service 95ac19
		 * Substitute ! and !! here, before substitutions are done
Packit Service 95ac19
		 * so ! in expanded variables are not expanded.
Packit Service 95ac19
		 * NOTE: this is not what AT&T ksh does (it does it after
Packit Service 95ac19
		 * substitutions, POSIX doesn't say which is to be done.
Packit Service 95ac19
		 */
Packit Service 95ac19
		{
Packit Service 95ac19
			struct shf *shf;
Packit Service 95ac19
			char * volatile ps1;
Packit Service 95ac19
			Area *saved_atemp;
Packit Service 95ac19
			int saved_lineno;
Packit Service 95ac19
Packit Service 95ac19
			ps1 = str_val(global("PS1"));
Packit Service 95ac19
			shf = shf_sopen(NULL, strlen(ps1) * 2,
Packit Service 95ac19
			    SHF_WR | SHF_DYNAMIC, NULL);
Packit Service 95ac19
			while (*ps1)
Packit Service 95ac19
				if (*ps1 != '!' || *++ps1 == '!')
Packit Service 95ac19
					shf_putchar(*ps1++, shf);
Packit Service 95ac19
				else
Packit Service 95ac19
					shf_fprintf(shf, Tf_lu, s ?
Packit Service 95ac19
					    (unsigned long)s->line + 1 : 0UL);
Packit Service 95ac19
			ps1 = shf_sclose(shf);
Packit Service 95ac19
			saved_lineno = current_lineno;
Packit Service 95ac19
			if (s)
Packit Service 95ac19
				current_lineno = s->line + 1;
Packit Service 95ac19
			saved_atemp = ATEMP;
Packit Service 95ac19
			newenv(E_ERRH);
Packit Service 95ac19
			if (kshsetjmp(e->jbuf)) {
Packit Service 95ac19
				prompt = safe_prompt;
Packit Service 95ac19
				/*
Packit Service 95ac19
				 * Don't print an error - assume it has already
Packit Service 95ac19
				 * been printed. Reason is we may have forked
Packit Service 95ac19
				 * to run a command and the child may be
Packit Service 95ac19
				 * unwinding its stack through this code as it
Packit Service 95ac19
				 * exits.
Packit Service 95ac19
				 */
Packit Service 95ac19
			} else {
Packit Service 95ac19
				char *cp = substitute(ps1, 0);
Packit Service 95ac19
				strdupx(prompt, cp, saved_atemp);
Packit Service 95ac19
			}
Packit Service 95ac19
			current_lineno = saved_lineno;
Packit Service 95ac19
			quitenv(NULL);
Packit Service 95ac19
		}
Packit Service 95ac19
		break;
Packit Service 95ac19
	/* command continuation */
Packit Service 95ac19
	case PS2:
Packit Service 95ac19
		prompt = str_val(global("PS2"));
Packit Service 95ac19
		break;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
int
Packit Service 95ac19
pprompt(const char *cp, int ntruncate)
Packit Service 95ac19
{
Packit Service 95ac19
	char delimiter = 0;
Packit Service 95ac19
	bool doprint = (ntruncate != -1);
Packit Service 95ac19
	bool indelimit = false;
Packit Service 95ac19
	int columns = 0, lines = 0;
Packit Service 95ac19
Packit Service 95ac19
	/*
Packit Service 95ac19
	 * Undocumented AT&T ksh feature:
Packit Service 95ac19
	 * If the second char in the prompt string is \r then the first
Packit Service 95ac19
	 * char is taken to be a non-printing delimiter and any chars
Packit Service 95ac19
	 * between two instances of the delimiter are not considered to
Packit Service 95ac19
	 * be part of the prompt length
Packit Service 95ac19
	 */
Packit Service 95ac19
	if (*cp && cp[1] == '\r') {
Packit Service 95ac19
		delimiter = *cp;
Packit Service 95ac19
		cp += 2;
Packit Service 95ac19
	}
Packit Service 95ac19
	for (; *cp; cp++) {
Packit Service 95ac19
		if (indelimit && *cp != delimiter)
Packit Service 95ac19
			;
Packit Service 95ac19
		else if (ctype(*cp, C_CR | C_LF)) {
Packit Service 95ac19
			lines += columns / x_cols + ((*cp == '\n') ? 1 : 0);
Packit Service 95ac19
			columns = 0;
Packit Service 95ac19
		} else if (*cp == '\t') {
Packit Service 95ac19
			columns = (columns | 7) + 1;
Packit Service 95ac19
		} else if (*cp == '\b') {
Packit Service 95ac19
			if (columns > 0)
Packit Service 95ac19
				columns--;
Packit Service 95ac19
		} else if (*cp == delimiter)
Packit Service 95ac19
			indelimit = !indelimit;
Packit Service 95ac19
		else if (UTFMODE && (rtt2asc(*cp) > 0x7F)) {
Packit Service 95ac19
			const char *cp2;
Packit Service 95ac19
			columns += utf_widthadj(cp, &cp2);
Packit Service 95ac19
			if (doprint && (indelimit ||
Packit Service 95ac19
			    (ntruncate < (x_cols * lines + columns))))
Packit Service 95ac19
				shf_write(cp, cp2 - cp, shl_out);
Packit Service 95ac19
			cp = cp2 - /* loop increment */ 1;
Packit Service 95ac19
			continue;
Packit Service 95ac19
		} else
Packit Service 95ac19
			columns++;
Packit Service 95ac19
		if (doprint && (*cp != delimiter) &&
Packit Service 95ac19
		    (indelimit || (ntruncate < (x_cols * lines + columns))))
Packit Service 95ac19
			shf_putc(*cp, shl_out);
Packit Service 95ac19
	}
Packit Service 95ac19
	if (doprint)
Packit Service 95ac19
		shf_flush(shl_out);
Packit Service 95ac19
	return (x_cols * lines + columns);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Read the variable part of a ${...} expression (i.e. up to but not
Packit Service 95ac19
 * including the :[-+?=#%] or close-brace).
Packit Service 95ac19
 */
Packit Service 95ac19
static char *
Packit Service 95ac19
get_brace_var(XString *wsp, char *wp)
Packit Service 95ac19
{
Packit Service 95ac19
	char c;
Packit Service 95ac19
	enum parse_state {
Packit Service 95ac19
		PS_INITIAL, PS_SAW_PERCENT, PS_SAW_HASH, PS_SAW_BANG,
Packit Service 95ac19
		PS_IDENT, PS_NUMBER, PS_VAR1
Packit Service 95ac19
	} state = PS_INITIAL;
Packit Service 95ac19
Packit Service 95ac19
	while (/* CONSTCOND */ 1) {
Packit Service 95ac19
		c = getsc();
Packit Service 95ac19
		/* State machine to figure out where the variable part ends. */
Packit Service 95ac19
		switch (state) {
Packit Service 95ac19
		case PS_SAW_HASH:
Packit Service 95ac19
			if (ctype(c, C_VAR1)) {
Packit Service 95ac19
				char c2;
Packit Service 95ac19
Packit Service 95ac19
				c2 = getsc();
Packit Service 95ac19
				ungetsc(c2);
Packit Service 95ac19
				if (ord(c2) != ORD(/*{*/ '}')) {
Packit Service 95ac19
					ungetsc(c);
Packit Service 95ac19
					goto out;
Packit Service 95ac19
				}
Packit Service 95ac19
			}
Packit Service 95ac19
			goto ps_common;
Packit Service 95ac19
		case PS_SAW_BANG:
Packit Service 95ac19
			switch (ord(c)) {
Packit Service 95ac19
			case ORD('@'):
Packit Service 95ac19
			case ORD('#'):
Packit Service 95ac19
			case ORD('-'):
Packit Service 95ac19
			case ORD('?'):
Packit Service 95ac19
				goto out;
Packit Service 95ac19
			}
Packit Service 95ac19
			goto ps_common;
Packit Service 95ac19
		case PS_INITIAL:
Packit Service 95ac19
			switch (ord(c)) {
Packit Service 95ac19
			case ORD('%'):
Packit Service 95ac19
				state = PS_SAW_PERCENT;
Packit Service 95ac19
				goto next;
Packit Service 95ac19
			case ORD('#'):
Packit Service 95ac19
				state = PS_SAW_HASH;
Packit Service 95ac19
				goto next;
Packit Service 95ac19
			case ORD('!'):
Packit Service 95ac19
				state = PS_SAW_BANG;
Packit Service 95ac19
				goto next;
Packit Service 95ac19
			}
Packit Service 95ac19
			/* FALLTHROUGH */
Packit Service 95ac19
		case PS_SAW_PERCENT:
Packit Service 95ac19
 ps_common:
Packit Service 95ac19
			if (ctype(c, C_ALPHX))
Packit Service 95ac19
				state = PS_IDENT;
Packit Service 95ac19
			else if (ctype(c, C_DIGIT))
Packit Service 95ac19
				state = PS_NUMBER;
Packit Service 95ac19
			else if (ctype(c, C_VAR1))
Packit Service 95ac19
				state = PS_VAR1;
Packit Service 95ac19
			else
Packit Service 95ac19
				goto out;
Packit Service 95ac19
			break;
Packit Service 95ac19
		case PS_IDENT:
Packit Service 95ac19
			if (!ctype(c, C_ALNUX)) {
Packit Service 95ac19
				if (ord(c) == ORD('[')) {
Packit Service 95ac19
					char *tmp, *p;
Packit Service 95ac19
Packit Service 95ac19
					if (!arraysub(&tmp))
Packit Service 95ac19
						yyerror("missing ]");
Packit Service 95ac19
					*wp++ = c;
Packit Service 95ac19
					p = tmp;
Packit Service 95ac19
					while (*p) {
Packit Service 95ac19
						Xcheck(*wsp, wp);
Packit Service 95ac19
						*wp++ = *p++;
Packit Service 95ac19
					}
Packit Service 95ac19
					afree(tmp, ATEMP);
Packit Service 95ac19
					/* the ] */
Packit Service 95ac19
					c = getsc();
Packit Service 95ac19
				}
Packit Service 95ac19
				goto out;
Packit Service 95ac19
			}
Packit Service 95ac19
 next:
Packit Service 95ac19
			break;
Packit Service 95ac19
		case PS_NUMBER:
Packit Service 95ac19
			if (!ctype(c, C_DIGIT))
Packit Service 95ac19
				goto out;
Packit Service 95ac19
			break;
Packit Service 95ac19
		case PS_VAR1:
Packit Service 95ac19
			goto out;
Packit Service 95ac19
		}
Packit Service 95ac19
		Xcheck(*wsp, wp);
Packit Service 95ac19
		*wp++ = c;
Packit Service 95ac19
	}
Packit Service 95ac19
 out:
Packit Service 95ac19
	/* end of variable part */
Packit Service 95ac19
	*wp++ = '\0';
Packit Service 95ac19
	ungetsc(c);
Packit Service 95ac19
	return (wp);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/*
Packit Service 95ac19
 * Save an array subscript - returns true if matching bracket found, false
Packit Service 95ac19
 * if eof or newline was found.
Packit Service 95ac19
 * (Returned string double null terminated)
Packit Service 95ac19
 */
Packit Service 95ac19
static bool
Packit Service 95ac19
arraysub(char **strp)
Packit Service 95ac19
{
Packit Service 95ac19
	XString ws;
Packit Service 95ac19
	char *wp, c;
Packit Service 95ac19
	/* we are just past the initial [ */
Packit Service 95ac19
	unsigned int depth = 1;
Packit Service 95ac19
Packit Service 95ac19
	Xinit(ws, wp, 32, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	do {
Packit Service 95ac19
		c = getsc();
Packit Service 95ac19
		Xcheck(ws, wp);
Packit Service 95ac19
		*wp++ = c;
Packit Service 95ac19
		if (ord(c) == ORD('['))
Packit Service 95ac19
			depth++;
Packit Service 95ac19
		else if (ord(c) == ORD(']'))
Packit Service 95ac19
			depth--;
Packit Service 95ac19
	} while (depth > 0 && c && c != '\n');
Packit Service 95ac19
Packit Service 95ac19
	*wp++ = '\0';
Packit Service 95ac19
	*strp = Xclose(ws, wp);
Packit Service 95ac19
Packit Service 95ac19
	return (tobool(depth == 0));
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
/* Unget a char: handles case when we are already at the start of the buffer */
Packit Service 95ac19
static void
Packit Service 95ac19
ungetsc(int c)
Packit Service 95ac19
{
Packit Service 95ac19
	struct sretrace_info *rp = retrace_info;
Packit Service 95ac19
Packit Service 95ac19
	if (backslash_skip)
Packit Service 95ac19
		backslash_skip--;
Packit Service 95ac19
	/* Don't unget EOF... */
Packit Service 95ac19
	if (source->str == null && c == '\0')
Packit Service 95ac19
		return;
Packit Service 95ac19
	while (rp) {
Packit Service 95ac19
		if (Xlength(rp->xs, rp->xp))
Packit Service 95ac19
			rp->xp--;
Packit Service 95ac19
		rp = rp->next;
Packit Service 95ac19
	}
Packit Service 95ac19
	ungetsc_i(c);
Packit Service 95ac19
}
Packit Service 95ac19
static void
Packit Service 95ac19
ungetsc_i(int c)
Packit Service 95ac19
{
Packit Service 95ac19
	if (source->str > source->start)
Packit Service 95ac19
		source->str--;
Packit Service 95ac19
	else {
Packit Service 95ac19
		Source *s;
Packit Service 95ac19
Packit Service 95ac19
		s = pushs(SREREAD, source->areap);
Packit Service 95ac19
		s->ugbuf[0] = c; s->ugbuf[1] = '\0';
Packit Service 95ac19
		s->start = s->str = s->ugbuf;
Packit Service 95ac19
		s->next = source;
Packit Service 95ac19
		source = s;
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
Packit Service 95ac19
/* Called to get a char that isn't a \newline sequence. */
Packit Service 95ac19
static int
Packit Service 95ac19
getsc_bn(void)
Packit Service 95ac19
{
Packit Service 95ac19
	int c, c2;
Packit Service 95ac19
Packit Service 95ac19
	if (ignore_backslash_newline)
Packit Service 95ac19
		return (o_getsc_u());
Packit Service 95ac19
Packit Service 95ac19
	if (backslash_skip == 1) {
Packit Service 95ac19
		backslash_skip = 2;
Packit Service 95ac19
		return (o_getsc_u());
Packit Service 95ac19
	}
Packit Service 95ac19
Packit Service 95ac19
	backslash_skip = 0;
Packit Service 95ac19
Packit Service 95ac19
	while (/* CONSTCOND */ 1) {
Packit Service 95ac19
		c = o_getsc_u();
Packit Service 95ac19
		if (c == '\\') {
Packit Service 95ac19
			if ((c2 = o_getsc_u()) == '\n')
Packit Service 95ac19
				/* ignore the \newline; get the next char... */
Packit Service 95ac19
				continue;
Packit Service 95ac19
			ungetsc_i(c2);
Packit Service 95ac19
			backslash_skip = 1;
Packit Service 95ac19
		}
Packit Service 95ac19
		return (c);
Packit Service 95ac19
	}
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
void
Packit Service 95ac19
yyskiputf8bom(void)
Packit Service 95ac19
{
Packit Service 95ac19
	int c;
Packit Service 95ac19
Packit Service 95ac19
	if (rtt2asc((c = o_getsc_u())) != 0xEF) {
Packit Service 95ac19
		ungetsc_i(c);
Packit Service 95ac19
		return;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (rtt2asc((c = o_getsc_u())) != 0xBB) {
Packit Service 95ac19
		ungetsc_i(c);
Packit Service 95ac19
		ungetsc_i(asc2rtt(0xEF));
Packit Service 95ac19
		return;
Packit Service 95ac19
	}
Packit Service 95ac19
	if (rtt2asc((c = o_getsc_u())) != 0xBF) {
Packit Service 95ac19
		ungetsc_i(c);
Packit Service 95ac19
		ungetsc_i(asc2rtt(0xBB));
Packit Service 95ac19
		ungetsc_i(asc2rtt(0xEF));
Packit Service 95ac19
		return;
Packit Service 95ac19
	}
Packit Service 95ac19
	UTFMODE |= 8;
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static Lex_state *
Packit Service 95ac19
push_state_i(State_info *si, Lex_state *old_end)
Packit Service 95ac19
{
Packit Service 95ac19
	Lex_state *news = alloc2(STATE_BSIZE, sizeof(Lex_state), ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	news[0].ls_base = old_end;
Packit Service 95ac19
	si->base = &news[0];
Packit Service 95ac19
	si->end = &news[STATE_BSIZE];
Packit Service 95ac19
	return (&news[1]);
Packit Service 95ac19
}
Packit Service 95ac19
Packit Service 95ac19
static Lex_state *
Packit Service 95ac19
pop_state_i(State_info *si, Lex_state *old_end)
Packit Service 95ac19
{
Packit Service 95ac19
	Lex_state *old_base = si->base;
Packit Service 95ac19
Packit Service 95ac19
	si->base = old_end->ls_base - STATE_BSIZE;
Packit Service 95ac19
	si->end = old_end->ls_base;
Packit Service 95ac19
Packit Service 95ac19
	afree(old_base, ATEMP);
Packit Service 95ac19
Packit Service 95ac19
	return (si->base + STATE_BSIZE - 1);
Packit Service 95ac19
}