1c84f3f3cSopenharmony_ci/*	$OpenBSD: lex.c,v 1.51 2015/09/10 22:48:58 nicm Exp $	*/
2c84f3f3cSopenharmony_ci
3c84f3f3cSopenharmony_ci/*-
4c84f3f3cSopenharmony_ci * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5c84f3f3cSopenharmony_ci *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
6c84f3f3cSopenharmony_ci *	mirabilos <m@mirbsd.org>
7c84f3f3cSopenharmony_ci *
8c84f3f3cSopenharmony_ci * Provided that these terms and disclaimer and all copyright notices
9c84f3f3cSopenharmony_ci * are retained or reproduced in an accompanying document, permission
10c84f3f3cSopenharmony_ci * is granted to deal in this work without restriction, including un-
11c84f3f3cSopenharmony_ci * limited rights to use, publicly perform, distribute, sell, modify,
12c84f3f3cSopenharmony_ci * merge, give away, or sublicence.
13c84f3f3cSopenharmony_ci *
14c84f3f3cSopenharmony_ci * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15c84f3f3cSopenharmony_ci * the utmost extent permitted by applicable law, neither express nor
16c84f3f3cSopenharmony_ci * implied; without malicious intent or gross negligence. In no event
17c84f3f3cSopenharmony_ci * may a licensor, author or contributor be held liable for indirect,
18c84f3f3cSopenharmony_ci * direct, other damage, loss, or other issues arising in any way out
19c84f3f3cSopenharmony_ci * of dealing in the work, even if advised of the possibility of such
20c84f3f3cSopenharmony_ci * damage or existence of a defect, except proven that it results out
21c84f3f3cSopenharmony_ci * of said person's immediate fault when using the work as intended.
22c84f3f3cSopenharmony_ci */
23c84f3f3cSopenharmony_ci
24c84f3f3cSopenharmony_ci#include "sh.h"
25c84f3f3cSopenharmony_ci
26c84f3f3cSopenharmony_ci__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.251 2020/03/10 23:48:40 tg Exp $");
27c84f3f3cSopenharmony_ci
28c84f3f3cSopenharmony_ci/*
29c84f3f3cSopenharmony_ci * states while lexing word
30c84f3f3cSopenharmony_ci */
31c84f3f3cSopenharmony_ci#define SBASE		0	/* outside any lexical constructs */
32c84f3f3cSopenharmony_ci#define SWORD		1	/* implicit quoting for substitute() */
33c84f3f3cSopenharmony_ci#define SLETPAREN	2	/* inside (( )), implicit quoting */
34c84f3f3cSopenharmony_ci#define SSQUOTE		3	/* inside '' */
35c84f3f3cSopenharmony_ci#define SDQUOTE		4	/* inside "" */
36c84f3f3cSopenharmony_ci#define SEQUOTE		5	/* inside $'' */
37c84f3f3cSopenharmony_ci#define SBRACE		6	/* inside ${} */
38c84f3f3cSopenharmony_ci#define SQBRACE		7	/* inside "${}" */
39c84f3f3cSopenharmony_ci#define SBQUOTE		8	/* inside `` */
40c84f3f3cSopenharmony_ci#define SASPAREN	9	/* inside $(( )) */
41c84f3f3cSopenharmony_ci#define SHEREDELIM	10	/* parsing << or <<- delimiter */
42c84f3f3cSopenharmony_ci#define SHEREDQUOTE	11	/* parsing " in << or <<- delimiter */
43c84f3f3cSopenharmony_ci#define SPATTERN	12	/* parsing *(...|...) pattern (*+?@!) */
44c84f3f3cSopenharmony_ci#define SADELIM		13	/* like SBASE, looking for delimiter */
45c84f3f3cSopenharmony_ci#define STBRACEKORN	14	/* parsing ${...[#%]...} !FSH */
46c84f3f3cSopenharmony_ci#define STBRACEBOURNE	15	/* parsing ${...[#%]...} FSH */
47c84f3f3cSopenharmony_ci#define SINVALID	255	/* invalid state */
48c84f3f3cSopenharmony_ci
49c84f3f3cSopenharmony_cistruct sretrace_info {
50c84f3f3cSopenharmony_ci	struct sretrace_info *next;
51c84f3f3cSopenharmony_ci	XString xs;
52c84f3f3cSopenharmony_ci	char *xp;
53c84f3f3cSopenharmony_ci};
54c84f3f3cSopenharmony_ci
55c84f3f3cSopenharmony_ci/*
56c84f3f3cSopenharmony_ci * Structure to keep track of the lexing state and the various pieces of info
57c84f3f3cSopenharmony_ci * needed for each particular state.
58c84f3f3cSopenharmony_ci */
59c84f3f3cSopenharmony_citypedef struct lex_state {
60c84f3f3cSopenharmony_ci	union {
61c84f3f3cSopenharmony_ci		/* point to the next state block */
62c84f3f3cSopenharmony_ci		struct lex_state *base;
63c84f3f3cSopenharmony_ci		/* marks start of state output in output string */
64c84f3f3cSopenharmony_ci		size_t start;
65c84f3f3cSopenharmony_ci		/* SBQUOTE: true if in double quotes: "`...`" */
66c84f3f3cSopenharmony_ci		/* SEQUOTE: got NUL, ignore rest of string */
67c84f3f3cSopenharmony_ci		bool abool;
68c84f3f3cSopenharmony_ci		/* SADELIM information */
69c84f3f3cSopenharmony_ci		struct {
70c84f3f3cSopenharmony_ci			/* character to search for */
71c84f3f3cSopenharmony_ci			unsigned char delimiter;
72c84f3f3cSopenharmony_ci			/* max. number of delimiters */
73c84f3f3cSopenharmony_ci			unsigned char num;
74c84f3f3cSopenharmony_ci		} adelim;
75c84f3f3cSopenharmony_ci	} u;
76c84f3f3cSopenharmony_ci	/* count open parentheses */
77c84f3f3cSopenharmony_ci	short nparen;
78c84f3f3cSopenharmony_ci	/* type of this state */
79c84f3f3cSopenharmony_ci	uint8_t type;
80c84f3f3cSopenharmony_ci	/* extra flags */
81c84f3f3cSopenharmony_ci	uint8_t ls_flags;
82c84f3f3cSopenharmony_ci} Lex_state;
83c84f3f3cSopenharmony_ci#define ls_base		u.base
84c84f3f3cSopenharmony_ci#define ls_start	u.start
85c84f3f3cSopenharmony_ci#define ls_bool		u.abool
86c84f3f3cSopenharmony_ci#define ls_adelim	u.adelim
87c84f3f3cSopenharmony_ci
88c84f3f3cSopenharmony_ci/* ls_flags */
89c84f3f3cSopenharmony_ci#define LS_HEREDOC	BIT(0)
90c84f3f3cSopenharmony_ci
91c84f3f3cSopenharmony_citypedef struct {
92c84f3f3cSopenharmony_ci	Lex_state *base;
93c84f3f3cSopenharmony_ci	Lex_state *end;
94c84f3f3cSopenharmony_ci} State_info;
95c84f3f3cSopenharmony_ci
96c84f3f3cSopenharmony_cistatic void readhere(struct ioword *);
97c84f3f3cSopenharmony_cistatic void ungetsc(int);
98c84f3f3cSopenharmony_cistatic void ungetsc_i(int);
99c84f3f3cSopenharmony_cistatic int getsc_uu(void);
100c84f3f3cSopenharmony_cistatic void getsc_line(Source *);
101c84f3f3cSopenharmony_cistatic int getsc_bn(void);
102c84f3f3cSopenharmony_cistatic int getsc_i(void);
103c84f3f3cSopenharmony_cistatic char *get_brace_var(XString *, char *);
104c84f3f3cSopenharmony_cistatic bool arraysub(char **);
105c84f3f3cSopenharmony_cistatic void gethere(void);
106c84f3f3cSopenharmony_cistatic Lex_state *push_state_i(State_info *, Lex_state *);
107c84f3f3cSopenharmony_cistatic Lex_state *pop_state_i(State_info *, Lex_state *);
108c84f3f3cSopenharmony_ci
109c84f3f3cSopenharmony_cistatic int backslash_skip;
110c84f3f3cSopenharmony_cistatic int ignore_backslash_newline;
111c84f3f3cSopenharmony_ci
112c84f3f3cSopenharmony_ci/* optimised getsc_bn() */
113c84f3f3cSopenharmony_ci#define o_getsc()	(*source->str != '\0' && *source->str != '\\' && \
114c84f3f3cSopenharmony_ci			    !backslash_skip ? *source->str++ : getsc_bn())
115c84f3f3cSopenharmony_ci/* optimised getsc_uu() */
116c84f3f3cSopenharmony_ci#define	o_getsc_u()	((*source->str != '\0') ? *source->str++ : getsc_uu())
117c84f3f3cSopenharmony_ci
118c84f3f3cSopenharmony_ci/* retrace helper */
119c84f3f3cSopenharmony_ci#define o_getsc_r(carg)					\
120c84f3f3cSopenharmony_ci	int cev = (carg);				\
121c84f3f3cSopenharmony_ci	struct sretrace_info *rp = retrace_info;	\
122c84f3f3cSopenharmony_ci							\
123c84f3f3cSopenharmony_ci	while (rp) {					\
124c84f3f3cSopenharmony_ci		Xcheck(rp->xs, rp->xp);			\
125c84f3f3cSopenharmony_ci		*rp->xp++ = cev;			\
126c84f3f3cSopenharmony_ci		rp = rp->next;				\
127c84f3f3cSopenharmony_ci	}						\
128c84f3f3cSopenharmony_ci							\
129c84f3f3cSopenharmony_ci	return (cev);
130c84f3f3cSopenharmony_ci
131c84f3f3cSopenharmony_ci/* callback */
132c84f3f3cSopenharmony_cistatic int
133c84f3f3cSopenharmony_cigetsc_i(void)
134c84f3f3cSopenharmony_ci{
135c84f3f3cSopenharmony_ci	o_getsc_r((unsigned int)(unsigned char)o_getsc());
136c84f3f3cSopenharmony_ci}
137c84f3f3cSopenharmony_ci
138c84f3f3cSopenharmony_ci#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
139c84f3f3cSopenharmony_ci#define getsc()		getsc_i()
140c84f3f3cSopenharmony_ci#else
141c84f3f3cSopenharmony_cistatic int getsc_r(int);
142c84f3f3cSopenharmony_ci
143c84f3f3cSopenharmony_cistatic int
144c84f3f3cSopenharmony_cigetsc_r(int c)
145c84f3f3cSopenharmony_ci{
146c84f3f3cSopenharmony_ci	o_getsc_r(c);
147c84f3f3cSopenharmony_ci}
148c84f3f3cSopenharmony_ci
149c84f3f3cSopenharmony_ci#define getsc()		getsc_r((unsigned int)(unsigned char)o_getsc())
150c84f3f3cSopenharmony_ci#endif
151c84f3f3cSopenharmony_ci
152c84f3f3cSopenharmony_ci#define STATE_BSIZE	8
153c84f3f3cSopenharmony_ci
154c84f3f3cSopenharmony_ci#define PUSH_STATE(s)	do {					\
155c84f3f3cSopenharmony_ci	uint8_t state_flags = statep->ls_flags;			\
156c84f3f3cSopenharmony_ci	if (++statep == state_info.end)				\
157c84f3f3cSopenharmony_ci		statep = push_state_i(&state_info, statep);	\
158c84f3f3cSopenharmony_ci	state = statep->type = (s);				\
159c84f3f3cSopenharmony_ci	statep->ls_flags = state_flags;				\
160c84f3f3cSopenharmony_ci} while (/* CONSTCOND */ 0)
161c84f3f3cSopenharmony_ci
162c84f3f3cSopenharmony_ci#define POP_STATE()	do {					\
163c84f3f3cSopenharmony_ci	if (--statep == state_info.base)			\
164c84f3f3cSopenharmony_ci		statep = pop_state_i(&state_info, statep);	\
165c84f3f3cSopenharmony_ci	state = statep->type;					\
166c84f3f3cSopenharmony_ci} while (/* CONSTCOND */ 0)
167c84f3f3cSopenharmony_ci
168c84f3f3cSopenharmony_ci#define PUSH_SRETRACE(s) do {					\
169c84f3f3cSopenharmony_ci	struct sretrace_info *ri;				\
170c84f3f3cSopenharmony_ci								\
171c84f3f3cSopenharmony_ci	PUSH_STATE(s);						\
172c84f3f3cSopenharmony_ci	statep->ls_start = Xsavepos(ws, wp);			\
173c84f3f3cSopenharmony_ci	ri = alloc(sizeof(struct sretrace_info), ATEMP);	\
174c84f3f3cSopenharmony_ci	Xinit(ri->xs, ri->xp, 64, ATEMP);			\
175c84f3f3cSopenharmony_ci	ri->next = retrace_info;				\
176c84f3f3cSopenharmony_ci	retrace_info = ri;					\
177c84f3f3cSopenharmony_ci} while (/* CONSTCOND */ 0)
178c84f3f3cSopenharmony_ci
179c84f3f3cSopenharmony_ci#define POP_SRETRACE()	do {					\
180c84f3f3cSopenharmony_ci	wp = Xrestpos(ws, wp, statep->ls_start);		\
181c84f3f3cSopenharmony_ci	*retrace_info->xp = '\0';				\
182c84f3f3cSopenharmony_ci	sp = Xstring(retrace_info->xs, retrace_info->xp);	\
183c84f3f3cSopenharmony_ci	dp = (void *)retrace_info;				\
184c84f3f3cSopenharmony_ci	retrace_info = retrace_info->next;			\
185c84f3f3cSopenharmony_ci	afree(dp, ATEMP);					\
186c84f3f3cSopenharmony_ci	POP_STATE();						\
187c84f3f3cSopenharmony_ci} while (/* CONSTCOND */ 0)
188c84f3f3cSopenharmony_ci
189c84f3f3cSopenharmony_ci/**
190c84f3f3cSopenharmony_ci * Lexical analyser
191c84f3f3cSopenharmony_ci *
192c84f3f3cSopenharmony_ci * tokens are not regular expressions, they are LL(1).
193c84f3f3cSopenharmony_ci * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
194c84f3f3cSopenharmony_ci * hence the state stack. Note "$(...)" are now parsed recursively.
195c84f3f3cSopenharmony_ci */
196c84f3f3cSopenharmony_ci
197c84f3f3cSopenharmony_ciint
198c84f3f3cSopenharmony_ciyylex(int cf)
199c84f3f3cSopenharmony_ci{
200c84f3f3cSopenharmony_ci	Lex_state states[STATE_BSIZE], *statep, *s2, *base;
201c84f3f3cSopenharmony_ci	State_info state_info;
202c84f3f3cSopenharmony_ci	int c, c2, state;
203c84f3f3cSopenharmony_ci	size_t cz;
204c84f3f3cSopenharmony_ci	XString ws;		/* expandable output word */
205c84f3f3cSopenharmony_ci	char *wp;		/* output word pointer */
206c84f3f3cSopenharmony_ci	char *sp, *dp;
207c84f3f3cSopenharmony_ci
208c84f3f3cSopenharmony_ci Again:
209c84f3f3cSopenharmony_ci	states[0].type = SINVALID;
210c84f3f3cSopenharmony_ci	states[0].ls_base = NULL;
211c84f3f3cSopenharmony_ci	statep = &states[1];
212c84f3f3cSopenharmony_ci	state_info.base = states;
213c84f3f3cSopenharmony_ci	state_info.end = &state_info.base[STATE_BSIZE];
214c84f3f3cSopenharmony_ci
215c84f3f3cSopenharmony_ci	Xinit(ws, wp, 64, ATEMP);
216c84f3f3cSopenharmony_ci
217c84f3f3cSopenharmony_ci	backslash_skip = 0;
218c84f3f3cSopenharmony_ci	ignore_backslash_newline = 0;
219c84f3f3cSopenharmony_ci
220c84f3f3cSopenharmony_ci	if (cf & ONEWORD)
221c84f3f3cSopenharmony_ci		state = SWORD;
222c84f3f3cSopenharmony_ci	else if (cf & LETEXPR) {
223c84f3f3cSopenharmony_ci		/* enclose arguments in (double) quotes */
224c84f3f3cSopenharmony_ci		*wp++ = OQUOTE;
225c84f3f3cSopenharmony_ci		state = SLETPAREN;
226c84f3f3cSopenharmony_ci		statep->nparen = 0;
227c84f3f3cSopenharmony_ci	} else {
228c84f3f3cSopenharmony_ci		/* normal lexing */
229c84f3f3cSopenharmony_ci		state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
230c84f3f3cSopenharmony_ci		do {
231c84f3f3cSopenharmony_ci			c = getsc();
232c84f3f3cSopenharmony_ci		} while (ctype(c, C_BLANK));
233c84f3f3cSopenharmony_ci		if (c == '#') {
234c84f3f3cSopenharmony_ci			ignore_backslash_newline++;
235c84f3f3cSopenharmony_ci			do {
236c84f3f3cSopenharmony_ci				c = getsc();
237c84f3f3cSopenharmony_ci			} while (!ctype(c, C_NUL | C_LF));
238c84f3f3cSopenharmony_ci			ignore_backslash_newline--;
239c84f3f3cSopenharmony_ci		}
240c84f3f3cSopenharmony_ci		ungetsc(c);
241c84f3f3cSopenharmony_ci	}
242c84f3f3cSopenharmony_ci	if (source->flags & SF_ALIAS) {
243c84f3f3cSopenharmony_ci		/* trailing ' ' in alias definition */
244c84f3f3cSopenharmony_ci		source->flags &= ~SF_ALIAS;
245c84f3f3cSopenharmony_ci		/* POSIX: trailing space only counts if parsing simple cmd */
246c84f3f3cSopenharmony_ci		if (!Flag(FPOSIX) || (cf & CMDWORD))
247c84f3f3cSopenharmony_ci			cf |= ALIAS;
248c84f3f3cSopenharmony_ci	}
249c84f3f3cSopenharmony_ci
250c84f3f3cSopenharmony_ci	/* Initial state: one of SWORD SLETPAREN SHEREDELIM SBASE */
251c84f3f3cSopenharmony_ci	statep->type = state;
252c84f3f3cSopenharmony_ci	statep->ls_flags = (cf & HEREDOC) ? LS_HEREDOC : 0;
253c84f3f3cSopenharmony_ci
254c84f3f3cSopenharmony_ci	/* collect non-special or quoted characters to form word */
255c84f3f3cSopenharmony_ci	while (!((c = getsc()) == 0 ||
256c84f3f3cSopenharmony_ci	    ((state == SBASE || state == SHEREDELIM) && ctype(c, C_LEX1)))) {
257c84f3f3cSopenharmony_ci		if (state == SBASE &&
258c84f3f3cSopenharmony_ci		    subshell_nesting_type == ORD(/*{*/ '}') &&
259c84f3f3cSopenharmony_ci		    (unsigned int)c == ORD(/*{*/ '}'))
260c84f3f3cSopenharmony_ci			/* possibly end ${ :;} */
261c84f3f3cSopenharmony_ci			break;
262c84f3f3cSopenharmony_ci		Xcheck(ws, wp);
263c84f3f3cSopenharmony_ci		switch (state) {
264c84f3f3cSopenharmony_ci		case SADELIM:
265c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('('))
266c84f3f3cSopenharmony_ci				statep->nparen++;
267c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD(')'))
268c84f3f3cSopenharmony_ci				statep->nparen--;
269c84f3f3cSopenharmony_ci			else if (statep->nparen == 0 &&
270c84f3f3cSopenharmony_ci			    ((unsigned int)c == ORD(/*{*/ '}') ||
271c84f3f3cSopenharmony_ci			    c == (int)statep->ls_adelim.delimiter)) {
272c84f3f3cSopenharmony_ci				*wp++ = ADELIM;
273c84f3f3cSopenharmony_ci				*wp++ = c;
274c84f3f3cSopenharmony_ci				if ((unsigned int)c == ORD(/*{*/ '}') ||
275c84f3f3cSopenharmony_ci				    --statep->ls_adelim.num == 0)
276c84f3f3cSopenharmony_ci					POP_STATE();
277c84f3f3cSopenharmony_ci				if ((unsigned int)c == ORD(/*{*/ '}'))
278c84f3f3cSopenharmony_ci					POP_STATE();
279c84f3f3cSopenharmony_ci				break;
280c84f3f3cSopenharmony_ci			}
281c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
282c84f3f3cSopenharmony_ci		case SBASE:
283c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('[') && (cf & CMDASN)) {
284c84f3f3cSopenharmony_ci				/* temporary */
285c84f3f3cSopenharmony_ci				*wp = EOS;
286c84f3f3cSopenharmony_ci				if (is_wdvarname(Xstring(ws, wp), false)) {
287c84f3f3cSopenharmony_ci					char *p, *tmp;
288c84f3f3cSopenharmony_ci
289c84f3f3cSopenharmony_ci					if (arraysub(&tmp)) {
290c84f3f3cSopenharmony_ci						*wp++ = CHAR;
291c84f3f3cSopenharmony_ci						*wp++ = c;
292c84f3f3cSopenharmony_ci						for (p = tmp; *p; ) {
293c84f3f3cSopenharmony_ci							Xcheck(ws, wp);
294c84f3f3cSopenharmony_ci							*wp++ = CHAR;
295c84f3f3cSopenharmony_ci							*wp++ = *p++;
296c84f3f3cSopenharmony_ci						}
297c84f3f3cSopenharmony_ci						afree(tmp, ATEMP);
298c84f3f3cSopenharmony_ci						break;
299c84f3f3cSopenharmony_ci					}
300c84f3f3cSopenharmony_ci				}
301c84f3f3cSopenharmony_ci				*wp++ = CHAR;
302c84f3f3cSopenharmony_ci				*wp++ = c;
303c84f3f3cSopenharmony_ci				break;
304c84f3f3cSopenharmony_ci			}
305c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
306c84f3f3cSopenharmony_ci Sbase1:		/* includes *(...|...) pattern (*+?@!) */
307c84f3f3cSopenharmony_ci			if (ctype(c, C_PATMO)) {
308c84f3f3cSopenharmony_ci				c2 = getsc();
309c84f3f3cSopenharmony_ci				if ((unsigned int)c2 == ORD('(' /*)*/)) {
310c84f3f3cSopenharmony_ci					*wp++ = OPAT;
311c84f3f3cSopenharmony_ci					*wp++ = c;
312c84f3f3cSopenharmony_ci					PUSH_STATE(SPATTERN);
313c84f3f3cSopenharmony_ci					break;
314c84f3f3cSopenharmony_ci				}
315c84f3f3cSopenharmony_ci				ungetsc(c2);
316c84f3f3cSopenharmony_ci			}
317c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
318c84f3f3cSopenharmony_ci Sbase2:		/* doesn't include *(...|...) pattern (*+?@!) */
319c84f3f3cSopenharmony_ci			switch (c) {
320c84f3f3cSopenharmony_ci			case ORD('\\'):
321c84f3f3cSopenharmony_ci getsc_qchar:
322c84f3f3cSopenharmony_ci				if ((c = getsc())) {
323c84f3f3cSopenharmony_ci					/* trailing \ is lost */
324c84f3f3cSopenharmony_ci					*wp++ = QCHAR;
325c84f3f3cSopenharmony_ci					*wp++ = c;
326c84f3f3cSopenharmony_ci				}
327c84f3f3cSopenharmony_ci				break;
328c84f3f3cSopenharmony_ci			case ORD('\''):
329c84f3f3cSopenharmony_ci open_ssquote_unless_heredoc:
330c84f3f3cSopenharmony_ci				if ((statep->ls_flags & LS_HEREDOC))
331c84f3f3cSopenharmony_ci					goto store_char;
332c84f3f3cSopenharmony_ci				*wp++ = OQUOTE;
333c84f3f3cSopenharmony_ci				ignore_backslash_newline++;
334c84f3f3cSopenharmony_ci				PUSH_STATE(SSQUOTE);
335c84f3f3cSopenharmony_ci				break;
336c84f3f3cSopenharmony_ci			case ORD('"'):
337c84f3f3cSopenharmony_ci open_sdquote:
338c84f3f3cSopenharmony_ci				*wp++ = OQUOTE;
339c84f3f3cSopenharmony_ci				PUSH_STATE(SDQUOTE);
340c84f3f3cSopenharmony_ci				break;
341c84f3f3cSopenharmony_ci			case ORD('$'):
342c84f3f3cSopenharmony_ci				/*
343c84f3f3cSopenharmony_ci				 * processing of dollar sign belongs into
344c84f3f3cSopenharmony_ci				 * Subst, except for those which can open
345c84f3f3cSopenharmony_ci				 * a string: $'…' and $"…"
346c84f3f3cSopenharmony_ci				 */
347c84f3f3cSopenharmony_ci subst_dollar_ex:
348c84f3f3cSopenharmony_ci				c = getsc();
349c84f3f3cSopenharmony_ci				switch (c) {
350c84f3f3cSopenharmony_ci				case ORD('"'):
351c84f3f3cSopenharmony_ci					goto open_sdquote;
352c84f3f3cSopenharmony_ci				case ORD('\''):
353c84f3f3cSopenharmony_ci					goto open_sequote;
354c84f3f3cSopenharmony_ci				default:
355c84f3f3cSopenharmony_ci					goto SubstS;
356c84f3f3cSopenharmony_ci				}
357c84f3f3cSopenharmony_ci			default:
358c84f3f3cSopenharmony_ci				goto Subst;
359c84f3f3cSopenharmony_ci			}
360c84f3f3cSopenharmony_ci			break;
361c84f3f3cSopenharmony_ci
362c84f3f3cSopenharmony_ci Subst:
363c84f3f3cSopenharmony_ci			switch (c) {
364c84f3f3cSopenharmony_ci			case ORD('\\'):
365c84f3f3cSopenharmony_ci				c = getsc();
366c84f3f3cSopenharmony_ci				switch (c) {
367c84f3f3cSopenharmony_ci				case ORD('"'):
368c84f3f3cSopenharmony_ci					if ((statep->ls_flags & LS_HEREDOC))
369c84f3f3cSopenharmony_ci						goto heredocquote;
370c84f3f3cSopenharmony_ci					/* FALLTHROUGH */
371c84f3f3cSopenharmony_ci				case ORD('\\'):
372c84f3f3cSopenharmony_ci				case ORD('$'):
373c84f3f3cSopenharmony_ci				case ORD('`'):
374c84f3f3cSopenharmony_ci store_qchar:
375c84f3f3cSopenharmony_ci					*wp++ = QCHAR;
376c84f3f3cSopenharmony_ci					*wp++ = c;
377c84f3f3cSopenharmony_ci					break;
378c84f3f3cSopenharmony_ci				default:
379c84f3f3cSopenharmony_ci heredocquote:
380c84f3f3cSopenharmony_ci					Xcheck(ws, wp);
381c84f3f3cSopenharmony_ci					if (c) {
382c84f3f3cSopenharmony_ci						/* trailing \ is lost */
383c84f3f3cSopenharmony_ci						*wp++ = CHAR;
384c84f3f3cSopenharmony_ci						*wp++ = '\\';
385c84f3f3cSopenharmony_ci						*wp++ = CHAR;
386c84f3f3cSopenharmony_ci						*wp++ = c;
387c84f3f3cSopenharmony_ci					}
388c84f3f3cSopenharmony_ci					break;
389c84f3f3cSopenharmony_ci				}
390c84f3f3cSopenharmony_ci				break;
391c84f3f3cSopenharmony_ci			case ORD('$'):
392c84f3f3cSopenharmony_ci				c = getsc();
393c84f3f3cSopenharmony_ci SubstS:
394c84f3f3cSopenharmony_ci				if ((unsigned int)c == ORD('(' /*)*/)) {
395c84f3f3cSopenharmony_ci					c = getsc();
396c84f3f3cSopenharmony_ci					if ((unsigned int)c == ORD('(' /*)*/)) {
397c84f3f3cSopenharmony_ci						*wp++ = EXPRSUB;
398c84f3f3cSopenharmony_ci						PUSH_SRETRACE(SASPAREN);
399c84f3f3cSopenharmony_ci						/* unneeded? */
400c84f3f3cSopenharmony_ci						/*statep->ls_flags &= ~LS_HEREDOC;*/
401c84f3f3cSopenharmony_ci						statep->nparen = 2;
402c84f3f3cSopenharmony_ci						*retrace_info->xp++ = '(';
403c84f3f3cSopenharmony_ci					} else {
404c84f3f3cSopenharmony_ci						ungetsc(c);
405c84f3f3cSopenharmony_ci subst_command:
406c84f3f3cSopenharmony_ci						c = COMSUB;
407c84f3f3cSopenharmony_ci subst_command2:
408c84f3f3cSopenharmony_ci						sp = yyrecursive(c);
409c84f3f3cSopenharmony_ci						cz = strlen(sp) + 1;
410c84f3f3cSopenharmony_ci						XcheckN(ws, wp, cz);
411c84f3f3cSopenharmony_ci						*wp++ = c;
412c84f3f3cSopenharmony_ci						memcpy(wp, sp, cz);
413c84f3f3cSopenharmony_ci						wp += cz;
414c84f3f3cSopenharmony_ci					}
415c84f3f3cSopenharmony_ci				} else if ((unsigned int)c == ORD('{' /*}*/)) {
416c84f3f3cSopenharmony_ci					if ((unsigned int)(c = getsc()) == ORD('|')) {
417c84f3f3cSopenharmony_ci						/*
418c84f3f3cSopenharmony_ci						 * non-subenvironment
419c84f3f3cSopenharmony_ci						 * value substitution
420c84f3f3cSopenharmony_ci						 */
421c84f3f3cSopenharmony_ci						c = VALSUB;
422c84f3f3cSopenharmony_ci						goto subst_command2;
423c84f3f3cSopenharmony_ci					} else if (ctype(c, C_IFSWS)) {
424c84f3f3cSopenharmony_ci						/*
425c84f3f3cSopenharmony_ci						 * non-subenvironment
426c84f3f3cSopenharmony_ci						 * "command" substitution
427c84f3f3cSopenharmony_ci						 */
428c84f3f3cSopenharmony_ci						c = FUNSUB;
429c84f3f3cSopenharmony_ci						goto subst_command2;
430c84f3f3cSopenharmony_ci					}
431c84f3f3cSopenharmony_ci					ungetsc(c);
432c84f3f3cSopenharmony_ci					*wp++ = OSUBST;
433c84f3f3cSopenharmony_ci					*wp++ = '{' /*}*/;
434c84f3f3cSopenharmony_ci					wp = get_brace_var(&ws, wp);
435c84f3f3cSopenharmony_ci					c = getsc();
436c84f3f3cSopenharmony_ci					/* allow :# and :% (ksh88 compat) */
437c84f3f3cSopenharmony_ci					if ((unsigned int)c == ORD(':')) {
438c84f3f3cSopenharmony_ci						*wp++ = CHAR;
439c84f3f3cSopenharmony_ci						*wp++ = c;
440c84f3f3cSopenharmony_ci						c = getsc();
441c84f3f3cSopenharmony_ci						if ((unsigned int)c == ORD(':')) {
442c84f3f3cSopenharmony_ci							*wp++ = CHAR;
443c84f3f3cSopenharmony_ci							*wp++ = '0';
444c84f3f3cSopenharmony_ci							*wp++ = ADELIM;
445c84f3f3cSopenharmony_ci							*wp++ = ':';
446c84f3f3cSopenharmony_ci							PUSH_STATE(SBRACE);
447c84f3f3cSopenharmony_ci							/* perhaps unneeded? */
448c84f3f3cSopenharmony_ci							statep->ls_flags &= ~LS_HEREDOC;
449c84f3f3cSopenharmony_ci							PUSH_STATE(SADELIM);
450c84f3f3cSopenharmony_ci							statep->ls_adelim.delimiter = ':';
451c84f3f3cSopenharmony_ci							statep->ls_adelim.num = 1;
452c84f3f3cSopenharmony_ci							statep->nparen = 0;
453c84f3f3cSopenharmony_ci							break;
454c84f3f3cSopenharmony_ci						} else if (ctype(c, C_ALNUX | C_DOLAR | C_SPC) ||
455c84f3f3cSopenharmony_ci						    c == '(' /*)*/) {
456c84f3f3cSopenharmony_ci							/* substring subst. */
457c84f3f3cSopenharmony_ci							if (c != ' ') {
458c84f3f3cSopenharmony_ci								*wp++ = CHAR;
459c84f3f3cSopenharmony_ci								*wp++ = ' ';
460c84f3f3cSopenharmony_ci							}
461c84f3f3cSopenharmony_ci							ungetsc(c);
462c84f3f3cSopenharmony_ci							PUSH_STATE(SBRACE);
463c84f3f3cSopenharmony_ci							/* perhaps unneeded? */
464c84f3f3cSopenharmony_ci							statep->ls_flags &= ~LS_HEREDOC;
465c84f3f3cSopenharmony_ci							PUSH_STATE(SADELIM);
466c84f3f3cSopenharmony_ci							statep->ls_adelim.delimiter = ':';
467c84f3f3cSopenharmony_ci							statep->ls_adelim.num = 2;
468c84f3f3cSopenharmony_ci							statep->nparen = 0;
469c84f3f3cSopenharmony_ci							break;
470c84f3f3cSopenharmony_ci						}
471c84f3f3cSopenharmony_ci					} else if (c == '/') {
472c84f3f3cSopenharmony_ci						c2 = ADELIM;
473c84f3f3cSopenharmony_ci parse_adelim_slash:
474c84f3f3cSopenharmony_ci						*wp++ = CHAR;
475c84f3f3cSopenharmony_ci						*wp++ = c;
476c84f3f3cSopenharmony_ci						if ((unsigned int)(c = getsc()) == ORD('/')) {
477c84f3f3cSopenharmony_ci							*wp++ = c2;
478c84f3f3cSopenharmony_ci							*wp++ = c;
479c84f3f3cSopenharmony_ci						} else
480c84f3f3cSopenharmony_ci							ungetsc(c);
481c84f3f3cSopenharmony_ci						PUSH_STATE(SBRACE);
482c84f3f3cSopenharmony_ci						/* perhaps unneeded? */
483c84f3f3cSopenharmony_ci						statep->ls_flags &= ~LS_HEREDOC;
484c84f3f3cSopenharmony_ci						PUSH_STATE(SADELIM);
485c84f3f3cSopenharmony_ci						statep->ls_adelim.delimiter = '/';
486c84f3f3cSopenharmony_ci						statep->ls_adelim.num = 1;
487c84f3f3cSopenharmony_ci						statep->nparen = 0;
488c84f3f3cSopenharmony_ci						break;
489c84f3f3cSopenharmony_ci					} else if (c == '@') {
490c84f3f3cSopenharmony_ci						c2 = getsc();
491c84f3f3cSopenharmony_ci						ungetsc(c2);
492c84f3f3cSopenharmony_ci						if ((unsigned int)c2 == ORD('/')) {
493c84f3f3cSopenharmony_ci							c2 = CHAR;
494c84f3f3cSopenharmony_ci							goto parse_adelim_slash;
495c84f3f3cSopenharmony_ci						}
496c84f3f3cSopenharmony_ci					}
497c84f3f3cSopenharmony_ci					/*
498c84f3f3cSopenharmony_ci					 * If this is a trim operation,
499c84f3f3cSopenharmony_ci					 * treat (,|,) specially in STBRACE.
500c84f3f3cSopenharmony_ci					 */
501c84f3f3cSopenharmony_ci					if (ctype(c, C_SUB2)) {
502c84f3f3cSopenharmony_ci						ungetsc(c);
503c84f3f3cSopenharmony_ci						if (Flag(FSH))
504c84f3f3cSopenharmony_ci							PUSH_STATE(STBRACEBOURNE);
505c84f3f3cSopenharmony_ci						else
506c84f3f3cSopenharmony_ci							PUSH_STATE(STBRACEKORN);
507c84f3f3cSopenharmony_ci						/* single-quotes-in-heredoc-trim */
508c84f3f3cSopenharmony_ci						statep->ls_flags &= ~LS_HEREDOC;
509c84f3f3cSopenharmony_ci					} else {
510c84f3f3cSopenharmony_ci						ungetsc(c);
511c84f3f3cSopenharmony_ci						if (state == SDQUOTE ||
512c84f3f3cSopenharmony_ci						    state == SQBRACE)
513c84f3f3cSopenharmony_ci							PUSH_STATE(SQBRACE);
514c84f3f3cSopenharmony_ci						else
515c84f3f3cSopenharmony_ci							PUSH_STATE(SBRACE);
516c84f3f3cSopenharmony_ci						/* here no LS_HEREDOC removal */
517c84f3f3cSopenharmony_ci						/* single-quotes-in-heredoc-braces */
518c84f3f3cSopenharmony_ci					}
519c84f3f3cSopenharmony_ci				} else if (ctype(c, C_ALPHX)) {
520c84f3f3cSopenharmony_ci					*wp++ = OSUBST;
521c84f3f3cSopenharmony_ci					*wp++ = 'X';
522c84f3f3cSopenharmony_ci					do {
523c84f3f3cSopenharmony_ci						Xcheck(ws, wp);
524c84f3f3cSopenharmony_ci						*wp++ = c;
525c84f3f3cSopenharmony_ci						c = getsc();
526c84f3f3cSopenharmony_ci					} while (ctype(c, C_ALNUX));
527c84f3f3cSopenharmony_ci					*wp++ = '\0';
528c84f3f3cSopenharmony_ci					*wp++ = CSUBST;
529c84f3f3cSopenharmony_ci					*wp++ = 'X';
530c84f3f3cSopenharmony_ci					ungetsc(c);
531c84f3f3cSopenharmony_ci				} else if (ctype(c, C_VAR1 | C_DIGIT)) {
532c84f3f3cSopenharmony_ci					Xcheck(ws, wp);
533c84f3f3cSopenharmony_ci					*wp++ = OSUBST;
534c84f3f3cSopenharmony_ci					*wp++ = 'X';
535c84f3f3cSopenharmony_ci					*wp++ = c;
536c84f3f3cSopenharmony_ci					*wp++ = '\0';
537c84f3f3cSopenharmony_ci					*wp++ = CSUBST;
538c84f3f3cSopenharmony_ci					*wp++ = 'X';
539c84f3f3cSopenharmony_ci				} else {
540c84f3f3cSopenharmony_ci					*wp++ = CHAR;
541c84f3f3cSopenharmony_ci					*wp++ = '$';
542c84f3f3cSopenharmony_ci					ungetsc(c);
543c84f3f3cSopenharmony_ci				}
544c84f3f3cSopenharmony_ci				break;
545c84f3f3cSopenharmony_ci			case ORD('`'):
546c84f3f3cSopenharmony_ci subst_gravis:
547c84f3f3cSopenharmony_ci				PUSH_STATE(SBQUOTE);
548c84f3f3cSopenharmony_ci				*wp++ = COMASUB;
549c84f3f3cSopenharmony_ci				/*
550c84f3f3cSopenharmony_ci				 * We need to know whether we are within double
551c84f3f3cSopenharmony_ci				 * quotes in order to translate \" to " within
552c84f3f3cSopenharmony_ci				 * "…`…\"…`…" because, unlike for COMSUBs, the
553c84f3f3cSopenharmony_ci				 * outer double quoteing changes the backslash
554c84f3f3cSopenharmony_ci				 * meaning for the inside. For more details:
555c84f3f3cSopenharmony_ci				 * http://austingroupbugs.net/view.php?id=1015
556c84f3f3cSopenharmony_ci				 */
557c84f3f3cSopenharmony_ci				statep->ls_bool = false;
558c84f3f3cSopenharmony_ci				s2 = statep;
559c84f3f3cSopenharmony_ci				base = state_info.base;
560c84f3f3cSopenharmony_ci				while (/* CONSTCOND */ 1) {
561c84f3f3cSopenharmony_ci					for (; s2 != base; s2--) {
562c84f3f3cSopenharmony_ci						if (s2->type == SDQUOTE) {
563c84f3f3cSopenharmony_ci							statep->ls_bool = true;
564c84f3f3cSopenharmony_ci							break;
565c84f3f3cSopenharmony_ci						}
566c84f3f3cSopenharmony_ci					}
567c84f3f3cSopenharmony_ci					if (s2 != base)
568c84f3f3cSopenharmony_ci						break;
569c84f3f3cSopenharmony_ci					if (!(s2 = s2->ls_base))
570c84f3f3cSopenharmony_ci						break;
571c84f3f3cSopenharmony_ci					base = s2-- - STATE_BSIZE;
572c84f3f3cSopenharmony_ci				}
573c84f3f3cSopenharmony_ci				break;
574c84f3f3cSopenharmony_ci			case QCHAR:
575c84f3f3cSopenharmony_ci				if (cf & LQCHAR) {
576c84f3f3cSopenharmony_ci					*wp++ = QCHAR;
577c84f3f3cSopenharmony_ci					*wp++ = getsc();
578c84f3f3cSopenharmony_ci					break;
579c84f3f3cSopenharmony_ci				}
580c84f3f3cSopenharmony_ci				/* FALLTHROUGH */
581c84f3f3cSopenharmony_ci			default:
582c84f3f3cSopenharmony_ci store_char:
583c84f3f3cSopenharmony_ci				*wp++ = CHAR;
584c84f3f3cSopenharmony_ci				*wp++ = c;
585c84f3f3cSopenharmony_ci			}
586c84f3f3cSopenharmony_ci			break;
587c84f3f3cSopenharmony_ci
588c84f3f3cSopenharmony_ci		case SEQUOTE:
589c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('\'')) {
590c84f3f3cSopenharmony_ci				POP_STATE();
591c84f3f3cSopenharmony_ci				*wp++ = CQUOTE;
592c84f3f3cSopenharmony_ci				ignore_backslash_newline--;
593c84f3f3cSopenharmony_ci			} else if ((unsigned int)c == ORD('\\')) {
594c84f3f3cSopenharmony_ci				if ((c2 = unbksl(true, getsc_i, ungetsc)) == -1)
595c84f3f3cSopenharmony_ci					c2 = getsc();
596c84f3f3cSopenharmony_ci				if (c2 == 0)
597c84f3f3cSopenharmony_ci					statep->ls_bool = true;
598c84f3f3cSopenharmony_ci				if (!statep->ls_bool) {
599c84f3f3cSopenharmony_ci					char ts[4];
600c84f3f3cSopenharmony_ci
601c84f3f3cSopenharmony_ci					if ((unsigned int)c2 < 0x100) {
602c84f3f3cSopenharmony_ci						*wp++ = QCHAR;
603c84f3f3cSopenharmony_ci						*wp++ = c2;
604c84f3f3cSopenharmony_ci					} else {
605c84f3f3cSopenharmony_ci						cz = utf_wctomb(ts, c2 - 0x100);
606c84f3f3cSopenharmony_ci						ts[cz] = 0;
607c84f3f3cSopenharmony_ci						cz = 0;
608c84f3f3cSopenharmony_ci						do {
609c84f3f3cSopenharmony_ci							*wp++ = QCHAR;
610c84f3f3cSopenharmony_ci							*wp++ = ts[cz];
611c84f3f3cSopenharmony_ci						} while (ts[++cz]);
612c84f3f3cSopenharmony_ci					}
613c84f3f3cSopenharmony_ci				}
614c84f3f3cSopenharmony_ci			} else if (!statep->ls_bool) {
615c84f3f3cSopenharmony_ci				*wp++ = QCHAR;
616c84f3f3cSopenharmony_ci				*wp++ = c;
617c84f3f3cSopenharmony_ci			}
618c84f3f3cSopenharmony_ci			break;
619c84f3f3cSopenharmony_ci
620c84f3f3cSopenharmony_ci		case SSQUOTE:
621c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('\'')) {
622c84f3f3cSopenharmony_ci				POP_STATE();
623c84f3f3cSopenharmony_ci				if ((statep->ls_flags & LS_HEREDOC) ||
624c84f3f3cSopenharmony_ci				    state == SQBRACE)
625c84f3f3cSopenharmony_ci					goto store_char;
626c84f3f3cSopenharmony_ci				*wp++ = CQUOTE;
627c84f3f3cSopenharmony_ci				ignore_backslash_newline--;
628c84f3f3cSopenharmony_ci			} else {
629c84f3f3cSopenharmony_ci				*wp++ = QCHAR;
630c84f3f3cSopenharmony_ci				*wp++ = c;
631c84f3f3cSopenharmony_ci			}
632c84f3f3cSopenharmony_ci			break;
633c84f3f3cSopenharmony_ci
634c84f3f3cSopenharmony_ci		case SDQUOTE:
635c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('"')) {
636c84f3f3cSopenharmony_ci				POP_STATE();
637c84f3f3cSopenharmony_ci				*wp++ = CQUOTE;
638c84f3f3cSopenharmony_ci			} else
639c84f3f3cSopenharmony_ci				goto Subst;
640c84f3f3cSopenharmony_ci			break;
641c84f3f3cSopenharmony_ci
642c84f3f3cSopenharmony_ci		/* $(( ... )) */
643c84f3f3cSopenharmony_ci		case SASPAREN:
644c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('('))
645c84f3f3cSopenharmony_ci				statep->nparen++;
646c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD(')')) {
647c84f3f3cSopenharmony_ci				statep->nparen--;
648c84f3f3cSopenharmony_ci				if (statep->nparen == 1) {
649c84f3f3cSopenharmony_ci					/* end of EXPRSUB */
650c84f3f3cSopenharmony_ci					POP_SRETRACE();
651c84f3f3cSopenharmony_ci
652c84f3f3cSopenharmony_ci					if ((unsigned int)(c2 = getsc()) == ORD(/*(*/ ')')) {
653c84f3f3cSopenharmony_ci						cz = strlen(sp) - 2;
654c84f3f3cSopenharmony_ci						XcheckN(ws, wp, cz);
655c84f3f3cSopenharmony_ci						memcpy(wp, sp + 1, cz);
656c84f3f3cSopenharmony_ci						wp += cz;
657c84f3f3cSopenharmony_ci						afree(sp, ATEMP);
658c84f3f3cSopenharmony_ci						*wp++ = '\0';
659c84f3f3cSopenharmony_ci						break;
660c84f3f3cSopenharmony_ci					} else {
661c84f3f3cSopenharmony_ci						Source *s;
662c84f3f3cSopenharmony_ci
663c84f3f3cSopenharmony_ci						ungetsc(c2);
664c84f3f3cSopenharmony_ci						/*
665c84f3f3cSopenharmony_ci						 * mismatched parenthesis -
666c84f3f3cSopenharmony_ci						 * assume we were really
667c84f3f3cSopenharmony_ci						 * parsing a $(...) expression
668c84f3f3cSopenharmony_ci						 */
669c84f3f3cSopenharmony_ci						--wp;
670c84f3f3cSopenharmony_ci						s = pushs(SREREAD,
671c84f3f3cSopenharmony_ci						    source->areap);
672c84f3f3cSopenharmony_ci						s->start = s->str =
673c84f3f3cSopenharmony_ci						    s->u.freeme = sp;
674c84f3f3cSopenharmony_ci						s->next = source;
675c84f3f3cSopenharmony_ci						source = s;
676c84f3f3cSopenharmony_ci						goto subst_command;
677c84f3f3cSopenharmony_ci					}
678c84f3f3cSopenharmony_ci				}
679c84f3f3cSopenharmony_ci			}
680c84f3f3cSopenharmony_ci			/* reuse existing state machine */
681c84f3f3cSopenharmony_ci			goto Sbase2;
682c84f3f3cSopenharmony_ci
683c84f3f3cSopenharmony_ci		case SQBRACE:
684c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('\\')) {
685c84f3f3cSopenharmony_ci				/*
686c84f3f3cSopenharmony_ci				 * perform POSIX "quote removal" if the back-
687c84f3f3cSopenharmony_ci				 * slash is "special", i.e. same cases as the
688c84f3f3cSopenharmony_ci				 * {case '\\':} in Subst: plus closing brace;
689c84f3f3cSopenharmony_ci				 * in mksh code "quote removal" on '\c' means
690c84f3f3cSopenharmony_ci				 * write QCHAR+c, otherwise CHAR+\+CHAR+c are
691c84f3f3cSopenharmony_ci				 * emitted (in heredocquote:)
692c84f3f3cSopenharmony_ci				 */
693c84f3f3cSopenharmony_ci				if ((unsigned int)(c = getsc()) == ORD('"') ||
694c84f3f3cSopenharmony_ci				    (unsigned int)c == ORD('\\') ||
695c84f3f3cSopenharmony_ci				    ctype(c, C_DOLAR | C_GRAVE) ||
696c84f3f3cSopenharmony_ci				    (unsigned int)c == ORD(/*{*/ '}'))
697c84f3f3cSopenharmony_ci					goto store_qchar;
698c84f3f3cSopenharmony_ci				goto heredocquote;
699c84f3f3cSopenharmony_ci			}
700c84f3f3cSopenharmony_ci			goto common_SQBRACE;
701c84f3f3cSopenharmony_ci
702c84f3f3cSopenharmony_ci		case SBRACE:
703c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('\''))
704c84f3f3cSopenharmony_ci				goto open_ssquote_unless_heredoc;
705c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD('\\'))
706c84f3f3cSopenharmony_ci				goto getsc_qchar;
707c84f3f3cSopenharmony_ci common_SQBRACE:
708c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('"'))
709c84f3f3cSopenharmony_ci				goto open_sdquote;
710c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD('$'))
711c84f3f3cSopenharmony_ci				goto subst_dollar_ex;
712c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD('`'))
713c84f3f3cSopenharmony_ci				goto subst_gravis;
714c84f3f3cSopenharmony_ci			else if ((unsigned int)c != ORD(/*{*/ '}'))
715c84f3f3cSopenharmony_ci				goto store_char;
716c84f3f3cSopenharmony_ci			POP_STATE();
717c84f3f3cSopenharmony_ci			*wp++ = CSUBST;
718c84f3f3cSopenharmony_ci			*wp++ = /*{*/ '}';
719c84f3f3cSopenharmony_ci			break;
720c84f3f3cSopenharmony_ci
721c84f3f3cSopenharmony_ci		/* Same as SBASE, except (,|,) treated specially */
722c84f3f3cSopenharmony_ci		case STBRACEKORN:
723c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('|'))
724c84f3f3cSopenharmony_ci				*wp++ = SPAT;
725c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD('(')) {
726c84f3f3cSopenharmony_ci				*wp++ = OPAT;
727c84f3f3cSopenharmony_ci				/* simile for @ */
728c84f3f3cSopenharmony_ci				*wp++ = ' ';
729c84f3f3cSopenharmony_ci				PUSH_STATE(SPATTERN);
730c84f3f3cSopenharmony_ci			} else /* FALLTHROUGH */
731c84f3f3cSopenharmony_ci		case STBRACEBOURNE:
732c84f3f3cSopenharmony_ci			  if ((unsigned int)c == ORD(/*{*/ '}')) {
733c84f3f3cSopenharmony_ci				POP_STATE();
734c84f3f3cSopenharmony_ci				*wp++ = CSUBST;
735c84f3f3cSopenharmony_ci				*wp++ = /*{*/ '}';
736c84f3f3cSopenharmony_ci			} else
737c84f3f3cSopenharmony_ci				goto Sbase1;
738c84f3f3cSopenharmony_ci			break;
739c84f3f3cSopenharmony_ci
740c84f3f3cSopenharmony_ci		case SBQUOTE:
741c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('`')) {
742c84f3f3cSopenharmony_ci				*wp++ = 0;
743c84f3f3cSopenharmony_ci				POP_STATE();
744c84f3f3cSopenharmony_ci			} else if ((unsigned int)c == ORD('\\')) {
745c84f3f3cSopenharmony_ci				switch (c = getsc()) {
746c84f3f3cSopenharmony_ci				case 0:
747c84f3f3cSopenharmony_ci					/* trailing \ is lost */
748c84f3f3cSopenharmony_ci					break;
749c84f3f3cSopenharmony_ci				case ORD('$'):
750c84f3f3cSopenharmony_ci				case ORD('`'):
751c84f3f3cSopenharmony_ci				case ORD('\\'):
752c84f3f3cSopenharmony_ci					*wp++ = c;
753c84f3f3cSopenharmony_ci					break;
754c84f3f3cSopenharmony_ci				case ORD('"'):
755c84f3f3cSopenharmony_ci					if (statep->ls_bool) {
756c84f3f3cSopenharmony_ci						*wp++ = c;
757c84f3f3cSopenharmony_ci						break;
758c84f3f3cSopenharmony_ci					}
759c84f3f3cSopenharmony_ci					/* FALLTHROUGH */
760c84f3f3cSopenharmony_ci				default:
761c84f3f3cSopenharmony_ci					*wp++ = '\\';
762c84f3f3cSopenharmony_ci					*wp++ = c;
763c84f3f3cSopenharmony_ci					break;
764c84f3f3cSopenharmony_ci				}
765c84f3f3cSopenharmony_ci			} else
766c84f3f3cSopenharmony_ci				*wp++ = c;
767c84f3f3cSopenharmony_ci			break;
768c84f3f3cSopenharmony_ci
769c84f3f3cSopenharmony_ci		/* ONEWORD */
770c84f3f3cSopenharmony_ci		case SWORD:
771c84f3f3cSopenharmony_ci			goto Subst;
772c84f3f3cSopenharmony_ci
773c84f3f3cSopenharmony_ci		/* LETEXPR: (( ... )) */
774c84f3f3cSopenharmony_ci		case SLETPAREN:
775c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD(/*(*/ ')')) {
776c84f3f3cSopenharmony_ci				if (statep->nparen > 0)
777c84f3f3cSopenharmony_ci					--statep->nparen;
778c84f3f3cSopenharmony_ci				else if ((unsigned int)(c2 = getsc()) == ORD(/*(*/ ')')) {
779c84f3f3cSopenharmony_ci					c = 0;
780c84f3f3cSopenharmony_ci					*wp++ = CQUOTE;
781c84f3f3cSopenharmony_ci					goto Done;
782c84f3f3cSopenharmony_ci				} else {
783c84f3f3cSopenharmony_ci					Source *s;
784c84f3f3cSopenharmony_ci
785c84f3f3cSopenharmony_ci					ungetsc(c2);
786c84f3f3cSopenharmony_ci					ungetsc(c);
787c84f3f3cSopenharmony_ci					/*
788c84f3f3cSopenharmony_ci					 * mismatched parenthesis -
789c84f3f3cSopenharmony_ci					 * assume we were really
790c84f3f3cSopenharmony_ci					 * parsing a (...) expression
791c84f3f3cSopenharmony_ci					 */
792c84f3f3cSopenharmony_ci					*wp = EOS;
793c84f3f3cSopenharmony_ci					sp = Xstring(ws, wp);
794c84f3f3cSopenharmony_ci					dp = wdstrip(sp + 1, WDS_TPUTS);
795c84f3f3cSopenharmony_ci					s = pushs(SREREAD, source->areap);
796c84f3f3cSopenharmony_ci					s->start = s->str = s->u.freeme = dp;
797c84f3f3cSopenharmony_ci					s->next = source;
798c84f3f3cSopenharmony_ci					source = s;
799c84f3f3cSopenharmony_ci					ungetsc('(' /*)*/);
800c84f3f3cSopenharmony_ci					return (ORD('(' /*)*/));
801c84f3f3cSopenharmony_ci				}
802c84f3f3cSopenharmony_ci			} else if ((unsigned int)c == ORD('('))
803c84f3f3cSopenharmony_ci				/*
804c84f3f3cSopenharmony_ci				 * parentheses inside quotes and
805c84f3f3cSopenharmony_ci				 * backslashes are lost, but AT&T ksh
806c84f3f3cSopenharmony_ci				 * doesn't count them either
807c84f3f3cSopenharmony_ci				 */
808c84f3f3cSopenharmony_ci				++statep->nparen;
809c84f3f3cSopenharmony_ci			goto Sbase2;
810c84f3f3cSopenharmony_ci
811c84f3f3cSopenharmony_ci		/* << or <<- delimiter */
812c84f3f3cSopenharmony_ci		case SHEREDELIM:
813c84f3f3cSopenharmony_ci			/*
814c84f3f3cSopenharmony_ci			 * here delimiters need a special case since
815c84f3f3cSopenharmony_ci			 * $ and `...` are not to be treated specially
816c84f3f3cSopenharmony_ci			 */
817c84f3f3cSopenharmony_ci			switch (c) {
818c84f3f3cSopenharmony_ci			case ORD('\\'):
819c84f3f3cSopenharmony_ci				if ((c = getsc())) {
820c84f3f3cSopenharmony_ci					/* trailing \ is lost */
821c84f3f3cSopenharmony_ci					*wp++ = QCHAR;
822c84f3f3cSopenharmony_ci					*wp++ = c;
823c84f3f3cSopenharmony_ci				}
824c84f3f3cSopenharmony_ci				break;
825c84f3f3cSopenharmony_ci			case ORD('\''):
826c84f3f3cSopenharmony_ci				goto open_ssquote_unless_heredoc;
827c84f3f3cSopenharmony_ci			case ORD('$'):
828c84f3f3cSopenharmony_ci				if ((unsigned int)(c2 = getsc()) == ORD('\'')) {
829c84f3f3cSopenharmony_ci open_sequote:
830c84f3f3cSopenharmony_ci					*wp++ = OQUOTE;
831c84f3f3cSopenharmony_ci					ignore_backslash_newline++;
832c84f3f3cSopenharmony_ci					PUSH_STATE(SEQUOTE);
833c84f3f3cSopenharmony_ci					statep->ls_bool = false;
834c84f3f3cSopenharmony_ci					break;
835c84f3f3cSopenharmony_ci				} else if ((unsigned int)c2 == ORD('"')) {
836c84f3f3cSopenharmony_ci					/* FALLTHROUGH */
837c84f3f3cSopenharmony_ci			case ORD('"'):
838c84f3f3cSopenharmony_ci					PUSH_SRETRACE(SHEREDQUOTE);
839c84f3f3cSopenharmony_ci					break;
840c84f3f3cSopenharmony_ci				}
841c84f3f3cSopenharmony_ci				ungetsc(c2);
842c84f3f3cSopenharmony_ci				/* FALLTHROUGH */
843c84f3f3cSopenharmony_ci			default:
844c84f3f3cSopenharmony_ci				*wp++ = CHAR;
845c84f3f3cSopenharmony_ci				*wp++ = c;
846c84f3f3cSopenharmony_ci			}
847c84f3f3cSopenharmony_ci			break;
848c84f3f3cSopenharmony_ci
849c84f3f3cSopenharmony_ci		/* " in << or <<- delimiter */
850c84f3f3cSopenharmony_ci		case SHEREDQUOTE:
851c84f3f3cSopenharmony_ci			if ((unsigned int)c != ORD('"'))
852c84f3f3cSopenharmony_ci				goto Subst;
853c84f3f3cSopenharmony_ci			POP_SRETRACE();
854c84f3f3cSopenharmony_ci			dp = strnul(sp) - 1;
855c84f3f3cSopenharmony_ci			/* remove the trailing double quote */
856c84f3f3cSopenharmony_ci			*dp = '\0';
857c84f3f3cSopenharmony_ci			/* store the quoted string */
858c84f3f3cSopenharmony_ci			*wp++ = OQUOTE;
859c84f3f3cSopenharmony_ci			XcheckN(ws, wp, (dp - sp) * 2);
860c84f3f3cSopenharmony_ci			dp = sp;
861c84f3f3cSopenharmony_ci			while ((c = *dp++)) {
862c84f3f3cSopenharmony_ci				if (c == '\\') {
863c84f3f3cSopenharmony_ci					switch ((c = *dp++)) {
864c84f3f3cSopenharmony_ci					case ORD('\\'):
865c84f3f3cSopenharmony_ci					case ORD('"'):
866c84f3f3cSopenharmony_ci					case ORD('$'):
867c84f3f3cSopenharmony_ci					case ORD('`'):
868c84f3f3cSopenharmony_ci						break;
869c84f3f3cSopenharmony_ci					default:
870c84f3f3cSopenharmony_ci						*wp++ = CHAR;
871c84f3f3cSopenharmony_ci						*wp++ = '\\';
872c84f3f3cSopenharmony_ci						break;
873c84f3f3cSopenharmony_ci					}
874c84f3f3cSopenharmony_ci				}
875c84f3f3cSopenharmony_ci				*wp++ = CHAR;
876c84f3f3cSopenharmony_ci				*wp++ = c;
877c84f3f3cSopenharmony_ci			}
878c84f3f3cSopenharmony_ci			afree(sp, ATEMP);
879c84f3f3cSopenharmony_ci			*wp++ = CQUOTE;
880c84f3f3cSopenharmony_ci			state = statep->type = SHEREDELIM;
881c84f3f3cSopenharmony_ci			break;
882c84f3f3cSopenharmony_ci
883c84f3f3cSopenharmony_ci		/* in *(...|...) pattern (*+?@!) */
884c84f3f3cSopenharmony_ci		case SPATTERN:
885c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD(/*(*/ ')')) {
886c84f3f3cSopenharmony_ci				*wp++ = CPAT;
887c84f3f3cSopenharmony_ci				POP_STATE();
888c84f3f3cSopenharmony_ci			} else if ((unsigned int)c == ORD('|')) {
889c84f3f3cSopenharmony_ci				*wp++ = SPAT;
890c84f3f3cSopenharmony_ci			} else if ((unsigned int)c == ORD('(')) {
891c84f3f3cSopenharmony_ci				*wp++ = OPAT;
892c84f3f3cSopenharmony_ci				/* simile for @ */
893c84f3f3cSopenharmony_ci				*wp++ = ' ';
894c84f3f3cSopenharmony_ci				PUSH_STATE(SPATTERN);
895c84f3f3cSopenharmony_ci			} else
896c84f3f3cSopenharmony_ci				goto Sbase1;
897c84f3f3cSopenharmony_ci			break;
898c84f3f3cSopenharmony_ci		}
899c84f3f3cSopenharmony_ci	}
900c84f3f3cSopenharmony_ci Done:
901c84f3f3cSopenharmony_ci	Xcheck(ws, wp);
902c84f3f3cSopenharmony_ci	if (statep != &states[1])
903c84f3f3cSopenharmony_ci		/* XXX figure out what is missing */
904c84f3f3cSopenharmony_ci		yyerror("no closing quote");
905c84f3f3cSopenharmony_ci
906c84f3f3cSopenharmony_ci	/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
907c84f3f3cSopenharmony_ci	if (state == SHEREDELIM)
908c84f3f3cSopenharmony_ci		state = SBASE;
909c84f3f3cSopenharmony_ci
910c84f3f3cSopenharmony_ci	dp = Xstring(ws, wp);
911c84f3f3cSopenharmony_ci	if (state == SBASE && (
912c84f3f3cSopenharmony_ci	    (c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
913c84f3f3cSopenharmony_ci	    ctype(c, C_ANGLE)) && ((c2 = Xlength(ws, wp)) == 0 ||
914c84f3f3cSopenharmony_ci	    (c2 == 2 && dp[0] == CHAR && ctype(dp[1], C_DIGIT)))) {
915c84f3f3cSopenharmony_ci		struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
916c84f3f3cSopenharmony_ci
917c84f3f3cSopenharmony_ci		iop->unit = c2 == 2 ? ksh_numdig(dp[1]) : c == '<' ? 0 : 1;
918c84f3f3cSopenharmony_ci
919c84f3f3cSopenharmony_ci		if (c == '&') {
920c84f3f3cSopenharmony_ci			if ((unsigned int)(c2 = getsc()) != ORD('>')) {
921c84f3f3cSopenharmony_ci				ungetsc(c2);
922c84f3f3cSopenharmony_ci				goto no_iop;
923c84f3f3cSopenharmony_ci			}
924c84f3f3cSopenharmony_ci			c = c2;
925c84f3f3cSopenharmony_ci			iop->ioflag = IOBASH;
926c84f3f3cSopenharmony_ci		} else
927c84f3f3cSopenharmony_ci			iop->ioflag = 0;
928c84f3f3cSopenharmony_ci
929c84f3f3cSopenharmony_ci		c2 = getsc();
930c84f3f3cSopenharmony_ci		/* <<, >>, <> are ok, >< is not */
931c84f3f3cSopenharmony_ci		if (c == c2 || ((unsigned int)c == ORD('<') &&
932c84f3f3cSopenharmony_ci		    (unsigned int)c2 == ORD('>'))) {
933c84f3f3cSopenharmony_ci			iop->ioflag |= c == c2 ?
934c84f3f3cSopenharmony_ci			    ((unsigned int)c == ORD('>') ? IOCAT : IOHERE) : IORDWR;
935c84f3f3cSopenharmony_ci			if (iop->ioflag == IOHERE) {
936c84f3f3cSopenharmony_ci				if ((unsigned int)(c2 = getsc()) == ORD('-'))
937c84f3f3cSopenharmony_ci					iop->ioflag |= IOSKIP;
938c84f3f3cSopenharmony_ci				else if ((unsigned int)c2 == ORD('<'))
939c84f3f3cSopenharmony_ci					iop->ioflag |= IOHERESTR;
940c84f3f3cSopenharmony_ci				else
941c84f3f3cSopenharmony_ci					ungetsc(c2);
942c84f3f3cSopenharmony_ci			}
943c84f3f3cSopenharmony_ci		} else if ((unsigned int)c2 == ORD('&'))
944c84f3f3cSopenharmony_ci			iop->ioflag |= IODUP | ((unsigned int)c == ORD('<') ? IORDUP : 0);
945c84f3f3cSopenharmony_ci		else {
946c84f3f3cSopenharmony_ci			iop->ioflag |= (unsigned int)c == ORD('>') ? IOWRITE : IOREAD;
947c84f3f3cSopenharmony_ci			if ((unsigned int)c == ORD('>') && (unsigned int)c2 == ORD('|'))
948c84f3f3cSopenharmony_ci				iop->ioflag |= IOCLOB;
949c84f3f3cSopenharmony_ci			else
950c84f3f3cSopenharmony_ci				ungetsc(c2);
951c84f3f3cSopenharmony_ci		}
952c84f3f3cSopenharmony_ci
953c84f3f3cSopenharmony_ci		iop->ioname = NULL;
954c84f3f3cSopenharmony_ci		iop->delim = NULL;
955c84f3f3cSopenharmony_ci		iop->heredoc = NULL;
956c84f3f3cSopenharmony_ci		/* free word */
957c84f3f3cSopenharmony_ci		Xfree(ws, wp);
958c84f3f3cSopenharmony_ci		yylval.iop = iop;
959c84f3f3cSopenharmony_ci		return (REDIR);
960c84f3f3cSopenharmony_ci no_iop:
961c84f3f3cSopenharmony_ci		afree(iop, ATEMP);
962c84f3f3cSopenharmony_ci	}
963c84f3f3cSopenharmony_ci
964c84f3f3cSopenharmony_ci	if (wp == dp && state == SBASE) {
965c84f3f3cSopenharmony_ci		/* free word */
966c84f3f3cSopenharmony_ci		Xfree(ws, wp);
967c84f3f3cSopenharmony_ci		/* no word, process LEX1 character */
968c84f3f3cSopenharmony_ci		if (((unsigned int)c == ORD('|')) ||
969c84f3f3cSopenharmony_ci		    ((unsigned int)c == ORD('&')) ||
970c84f3f3cSopenharmony_ci		    ((unsigned int)c == ORD(';')) ||
971c84f3f3cSopenharmony_ci		    ((unsigned int)c == ORD('(' /*)*/))) {
972c84f3f3cSopenharmony_ci			if ((c2 = getsc()) == c)
973c84f3f3cSopenharmony_ci				c = ((unsigned int)c == ORD(';')) ? BREAK :
974c84f3f3cSopenharmony_ci				    ((unsigned int)c == ORD('|')) ? LOGOR :
975c84f3f3cSopenharmony_ci				    ((unsigned int)c == ORD('&')) ? LOGAND :
976c84f3f3cSopenharmony_ci				    /* (unsigned int)c == ORD('(' )) */ MDPAREN;
977c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD('|') && (unsigned int)c2 == ORD('&'))
978c84f3f3cSopenharmony_ci				c = COPROC;
979c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD(';') && (unsigned int)c2 == ORD('|'))
980c84f3f3cSopenharmony_ci				c = BRKEV;
981c84f3f3cSopenharmony_ci			else if ((unsigned int)c == ORD(';') && (unsigned int)c2 == ORD('&'))
982c84f3f3cSopenharmony_ci				c = BRKFT;
983c84f3f3cSopenharmony_ci			else
984c84f3f3cSopenharmony_ci				ungetsc(c2);
985c84f3f3cSopenharmony_ci#ifndef MKSH_SMALL
986c84f3f3cSopenharmony_ci			if (c == BREAK) {
987c84f3f3cSopenharmony_ci				if ((unsigned int)(c2 = getsc()) == ORD('&'))
988c84f3f3cSopenharmony_ci					c = BRKEV;
989c84f3f3cSopenharmony_ci				else
990c84f3f3cSopenharmony_ci					ungetsc(c2);
991c84f3f3cSopenharmony_ci			}
992c84f3f3cSopenharmony_ci#endif
993c84f3f3cSopenharmony_ci		} else if ((unsigned int)c == ORD('\n')) {
994c84f3f3cSopenharmony_ci			if (cf & HEREDELIM)
995c84f3f3cSopenharmony_ci				ungetsc(c);
996c84f3f3cSopenharmony_ci			else {
997c84f3f3cSopenharmony_ci				gethere();
998c84f3f3cSopenharmony_ci				if (cf & CONTIN)
999c84f3f3cSopenharmony_ci					goto Again;
1000c84f3f3cSopenharmony_ci			}
1001c84f3f3cSopenharmony_ci		} else if (c == '\0' && !(cf & HEREDELIM)) {
1002c84f3f3cSopenharmony_ci			struct ioword **p = heres;
1003c84f3f3cSopenharmony_ci
1004c84f3f3cSopenharmony_ci			while (p < herep)
1005c84f3f3cSopenharmony_ci				if ((*p)->ioflag & IOHERESTR)
1006c84f3f3cSopenharmony_ci					++p;
1007c84f3f3cSopenharmony_ci				else
1008c84f3f3cSopenharmony_ci					/* ksh -c 'cat <<EOF' can cause this */
1009c84f3f3cSopenharmony_ci					yyerror(Tf_heredoc,
1010c84f3f3cSopenharmony_ci					    evalstr((*p)->delim, 0));
1011c84f3f3cSopenharmony_ci		}
1012c84f3f3cSopenharmony_ci		return (c);
1013c84f3f3cSopenharmony_ci	}
1014c84f3f3cSopenharmony_ci
1015c84f3f3cSopenharmony_ci	/* terminate word */
1016c84f3f3cSopenharmony_ci	*wp++ = EOS;
1017c84f3f3cSopenharmony_ci	yylval.cp = Xclose(ws, wp);
1018c84f3f3cSopenharmony_ci	if (state == SWORD || state == SLETPAREN
1019c84f3f3cSopenharmony_ci	    /* XXX ONEWORD? */)
1020c84f3f3cSopenharmony_ci		return (LWORD);
1021c84f3f3cSopenharmony_ci
1022c84f3f3cSopenharmony_ci	/* unget terminator */
1023c84f3f3cSopenharmony_ci	ungetsc(c);
1024c84f3f3cSopenharmony_ci
1025c84f3f3cSopenharmony_ci	/*
1026c84f3f3cSopenharmony_ci	 * note: the alias-vs-function code below depends on several
1027c84f3f3cSopenharmony_ci	 * interna: starting from here, source->str is not modified;
1028c84f3f3cSopenharmony_ci	 * the way getsc() and ungetsc() operate; etc.
1029c84f3f3cSopenharmony_ci	 */
1030c84f3f3cSopenharmony_ci
1031c84f3f3cSopenharmony_ci	/* copy word to unprefixed string ident */
1032c84f3f3cSopenharmony_ci	sp = yylval.cp;
1033c84f3f3cSopenharmony_ci	dp = ident;
1034c84f3f3cSopenharmony_ci	while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
1035c84f3f3cSopenharmony_ci		*dp++ = *sp++;
1036c84f3f3cSopenharmony_ci	if (c != EOS)
1037c84f3f3cSopenharmony_ci		/* word is not unquoted, or space ran out */
1038c84f3f3cSopenharmony_ci		dp = ident;
1039c84f3f3cSopenharmony_ci	/* make sure the ident array stays NUL padded */
1040c84f3f3cSopenharmony_ci	memset(dp, 0, (ident + IDENT) - dp + 1);
1041c84f3f3cSopenharmony_ci
1042c84f3f3cSopenharmony_ci	if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
1043c84f3f3cSopenharmony_ci		struct tbl *p;
1044c84f3f3cSopenharmony_ci		uint32_t h = hash(ident);
1045c84f3f3cSopenharmony_ci
1046c84f3f3cSopenharmony_ci		if ((cf & KEYWORD) && (p = ktsearch(&keywords, ident, h)) &&
1047c84f3f3cSopenharmony_ci		    (!(cf & ESACONLY) || p->val.i == ESAC ||
1048c84f3f3cSopenharmony_ci		    (unsigned int)p->val.i == ORD(/*{*/ '}'))) {
1049c84f3f3cSopenharmony_ci			afree(yylval.cp, ATEMP);
1050c84f3f3cSopenharmony_ci			return (p->val.i);
1051c84f3f3cSopenharmony_ci		}
1052c84f3f3cSopenharmony_ci		if ((cf & ALIAS) && (p = ktsearch(&aliases, ident, h)) &&
1053c84f3f3cSopenharmony_ci		    (p->flag & ISSET)) {
1054c84f3f3cSopenharmony_ci			/*
1055c84f3f3cSopenharmony_ci			 * this still points to the same character as the
1056c84f3f3cSopenharmony_ci			 * ungetsc'd terminator from above
1057c84f3f3cSopenharmony_ci			 */
1058c84f3f3cSopenharmony_ci			const char *cp = source->str;
1059c84f3f3cSopenharmony_ci
1060c84f3f3cSopenharmony_ci			/* prefer POSIX but not Korn functions over aliases */
1061c84f3f3cSopenharmony_ci			while (ctype(*cp, C_BLANK))
1062c84f3f3cSopenharmony_ci				/*
1063c84f3f3cSopenharmony_ci				 * this is like getsc() without skipping
1064c84f3f3cSopenharmony_ci				 * over Source boundaries (including not
1065c84f3f3cSopenharmony_ci				 * parsing ungetsc'd characters that got
1066c84f3f3cSopenharmony_ci				 * pushed into an SREREAD) which is what
1067c84f3f3cSopenharmony_ci				 * we want here anyway: find out whether
1068c84f3f3cSopenharmony_ci				 * the alias name is followed by a POSIX
1069c84f3f3cSopenharmony_ci				 * function definition
1070c84f3f3cSopenharmony_ci				 */
1071c84f3f3cSopenharmony_ci				++cp;
1072c84f3f3cSopenharmony_ci			/* prefer functions over aliases */
1073c84f3f3cSopenharmony_ci			if (cp[0] != '(' || cp[1] != ')') {
1074c84f3f3cSopenharmony_ci				Source *s = source;
1075c84f3f3cSopenharmony_ci
1076c84f3f3cSopenharmony_ci				while (s && (s->flags & SF_HASALIAS))
1077c84f3f3cSopenharmony_ci					if (s->u.tblp == p)
1078c84f3f3cSopenharmony_ci						return (LWORD);
1079c84f3f3cSopenharmony_ci					else
1080c84f3f3cSopenharmony_ci						s = s->next;
1081c84f3f3cSopenharmony_ci				/* push alias expansion */
1082c84f3f3cSopenharmony_ci				s = pushs(SALIAS, source->areap);
1083c84f3f3cSopenharmony_ci				s->start = s->str = p->val.s;
1084c84f3f3cSopenharmony_ci				s->u.tblp = p;
1085c84f3f3cSopenharmony_ci				s->flags |= SF_HASALIAS;
1086c84f3f3cSopenharmony_ci				s->line = source->line;
1087c84f3f3cSopenharmony_ci				s->next = source;
1088c84f3f3cSopenharmony_ci				if (source->type == SEOF) {
1089c84f3f3cSopenharmony_ci					/* prevent infinite recursion at EOS */
1090c84f3f3cSopenharmony_ci					source->u.tblp = p;
1091c84f3f3cSopenharmony_ci					source->flags |= SF_HASALIAS;
1092c84f3f3cSopenharmony_ci				}
1093c84f3f3cSopenharmony_ci				source = s;
1094c84f3f3cSopenharmony_ci				afree(yylval.cp, ATEMP);
1095c84f3f3cSopenharmony_ci				goto Again;
1096c84f3f3cSopenharmony_ci			}
1097c84f3f3cSopenharmony_ci		}
1098c84f3f3cSopenharmony_ci	} else if (*ident == '\0') {
1099c84f3f3cSopenharmony_ci		/* retain typeset et al. even when quoted */
1100c84f3f3cSopenharmony_ci		struct tbl *tt = get_builtin((dp = wdstrip(yylval.cp, 0)));
1101c84f3f3cSopenharmony_ci		uint32_t flag = tt ? tt->flag : 0;
1102c84f3f3cSopenharmony_ci
1103c84f3f3cSopenharmony_ci		if (flag & (DECL_UTIL | DECL_FWDR))
1104c84f3f3cSopenharmony_ci			strlcpy(ident, dp, sizeof(ident));
1105c84f3f3cSopenharmony_ci		afree(dp, ATEMP);
1106c84f3f3cSopenharmony_ci	}
1107c84f3f3cSopenharmony_ci
1108c84f3f3cSopenharmony_ci	return (LWORD);
1109c84f3f3cSopenharmony_ci}
1110c84f3f3cSopenharmony_ci
1111c84f3f3cSopenharmony_cistatic void
1112c84f3f3cSopenharmony_cigethere(void)
1113c84f3f3cSopenharmony_ci{
1114c84f3f3cSopenharmony_ci	struct ioword **p;
1115c84f3f3cSopenharmony_ci
1116c84f3f3cSopenharmony_ci	for (p = heres; p < herep; p++)
1117c84f3f3cSopenharmony_ci		if (!((*p)->ioflag & IOHERESTR))
1118c84f3f3cSopenharmony_ci			readhere(*p);
1119c84f3f3cSopenharmony_ci	herep = heres;
1120c84f3f3cSopenharmony_ci}
1121c84f3f3cSopenharmony_ci
1122c84f3f3cSopenharmony_ci/*
1123c84f3f3cSopenharmony_ci * read "<<word" text into temp file
1124c84f3f3cSopenharmony_ci */
1125c84f3f3cSopenharmony_ci
1126c84f3f3cSopenharmony_cistatic void
1127c84f3f3cSopenharmony_cireadhere(struct ioword *iop)
1128c84f3f3cSopenharmony_ci{
1129c84f3f3cSopenharmony_ci	int c;
1130c84f3f3cSopenharmony_ci	const char *eof, *eofp;
1131c84f3f3cSopenharmony_ci	XString xs;
1132c84f3f3cSopenharmony_ci	char *xp;
1133c84f3f3cSopenharmony_ci	size_t xpos;
1134c84f3f3cSopenharmony_ci
1135c84f3f3cSopenharmony_ci	eof = evalstr(iop->delim, 0);
1136c84f3f3cSopenharmony_ci
1137c84f3f3cSopenharmony_ci	if (!(iop->ioflag & IOEVAL))
1138c84f3f3cSopenharmony_ci		ignore_backslash_newline++;
1139c84f3f3cSopenharmony_ci
1140c84f3f3cSopenharmony_ci	Xinit(xs, xp, 256, ATEMP);
1141c84f3f3cSopenharmony_ci
1142c84f3f3cSopenharmony_ci heredoc_read_line:
1143c84f3f3cSopenharmony_ci	/* beginning of line */
1144c84f3f3cSopenharmony_ci	eofp = eof;
1145c84f3f3cSopenharmony_ci	xpos = Xsavepos(xs, xp);
1146c84f3f3cSopenharmony_ci	if (iop->ioflag & IOSKIP) {
1147c84f3f3cSopenharmony_ci		/* skip over leading tabs */
1148c84f3f3cSopenharmony_ci		while ((c = getsc()) == '\t')
1149c84f3f3cSopenharmony_ci			;	/* nothing */
1150c84f3f3cSopenharmony_ci		goto heredoc_parse_char;
1151c84f3f3cSopenharmony_ci	}
1152c84f3f3cSopenharmony_ci heredoc_read_char:
1153c84f3f3cSopenharmony_ci	c = getsc();
1154c84f3f3cSopenharmony_ci heredoc_parse_char:
1155c84f3f3cSopenharmony_ci	/* compare with here document marker */
1156c84f3f3cSopenharmony_ci	if (!*eofp) {
1157c84f3f3cSopenharmony_ci		/* end of here document marker, what to do? */
1158c84f3f3cSopenharmony_ci		switch (c) {
1159c84f3f3cSopenharmony_ci		case ORD(/*(*/ ')'):
1160c84f3f3cSopenharmony_ci			if (!subshell_nesting_type)
1161c84f3f3cSopenharmony_ci				/*-
1162c84f3f3cSopenharmony_ci				 * not allowed outside $(...) or (...)
1163c84f3f3cSopenharmony_ci				 * => mismatch
1164c84f3f3cSopenharmony_ci				 */
1165c84f3f3cSopenharmony_ci				break;
1166c84f3f3cSopenharmony_ci			/* allow $(...) or (...) to close here */
1167c84f3f3cSopenharmony_ci			ungetsc(/*(*/ ')');
1168c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
1169c84f3f3cSopenharmony_ci		case 0:
1170c84f3f3cSopenharmony_ci			/*
1171c84f3f3cSopenharmony_ci			 * Allow EOF here to commands without trailing
1172c84f3f3cSopenharmony_ci			 * newlines (mksh -c '...') will work as well.
1173c84f3f3cSopenharmony_ci			 */
1174c84f3f3cSopenharmony_ci		case ORD('\n'):
1175c84f3f3cSopenharmony_ci			/* Newline terminates here document marker */
1176c84f3f3cSopenharmony_ci			goto heredoc_found_terminator;
1177c84f3f3cSopenharmony_ci		}
1178c84f3f3cSopenharmony_ci	} else if ((unsigned int)c == ord(*eofp++))
1179c84f3f3cSopenharmony_ci		/* store; then read and compare next character */
1180c84f3f3cSopenharmony_ci		goto heredoc_store_and_loop;
1181c84f3f3cSopenharmony_ci	/* nope, mismatch; read until end of line */
1182c84f3f3cSopenharmony_ci	while (c != '\n') {
1183c84f3f3cSopenharmony_ci		if (!c)
1184c84f3f3cSopenharmony_ci			/* oops, reached EOF */
1185c84f3f3cSopenharmony_ci			yyerror(Tf_heredoc, eof);
1186c84f3f3cSopenharmony_ci		/* store character */
1187c84f3f3cSopenharmony_ci		Xcheck(xs, xp);
1188c84f3f3cSopenharmony_ci		Xput(xs, xp, c);
1189c84f3f3cSopenharmony_ci		/* read next character */
1190c84f3f3cSopenharmony_ci		c = getsc();
1191c84f3f3cSopenharmony_ci	}
1192c84f3f3cSopenharmony_ci	/* we read a newline as last character */
1193c84f3f3cSopenharmony_ci heredoc_store_and_loop:
1194c84f3f3cSopenharmony_ci	/* store character */
1195c84f3f3cSopenharmony_ci	Xcheck(xs, xp);
1196c84f3f3cSopenharmony_ci	Xput(xs, xp, c);
1197c84f3f3cSopenharmony_ci	if (c == '\n')
1198c84f3f3cSopenharmony_ci		goto heredoc_read_line;
1199c84f3f3cSopenharmony_ci	goto heredoc_read_char;
1200c84f3f3cSopenharmony_ci
1201c84f3f3cSopenharmony_ci heredoc_found_terminator:
1202c84f3f3cSopenharmony_ci	/* jump back to saved beginning of line */
1203c84f3f3cSopenharmony_ci	xp = Xrestpos(xs, xp, xpos);
1204c84f3f3cSopenharmony_ci	/* terminate, close and store */
1205c84f3f3cSopenharmony_ci	Xput(xs, xp, '\0');
1206c84f3f3cSopenharmony_ci	iop->heredoc = Xclose(xs, xp);
1207c84f3f3cSopenharmony_ci
1208c84f3f3cSopenharmony_ci	if (!(iop->ioflag & IOEVAL))
1209c84f3f3cSopenharmony_ci		ignore_backslash_newline--;
1210c84f3f3cSopenharmony_ci}
1211c84f3f3cSopenharmony_ci
1212c84f3f3cSopenharmony_civoid
1213c84f3f3cSopenharmony_ciyyerror(const char *fmt, ...)
1214c84f3f3cSopenharmony_ci{
1215c84f3f3cSopenharmony_ci	va_list va;
1216c84f3f3cSopenharmony_ci
1217c84f3f3cSopenharmony_ci	/* pop aliases and re-reads */
1218c84f3f3cSopenharmony_ci	while (source->type == SALIAS || source->type == SREREAD)
1219c84f3f3cSopenharmony_ci		source = source->next;
1220c84f3f3cSopenharmony_ci	/* zap pending input */
1221c84f3f3cSopenharmony_ci	source->str = null;
1222c84f3f3cSopenharmony_ci
1223c84f3f3cSopenharmony_ci	error_prefix(true);
1224c84f3f3cSopenharmony_ci	va_start(va, fmt);
1225c84f3f3cSopenharmony_ci	shf_vfprintf(shl_out, fmt, va);
1226c84f3f3cSopenharmony_ci	shf_putc('\n', shl_out);
1227c84f3f3cSopenharmony_ci	va_end(va);
1228c84f3f3cSopenharmony_ci	errorfz();
1229c84f3f3cSopenharmony_ci}
1230c84f3f3cSopenharmony_ci
1231c84f3f3cSopenharmony_ci/*
1232c84f3f3cSopenharmony_ci * input for yylex with alias expansion
1233c84f3f3cSopenharmony_ci */
1234c84f3f3cSopenharmony_ci
1235c84f3f3cSopenharmony_ciSource *
1236c84f3f3cSopenharmony_cipushs(int type, Area *areap)
1237c84f3f3cSopenharmony_ci{
1238c84f3f3cSopenharmony_ci	Source *s;
1239c84f3f3cSopenharmony_ci
1240c84f3f3cSopenharmony_ci	s = alloc(sizeof(Source), areap);
1241c84f3f3cSopenharmony_ci	memset(s, 0, sizeof(Source));
1242c84f3f3cSopenharmony_ci	s->type = type;
1243c84f3f3cSopenharmony_ci	s->str = null;
1244c84f3f3cSopenharmony_ci	s->areap = areap;
1245c84f3f3cSopenharmony_ci	if (type == SFILE || type == SSTDIN)
1246c84f3f3cSopenharmony_ci		XinitN(s->xs, 256, s->areap);
1247c84f3f3cSopenharmony_ci	return (s);
1248c84f3f3cSopenharmony_ci}
1249c84f3f3cSopenharmony_ci
1250c84f3f3cSopenharmony_cistatic int
1251c84f3f3cSopenharmony_cigetsc_uu(void)
1252c84f3f3cSopenharmony_ci{
1253c84f3f3cSopenharmony_ci	Source *s = source;
1254c84f3f3cSopenharmony_ci	int c;
1255c84f3f3cSopenharmony_ci
1256c84f3f3cSopenharmony_ci	while ((c = ord(*s->str++)) == 0) {
1257c84f3f3cSopenharmony_ci		/* return 0 for EOF by default */
1258c84f3f3cSopenharmony_ci		s->str = NULL;
1259c84f3f3cSopenharmony_ci		switch (s->type) {
1260c84f3f3cSopenharmony_ci		case SEOF:
1261c84f3f3cSopenharmony_ci			s->str = null;
1262c84f3f3cSopenharmony_ci			return (0);
1263c84f3f3cSopenharmony_ci
1264c84f3f3cSopenharmony_ci		case SSTDIN:
1265c84f3f3cSopenharmony_ci		case SFILE:
1266c84f3f3cSopenharmony_ci			getsc_line(s);
1267c84f3f3cSopenharmony_ci			break;
1268c84f3f3cSopenharmony_ci
1269c84f3f3cSopenharmony_ci		case SWSTR:
1270c84f3f3cSopenharmony_ci			break;
1271c84f3f3cSopenharmony_ci
1272c84f3f3cSopenharmony_ci		case SSTRING:
1273c84f3f3cSopenharmony_ci		case SSTRINGCMDLINE:
1274c84f3f3cSopenharmony_ci			break;
1275c84f3f3cSopenharmony_ci
1276c84f3f3cSopenharmony_ci		case SWORDS:
1277c84f3f3cSopenharmony_ci			s->start = s->str = *s->u.strv++;
1278c84f3f3cSopenharmony_ci			s->type = SWORDSEP;
1279c84f3f3cSopenharmony_ci			break;
1280c84f3f3cSopenharmony_ci
1281c84f3f3cSopenharmony_ci		case SWORDSEP:
1282c84f3f3cSopenharmony_ci			if (*s->u.strv == NULL) {
1283c84f3f3cSopenharmony_ci				s->start = s->str = "\n";
1284c84f3f3cSopenharmony_ci				s->type = SEOF;
1285c84f3f3cSopenharmony_ci			} else {
1286c84f3f3cSopenharmony_ci				s->start = s->str = T1space;
1287c84f3f3cSopenharmony_ci				s->type = SWORDS;
1288c84f3f3cSopenharmony_ci			}
1289c84f3f3cSopenharmony_ci			break;
1290c84f3f3cSopenharmony_ci
1291c84f3f3cSopenharmony_ci		case SALIAS:
1292c84f3f3cSopenharmony_ci			if (s->flags & SF_ALIASEND) {
1293c84f3f3cSopenharmony_ci				/* pass on an unused SF_ALIAS flag */
1294c84f3f3cSopenharmony_ci				source = s->next;
1295c84f3f3cSopenharmony_ci				source->flags |= s->flags & SF_ALIAS;
1296c84f3f3cSopenharmony_ci				s = source;
1297c84f3f3cSopenharmony_ci			} else if (*s->u.tblp->val.s &&
1298c84f3f3cSopenharmony_ci			    ctype((c = strnul(s->u.tblp->val.s)[-1]), C_SPACE)) {
1299c84f3f3cSopenharmony_ci				/* pop source stack */
1300c84f3f3cSopenharmony_ci				source = s = s->next;
1301c84f3f3cSopenharmony_ci				/*
1302c84f3f3cSopenharmony_ci				 * Note that this alias ended with a
1303c84f3f3cSopenharmony_ci				 * space, enabling alias expansion on
1304c84f3f3cSopenharmony_ci				 * the following word.
1305c84f3f3cSopenharmony_ci				 */
1306c84f3f3cSopenharmony_ci				s->flags |= SF_ALIAS;
1307c84f3f3cSopenharmony_ci			} else {
1308c84f3f3cSopenharmony_ci				/*
1309c84f3f3cSopenharmony_ci				 * At this point, we need to keep the current
1310c84f3f3cSopenharmony_ci				 * alias in the source list so recursive
1311c84f3f3cSopenharmony_ci				 * aliases can be detected and we also need to
1312c84f3f3cSopenharmony_ci				 * return the next character. Do this by
1313c84f3f3cSopenharmony_ci				 * temporarily popping the alias to get the
1314c84f3f3cSopenharmony_ci				 * next character and then put it back in the
1315c84f3f3cSopenharmony_ci				 * source list with the SF_ALIASEND flag set.
1316c84f3f3cSopenharmony_ci				 */
1317c84f3f3cSopenharmony_ci				/* pop source stack */
1318c84f3f3cSopenharmony_ci				source = s->next;
1319c84f3f3cSopenharmony_ci				source->flags |= s->flags & SF_ALIAS;
1320c84f3f3cSopenharmony_ci				c = getsc_uu();
1321c84f3f3cSopenharmony_ci				if (c) {
1322c84f3f3cSopenharmony_ci					s->flags |= SF_ALIASEND;
1323c84f3f3cSopenharmony_ci					s->ugbuf[0] = c; s->ugbuf[1] = '\0';
1324c84f3f3cSopenharmony_ci					s->start = s->str = s->ugbuf;
1325c84f3f3cSopenharmony_ci					s->next = source;
1326c84f3f3cSopenharmony_ci					source = s;
1327c84f3f3cSopenharmony_ci				} else {
1328c84f3f3cSopenharmony_ci					s = source;
1329c84f3f3cSopenharmony_ci					/* avoid reading EOF twice */
1330c84f3f3cSopenharmony_ci					s->str = NULL;
1331c84f3f3cSopenharmony_ci					break;
1332c84f3f3cSopenharmony_ci				}
1333c84f3f3cSopenharmony_ci			}
1334c84f3f3cSopenharmony_ci			continue;
1335c84f3f3cSopenharmony_ci
1336c84f3f3cSopenharmony_ci		case SREREAD:
1337c84f3f3cSopenharmony_ci			if (s->start != s->ugbuf)
1338c84f3f3cSopenharmony_ci				/* yuck */
1339c84f3f3cSopenharmony_ci				afree(s->u.freeme, ATEMP);
1340c84f3f3cSopenharmony_ci			source = s = s->next;
1341c84f3f3cSopenharmony_ci			continue;
1342c84f3f3cSopenharmony_ci		}
1343c84f3f3cSopenharmony_ci		if (s->str == NULL) {
1344c84f3f3cSopenharmony_ci			s->type = SEOF;
1345c84f3f3cSopenharmony_ci			s->start = s->str = null;
1346c84f3f3cSopenharmony_ci			return ('\0');
1347c84f3f3cSopenharmony_ci		}
1348c84f3f3cSopenharmony_ci		if (s->flags & SF_ECHO) {
1349c84f3f3cSopenharmony_ci			shf_puts(s->str, shl_out);
1350c84f3f3cSopenharmony_ci			shf_flush(shl_out);
1351c84f3f3cSopenharmony_ci		}
1352c84f3f3cSopenharmony_ci	}
1353c84f3f3cSopenharmony_ci	return (c);
1354c84f3f3cSopenharmony_ci}
1355c84f3f3cSopenharmony_ci
1356c84f3f3cSopenharmony_cistatic void
1357c84f3f3cSopenharmony_cigetsc_line(Source *s)
1358c84f3f3cSopenharmony_ci{
1359c84f3f3cSopenharmony_ci	char *xp = Xstring(s->xs, xp), *cp;
1360c84f3f3cSopenharmony_ci	bool interactive = Flag(FTALKING) && s->type == SSTDIN;
1361c84f3f3cSopenharmony_ci	bool have_tty = interactive && (s->flags & SF_TTY) && tty_hasstate;
1362c84f3f3cSopenharmony_ci
1363c84f3f3cSopenharmony_ci	/* Done here to ensure nothing odd happens when a timeout occurs */
1364c84f3f3cSopenharmony_ci	XcheckN(s->xs, xp, LINE);
1365c84f3f3cSopenharmony_ci	*xp = '\0';
1366c84f3f3cSopenharmony_ci	s->start = s->str = xp;
1367c84f3f3cSopenharmony_ci
1368c84f3f3cSopenharmony_ci	if (have_tty && ksh_tmout) {
1369c84f3f3cSopenharmony_ci		ksh_tmout_state = TMOUT_READING;
1370c84f3f3cSopenharmony_ci		alarm(ksh_tmout);
1371c84f3f3cSopenharmony_ci	}
1372c84f3f3cSopenharmony_ci	if (interactive) {
1373c84f3f3cSopenharmony_ci		if (cur_prompt == PS1)
1374c84f3f3cSopenharmony_ci			histsave(&s->line, NULL, HIST_FLUSH, true);
1375c84f3f3cSopenharmony_ci		change_winsz();
1376c84f3f3cSopenharmony_ci	}
1377c84f3f3cSopenharmony_ci#ifndef MKSH_NO_CMDLINE_EDITING
1378c84f3f3cSopenharmony_ci	if (have_tty && (
1379c84f3f3cSopenharmony_ci#if !MKSH_S_NOVI
1380c84f3f3cSopenharmony_ci	    Flag(FVI) ||
1381c84f3f3cSopenharmony_ci#endif
1382c84f3f3cSopenharmony_ci	    Flag(FEMACS) || Flag(FGMACS))) {
1383c84f3f3cSopenharmony_ci		int nread;
1384c84f3f3cSopenharmony_ci
1385c84f3f3cSopenharmony_ci		nread = x_read(xp);
1386c84f3f3cSopenharmony_ci		if (nread < 0)
1387c84f3f3cSopenharmony_ci			/* read error */
1388c84f3f3cSopenharmony_ci			nread = 0;
1389c84f3f3cSopenharmony_ci		xp[nread] = '\0';
1390c84f3f3cSopenharmony_ci		xp += nread;
1391c84f3f3cSopenharmony_ci	} else
1392c84f3f3cSopenharmony_ci#endif
1393c84f3f3cSopenharmony_ci	  {
1394c84f3f3cSopenharmony_ci		if (interactive)
1395c84f3f3cSopenharmony_ci			pprompt(prompt, 0);
1396c84f3f3cSopenharmony_ci		else
1397c84f3f3cSopenharmony_ci			s->line++;
1398c84f3f3cSopenharmony_ci
1399c84f3f3cSopenharmony_ci		while (/* CONSTCOND */ 1) {
1400c84f3f3cSopenharmony_ci			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
1401c84f3f3cSopenharmony_ci
1402c84f3f3cSopenharmony_ci			if (!p && shf_error(s->u.shf) &&
1403c84f3f3cSopenharmony_ci			    shf_errno(s->u.shf) == EINTR) {
1404c84f3f3cSopenharmony_ci				shf_clearerr(s->u.shf);
1405c84f3f3cSopenharmony_ci				if (trap)
1406c84f3f3cSopenharmony_ci					runtraps(0);
1407c84f3f3cSopenharmony_ci				continue;
1408c84f3f3cSopenharmony_ci			}
1409c84f3f3cSopenharmony_ci			if (!p || (xp = p, xp[-1] == '\n'))
1410c84f3f3cSopenharmony_ci				break;
1411c84f3f3cSopenharmony_ci			/* double buffer size */
1412c84f3f3cSopenharmony_ci			/* move past NUL so doubling works... */
1413c84f3f3cSopenharmony_ci			xp++;
1414c84f3f3cSopenharmony_ci			XcheckN(s->xs, xp, Xlength(s->xs, xp));
1415c84f3f3cSopenharmony_ci			/* ...and move back again */
1416c84f3f3cSopenharmony_ci			xp--;
1417c84f3f3cSopenharmony_ci		}
1418c84f3f3cSopenharmony_ci		/*
1419c84f3f3cSopenharmony_ci		 * flush any unwanted input so other programs/builtins
1420c84f3f3cSopenharmony_ci		 * can read it. Not very optimal, but less error prone
1421c84f3f3cSopenharmony_ci		 * than flushing else where, dealing with redirections,
1422c84f3f3cSopenharmony_ci		 * etc.
1423c84f3f3cSopenharmony_ci		 * TODO: reduce size of shf buffer (~128?) if SSTDIN
1424c84f3f3cSopenharmony_ci		 */
1425c84f3f3cSopenharmony_ci		if (s->type == SSTDIN)
1426c84f3f3cSopenharmony_ci			shf_flush(s->u.shf);
1427c84f3f3cSopenharmony_ci	}
1428c84f3f3cSopenharmony_ci	/*
1429c84f3f3cSopenharmony_ci	 * XXX: temporary kludge to restore source after a
1430c84f3f3cSopenharmony_ci	 * trap may have been executed.
1431c84f3f3cSopenharmony_ci	 */
1432c84f3f3cSopenharmony_ci	source = s;
1433c84f3f3cSopenharmony_ci	if (have_tty && ksh_tmout) {
1434c84f3f3cSopenharmony_ci		ksh_tmout_state = TMOUT_EXECUTING;
1435c84f3f3cSopenharmony_ci		alarm(0);
1436c84f3f3cSopenharmony_ci	}
1437c84f3f3cSopenharmony_ci	cp = Xstring(s->xs, xp);
1438c84f3f3cSopenharmony_ci	rndpush(cp);
1439c84f3f3cSopenharmony_ci	s->start = s->str = cp;
1440c84f3f3cSopenharmony_ci	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
1441c84f3f3cSopenharmony_ci	/* Note: if input is all nulls, this is not eof */
1442c84f3f3cSopenharmony_ci	if (Xlength(s->xs, xp) == 0) {
1443c84f3f3cSopenharmony_ci		/* EOF */
1444c84f3f3cSopenharmony_ci		if (s->type == SFILE)
1445c84f3f3cSopenharmony_ci			shf_fdclose(s->u.shf);
1446c84f3f3cSopenharmony_ci		s->str = NULL;
1447c84f3f3cSopenharmony_ci	} else if (interactive && *s->str) {
1448c84f3f3cSopenharmony_ci		if (cur_prompt != PS1)
1449c84f3f3cSopenharmony_ci			histsave(&s->line, s->str, HIST_APPEND, true);
1450c84f3f3cSopenharmony_ci		else if (!ctype(*s->str, C_IFS | C_IFSWS))
1451c84f3f3cSopenharmony_ci			histsave(&s->line, s->str, HIST_QUEUE, true);
1452c84f3f3cSopenharmony_ci#if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
1453c84f3f3cSopenharmony_ci		else
1454c84f3f3cSopenharmony_ci			goto check_for_sole_return;
1455c84f3f3cSopenharmony_ci	} else if (interactive && cur_prompt == PS1) {
1456c84f3f3cSopenharmony_ci check_for_sole_return:
1457c84f3f3cSopenharmony_ci		cp = Xstring(s->xs, xp);
1458c84f3f3cSopenharmony_ci		while (ctype(*cp, C_IFSWS))
1459c84f3f3cSopenharmony_ci			++cp;
1460c84f3f3cSopenharmony_ci		if (!*cp) {
1461c84f3f3cSopenharmony_ci			histsave(&s->line, NULL, HIST_FLUSH, true);
1462c84f3f3cSopenharmony_ci			histsync();
1463c84f3f3cSopenharmony_ci		}
1464c84f3f3cSopenharmony_ci#endif
1465c84f3f3cSopenharmony_ci	}
1466c84f3f3cSopenharmony_ci	if (interactive)
1467c84f3f3cSopenharmony_ci		set_prompt(PS2, NULL);
1468c84f3f3cSopenharmony_ci}
1469c84f3f3cSopenharmony_ci
1470c84f3f3cSopenharmony_civoid
1471c84f3f3cSopenharmony_ciset_prompt(int to, Source *s)
1472c84f3f3cSopenharmony_ci{
1473c84f3f3cSopenharmony_ci	cur_prompt = (uint8_t)to;
1474c84f3f3cSopenharmony_ci
1475c84f3f3cSopenharmony_ci	switch (to) {
1476c84f3f3cSopenharmony_ci	/* command */
1477c84f3f3cSopenharmony_ci	case PS1:
1478c84f3f3cSopenharmony_ci		/*
1479c84f3f3cSopenharmony_ci		 * Substitute ! and !! here, before substitutions are done
1480c84f3f3cSopenharmony_ci		 * so ! in expanded variables are not expanded.
1481c84f3f3cSopenharmony_ci		 * NOTE: this is not what AT&T ksh does (it does it after
1482c84f3f3cSopenharmony_ci		 * substitutions, POSIX doesn't say which is to be done.
1483c84f3f3cSopenharmony_ci		 */
1484c84f3f3cSopenharmony_ci		{
1485c84f3f3cSopenharmony_ci			struct shf *shf;
1486c84f3f3cSopenharmony_ci			char * volatile ps1;
1487c84f3f3cSopenharmony_ci			Area *saved_atemp;
1488c84f3f3cSopenharmony_ci			int saved_lineno;
1489c84f3f3cSopenharmony_ci
1490c84f3f3cSopenharmony_ci			ps1 = str_val(global("PS1"));
1491c84f3f3cSopenharmony_ci			shf = shf_sopen(NULL, strlen(ps1) * 2,
1492c84f3f3cSopenharmony_ci			    SHF_WR | SHF_DYNAMIC, NULL);
1493c84f3f3cSopenharmony_ci			while (*ps1)
1494c84f3f3cSopenharmony_ci				if (*ps1 != '!' || *++ps1 == '!')
1495c84f3f3cSopenharmony_ci					shf_putchar(*ps1++, shf);
1496c84f3f3cSopenharmony_ci				else
1497c84f3f3cSopenharmony_ci					shf_fprintf(shf, Tf_lu, s ?
1498c84f3f3cSopenharmony_ci					    (unsigned long)s->line + 1 : 0UL);
1499c84f3f3cSopenharmony_ci			ps1 = shf_sclose(shf);
1500c84f3f3cSopenharmony_ci			saved_lineno = current_lineno;
1501c84f3f3cSopenharmony_ci			if (s)
1502c84f3f3cSopenharmony_ci				current_lineno = s->line + 1;
1503c84f3f3cSopenharmony_ci			saved_atemp = ATEMP;
1504c84f3f3cSopenharmony_ci			newenv(E_ERRH);
1505c84f3f3cSopenharmony_ci			if (kshsetjmp(e->jbuf)) {
1506c84f3f3cSopenharmony_ci				prompt = safe_prompt;
1507c84f3f3cSopenharmony_ci				/*
1508c84f3f3cSopenharmony_ci				 * Don't print an error - assume it has already
1509c84f3f3cSopenharmony_ci				 * been printed. Reason is we may have forked
1510c84f3f3cSopenharmony_ci				 * to run a command and the child may be
1511c84f3f3cSopenharmony_ci				 * unwinding its stack through this code as it
1512c84f3f3cSopenharmony_ci				 * exits.
1513c84f3f3cSopenharmony_ci				 */
1514c84f3f3cSopenharmony_ci			} else {
1515c84f3f3cSopenharmony_ci				char *cp = substitute(ps1, 0);
1516c84f3f3cSopenharmony_ci				strdupx(prompt, cp, saved_atemp);
1517c84f3f3cSopenharmony_ci			}
1518c84f3f3cSopenharmony_ci			current_lineno = saved_lineno;
1519c84f3f3cSopenharmony_ci			quitenv(NULL);
1520c84f3f3cSopenharmony_ci		}
1521c84f3f3cSopenharmony_ci		break;
1522c84f3f3cSopenharmony_ci	/* command continuation */
1523c84f3f3cSopenharmony_ci	case PS2:
1524c84f3f3cSopenharmony_ci		prompt = str_val(global("PS2"));
1525c84f3f3cSopenharmony_ci		break;
1526c84f3f3cSopenharmony_ci	}
1527c84f3f3cSopenharmony_ci}
1528c84f3f3cSopenharmony_ci
1529c84f3f3cSopenharmony_ciint
1530c84f3f3cSopenharmony_cipprompt(const char *cp, int ntruncate)
1531c84f3f3cSopenharmony_ci{
1532c84f3f3cSopenharmony_ci	char delimiter = 0;
1533c84f3f3cSopenharmony_ci	bool doprint = (ntruncate != -1);
1534c84f3f3cSopenharmony_ci	bool indelimit = false;
1535c84f3f3cSopenharmony_ci	int columns = 0, lines = 0;
1536c84f3f3cSopenharmony_ci
1537c84f3f3cSopenharmony_ci	/*
1538c84f3f3cSopenharmony_ci	 * Undocumented AT&T ksh feature:
1539c84f3f3cSopenharmony_ci	 * If the second char in the prompt string is \r then the first
1540c84f3f3cSopenharmony_ci	 * char is taken to be a non-printing delimiter and any chars
1541c84f3f3cSopenharmony_ci	 * between two instances of the delimiter are not considered to
1542c84f3f3cSopenharmony_ci	 * be part of the prompt length
1543c84f3f3cSopenharmony_ci	 */
1544c84f3f3cSopenharmony_ci	if (*cp && cp[1] == '\r') {
1545c84f3f3cSopenharmony_ci		delimiter = *cp;
1546c84f3f3cSopenharmony_ci		cp += 2;
1547c84f3f3cSopenharmony_ci	}
1548c84f3f3cSopenharmony_ci	for (; *cp; cp++) {
1549c84f3f3cSopenharmony_ci		if (indelimit && *cp != delimiter)
1550c84f3f3cSopenharmony_ci			;
1551c84f3f3cSopenharmony_ci		else if (ctype(*cp, C_CR | C_LF)) {
1552c84f3f3cSopenharmony_ci			lines += columns / x_cols + ((*cp == '\n') ? 1 : 0);
1553c84f3f3cSopenharmony_ci			columns = 0;
1554c84f3f3cSopenharmony_ci		} else if (*cp == '\t') {
1555c84f3f3cSopenharmony_ci			columns = (columns | 7) + 1;
1556c84f3f3cSopenharmony_ci		} else if (*cp == '\b') {
1557c84f3f3cSopenharmony_ci			if (columns > 0)
1558c84f3f3cSopenharmony_ci				columns--;
1559c84f3f3cSopenharmony_ci		} else if (*cp == delimiter)
1560c84f3f3cSopenharmony_ci			indelimit = !indelimit;
1561c84f3f3cSopenharmony_ci		else if (UTFMODE && (rtt2asc(*cp) > 0x7F)) {
1562c84f3f3cSopenharmony_ci			const char *cp2;
1563c84f3f3cSopenharmony_ci			columns += utf_widthadj(cp, &cp2);
1564c84f3f3cSopenharmony_ci			if (doprint && (indelimit ||
1565c84f3f3cSopenharmony_ci			    (ntruncate < (x_cols * lines + columns))))
1566c84f3f3cSopenharmony_ci				shf_write(cp, cp2 - cp, shl_out);
1567c84f3f3cSopenharmony_ci			cp = cp2 - /* loop increment */ 1;
1568c84f3f3cSopenharmony_ci			continue;
1569c84f3f3cSopenharmony_ci		} else
1570c84f3f3cSopenharmony_ci			columns++;
1571c84f3f3cSopenharmony_ci		if (doprint && (*cp != delimiter) &&
1572c84f3f3cSopenharmony_ci		    (indelimit || (ntruncate < (x_cols * lines + columns))))
1573c84f3f3cSopenharmony_ci			shf_putc(*cp, shl_out);
1574c84f3f3cSopenharmony_ci	}
1575c84f3f3cSopenharmony_ci	if (doprint)
1576c84f3f3cSopenharmony_ci		shf_flush(shl_out);
1577c84f3f3cSopenharmony_ci	return (x_cols * lines + columns);
1578c84f3f3cSopenharmony_ci}
1579c84f3f3cSopenharmony_ci
1580c84f3f3cSopenharmony_ci/*
1581c84f3f3cSopenharmony_ci * Read the variable part of a ${...} expression (i.e. up to but not
1582c84f3f3cSopenharmony_ci * including the :[-+?=#%] or close-brace).
1583c84f3f3cSopenharmony_ci */
1584c84f3f3cSopenharmony_cistatic char *
1585c84f3f3cSopenharmony_ciget_brace_var(XString *wsp, char *wp)
1586c84f3f3cSopenharmony_ci{
1587c84f3f3cSopenharmony_ci	char c;
1588c84f3f3cSopenharmony_ci	enum parse_state {
1589c84f3f3cSopenharmony_ci		PS_INITIAL, PS_SAW_PERCENT, PS_SAW_HASH, PS_SAW_BANG,
1590c84f3f3cSopenharmony_ci		PS_IDENT, PS_NUMBER, PS_VAR1
1591c84f3f3cSopenharmony_ci	} state = PS_INITIAL;
1592c84f3f3cSopenharmony_ci
1593c84f3f3cSopenharmony_ci	while (/* CONSTCOND */ 1) {
1594c84f3f3cSopenharmony_ci		c = getsc();
1595c84f3f3cSopenharmony_ci		/* State machine to figure out where the variable part ends. */
1596c84f3f3cSopenharmony_ci		switch (state) {
1597c84f3f3cSopenharmony_ci		case PS_SAW_HASH:
1598c84f3f3cSopenharmony_ci			if (ctype(c, C_VAR1)) {
1599c84f3f3cSopenharmony_ci				char c2;
1600c84f3f3cSopenharmony_ci
1601c84f3f3cSopenharmony_ci				c2 = getsc();
1602c84f3f3cSopenharmony_ci				ungetsc(c2);
1603c84f3f3cSopenharmony_ci				if (ord(c2) != ORD(/*{*/ '}')) {
1604c84f3f3cSopenharmony_ci					ungetsc(c);
1605c84f3f3cSopenharmony_ci					goto out;
1606c84f3f3cSopenharmony_ci				}
1607c84f3f3cSopenharmony_ci			}
1608c84f3f3cSopenharmony_ci			goto ps_common;
1609c84f3f3cSopenharmony_ci		case PS_SAW_BANG:
1610c84f3f3cSopenharmony_ci			switch (ord(c)) {
1611c84f3f3cSopenharmony_ci			case ORD('@'):
1612c84f3f3cSopenharmony_ci			case ORD('#'):
1613c84f3f3cSopenharmony_ci			case ORD('-'):
1614c84f3f3cSopenharmony_ci			case ORD('?'):
1615c84f3f3cSopenharmony_ci				goto out;
1616c84f3f3cSopenharmony_ci			}
1617c84f3f3cSopenharmony_ci			goto ps_common;
1618c84f3f3cSopenharmony_ci		case PS_INITIAL:
1619c84f3f3cSopenharmony_ci			switch (ord(c)) {
1620c84f3f3cSopenharmony_ci			case ORD('%'):
1621c84f3f3cSopenharmony_ci				state = PS_SAW_PERCENT;
1622c84f3f3cSopenharmony_ci				goto next;
1623c84f3f3cSopenharmony_ci			case ORD('#'):
1624c84f3f3cSopenharmony_ci				state = PS_SAW_HASH;
1625c84f3f3cSopenharmony_ci				goto next;
1626c84f3f3cSopenharmony_ci			case ORD('!'):
1627c84f3f3cSopenharmony_ci				state = PS_SAW_BANG;
1628c84f3f3cSopenharmony_ci				goto next;
1629c84f3f3cSopenharmony_ci			}
1630c84f3f3cSopenharmony_ci			/* FALLTHROUGH */
1631c84f3f3cSopenharmony_ci		case PS_SAW_PERCENT:
1632c84f3f3cSopenharmony_ci ps_common:
1633c84f3f3cSopenharmony_ci			if (ctype(c, C_ALPHX))
1634c84f3f3cSopenharmony_ci				state = PS_IDENT;
1635c84f3f3cSopenharmony_ci			else if (ctype(c, C_DIGIT))
1636c84f3f3cSopenharmony_ci				state = PS_NUMBER;
1637c84f3f3cSopenharmony_ci			else if (ctype(c, C_VAR1))
1638c84f3f3cSopenharmony_ci				state = PS_VAR1;
1639c84f3f3cSopenharmony_ci			else
1640c84f3f3cSopenharmony_ci				goto out;
1641c84f3f3cSopenharmony_ci			break;
1642c84f3f3cSopenharmony_ci		case PS_IDENT:
1643c84f3f3cSopenharmony_ci			if (!ctype(c, C_ALNUX)) {
1644c84f3f3cSopenharmony_ci				if (ord(c) == ORD('[')) {
1645c84f3f3cSopenharmony_ci					char *tmp, *p;
1646c84f3f3cSopenharmony_ci
1647c84f3f3cSopenharmony_ci					if (!arraysub(&tmp))
1648c84f3f3cSopenharmony_ci						yyerror("missing ]");
1649c84f3f3cSopenharmony_ci					*wp++ = c;
1650c84f3f3cSopenharmony_ci					p = tmp;
1651c84f3f3cSopenharmony_ci					while (*p) {
1652c84f3f3cSopenharmony_ci						Xcheck(*wsp, wp);
1653c84f3f3cSopenharmony_ci						*wp++ = *p++;
1654c84f3f3cSopenharmony_ci					}
1655c84f3f3cSopenharmony_ci					afree(tmp, ATEMP);
1656c84f3f3cSopenharmony_ci					/* the ] */
1657c84f3f3cSopenharmony_ci					c = getsc();
1658c84f3f3cSopenharmony_ci				}
1659c84f3f3cSopenharmony_ci				goto out;
1660c84f3f3cSopenharmony_ci			}
1661c84f3f3cSopenharmony_ci next:
1662c84f3f3cSopenharmony_ci			break;
1663c84f3f3cSopenharmony_ci		case PS_NUMBER:
1664c84f3f3cSopenharmony_ci			if (!ctype(c, C_DIGIT))
1665c84f3f3cSopenharmony_ci				goto out;
1666c84f3f3cSopenharmony_ci			break;
1667c84f3f3cSopenharmony_ci		case PS_VAR1:
1668c84f3f3cSopenharmony_ci			goto out;
1669c84f3f3cSopenharmony_ci		}
1670c84f3f3cSopenharmony_ci		Xcheck(*wsp, wp);
1671c84f3f3cSopenharmony_ci		*wp++ = c;
1672c84f3f3cSopenharmony_ci	}
1673c84f3f3cSopenharmony_ci out:
1674c84f3f3cSopenharmony_ci	/* end of variable part */
1675c84f3f3cSopenharmony_ci	*wp++ = '\0';
1676c84f3f3cSopenharmony_ci	ungetsc(c);
1677c84f3f3cSopenharmony_ci	return (wp);
1678c84f3f3cSopenharmony_ci}
1679c84f3f3cSopenharmony_ci
1680c84f3f3cSopenharmony_ci/*
1681c84f3f3cSopenharmony_ci * Save an array subscript - returns true if matching bracket found, false
1682c84f3f3cSopenharmony_ci * if eof or newline was found.
1683c84f3f3cSopenharmony_ci * (Returned string double null terminated)
1684c84f3f3cSopenharmony_ci */
1685c84f3f3cSopenharmony_cistatic bool
1686c84f3f3cSopenharmony_ciarraysub(char **strp)
1687c84f3f3cSopenharmony_ci{
1688c84f3f3cSopenharmony_ci	XString ws;
1689c84f3f3cSopenharmony_ci	char *wp, c;
1690c84f3f3cSopenharmony_ci	/* we are just past the initial [ */
1691c84f3f3cSopenharmony_ci	unsigned int depth = 1;
1692c84f3f3cSopenharmony_ci
1693c84f3f3cSopenharmony_ci	Xinit(ws, wp, 32, ATEMP);
1694c84f3f3cSopenharmony_ci
1695c84f3f3cSopenharmony_ci	do {
1696c84f3f3cSopenharmony_ci		c = getsc();
1697c84f3f3cSopenharmony_ci		Xcheck(ws, wp);
1698c84f3f3cSopenharmony_ci		*wp++ = c;
1699c84f3f3cSopenharmony_ci		if (ord(c) == ORD('['))
1700c84f3f3cSopenharmony_ci			depth++;
1701c84f3f3cSopenharmony_ci		else if (ord(c) == ORD(']'))
1702c84f3f3cSopenharmony_ci			depth--;
1703c84f3f3cSopenharmony_ci	} while (depth > 0 && c && c != '\n');
1704c84f3f3cSopenharmony_ci
1705c84f3f3cSopenharmony_ci	*wp++ = '\0';
1706c84f3f3cSopenharmony_ci	*strp = Xclose(ws, wp);
1707c84f3f3cSopenharmony_ci
1708c84f3f3cSopenharmony_ci	return (tobool(depth == 0));
1709c84f3f3cSopenharmony_ci}
1710c84f3f3cSopenharmony_ci
1711c84f3f3cSopenharmony_ci/* Unget a char: handles case when we are already at the start of the buffer */
1712c84f3f3cSopenharmony_cistatic void
1713c84f3f3cSopenharmony_ciungetsc(int c)
1714c84f3f3cSopenharmony_ci{
1715c84f3f3cSopenharmony_ci	struct sretrace_info *rp = retrace_info;
1716c84f3f3cSopenharmony_ci
1717c84f3f3cSopenharmony_ci	if (backslash_skip)
1718c84f3f3cSopenharmony_ci		backslash_skip--;
1719c84f3f3cSopenharmony_ci	/* Don't unget EOF... */
1720c84f3f3cSopenharmony_ci	if (source->str == null && c == '\0')
1721c84f3f3cSopenharmony_ci		return;
1722c84f3f3cSopenharmony_ci	while (rp) {
1723c84f3f3cSopenharmony_ci		if (Xlength(rp->xs, rp->xp))
1724c84f3f3cSopenharmony_ci			rp->xp--;
1725c84f3f3cSopenharmony_ci		rp = rp->next;
1726c84f3f3cSopenharmony_ci	}
1727c84f3f3cSopenharmony_ci	ungetsc_i(c);
1728c84f3f3cSopenharmony_ci}
1729c84f3f3cSopenharmony_cistatic void
1730c84f3f3cSopenharmony_ciungetsc_i(int c)
1731c84f3f3cSopenharmony_ci{
1732c84f3f3cSopenharmony_ci	if (source->str > source->start)
1733c84f3f3cSopenharmony_ci		source->str--;
1734c84f3f3cSopenharmony_ci	else {
1735c84f3f3cSopenharmony_ci		Source *s;
1736c84f3f3cSopenharmony_ci
1737c84f3f3cSopenharmony_ci		s = pushs(SREREAD, source->areap);
1738c84f3f3cSopenharmony_ci		s->ugbuf[0] = c; s->ugbuf[1] = '\0';
1739c84f3f3cSopenharmony_ci		s->start = s->str = s->ugbuf;
1740c84f3f3cSopenharmony_ci		s->next = source;
1741c84f3f3cSopenharmony_ci		source = s;
1742c84f3f3cSopenharmony_ci	}
1743c84f3f3cSopenharmony_ci}
1744c84f3f3cSopenharmony_ci
1745c84f3f3cSopenharmony_ci
1746c84f3f3cSopenharmony_ci/* Called to get a char that isn't a \newline sequence. */
1747c84f3f3cSopenharmony_cistatic int
1748c84f3f3cSopenharmony_cigetsc_bn(void)
1749c84f3f3cSopenharmony_ci{
1750c84f3f3cSopenharmony_ci	int c, c2;
1751c84f3f3cSopenharmony_ci
1752c84f3f3cSopenharmony_ci	if (ignore_backslash_newline)
1753c84f3f3cSopenharmony_ci		return (o_getsc_u());
1754c84f3f3cSopenharmony_ci
1755c84f3f3cSopenharmony_ci	if (backslash_skip == 1) {
1756c84f3f3cSopenharmony_ci		backslash_skip = 2;
1757c84f3f3cSopenharmony_ci		return (o_getsc_u());
1758c84f3f3cSopenharmony_ci	}
1759c84f3f3cSopenharmony_ci
1760c84f3f3cSopenharmony_ci	backslash_skip = 0;
1761c84f3f3cSopenharmony_ci
1762c84f3f3cSopenharmony_ci	while (/* CONSTCOND */ 1) {
1763c84f3f3cSopenharmony_ci		c = o_getsc_u();
1764c84f3f3cSopenharmony_ci		if (c == '\\') {
1765c84f3f3cSopenharmony_ci			if ((c2 = o_getsc_u()) == '\n')
1766c84f3f3cSopenharmony_ci				/* ignore the \newline; get the next char... */
1767c84f3f3cSopenharmony_ci				continue;
1768c84f3f3cSopenharmony_ci			ungetsc_i(c2);
1769c84f3f3cSopenharmony_ci			backslash_skip = 1;
1770c84f3f3cSopenharmony_ci		}
1771c84f3f3cSopenharmony_ci		return (c);
1772c84f3f3cSopenharmony_ci	}
1773c84f3f3cSopenharmony_ci}
1774c84f3f3cSopenharmony_ci
1775c84f3f3cSopenharmony_civoid
1776c84f3f3cSopenharmony_ciyyskiputf8bom(void)
1777c84f3f3cSopenharmony_ci{
1778c84f3f3cSopenharmony_ci	int c;
1779c84f3f3cSopenharmony_ci
1780c84f3f3cSopenharmony_ci	if (rtt2asc((c = o_getsc_u())) != 0xEF) {
1781c84f3f3cSopenharmony_ci		ungetsc_i(c);
1782c84f3f3cSopenharmony_ci		return;
1783c84f3f3cSopenharmony_ci	}
1784c84f3f3cSopenharmony_ci	if (rtt2asc((c = o_getsc_u())) != 0xBB) {
1785c84f3f3cSopenharmony_ci		ungetsc_i(c);
1786c84f3f3cSopenharmony_ci		ungetsc_i(asc2rtt(0xEF));
1787c84f3f3cSopenharmony_ci		return;
1788c84f3f3cSopenharmony_ci	}
1789c84f3f3cSopenharmony_ci	if (rtt2asc((c = o_getsc_u())) != 0xBF) {
1790c84f3f3cSopenharmony_ci		ungetsc_i(c);
1791c84f3f3cSopenharmony_ci		ungetsc_i(asc2rtt(0xBB));
1792c84f3f3cSopenharmony_ci		ungetsc_i(asc2rtt(0xEF));
1793c84f3f3cSopenharmony_ci		return;
1794c84f3f3cSopenharmony_ci	}
1795c84f3f3cSopenharmony_ci	UTFMODE |= 8;
1796c84f3f3cSopenharmony_ci}
1797c84f3f3cSopenharmony_ci
1798c84f3f3cSopenharmony_cistatic Lex_state *
1799c84f3f3cSopenharmony_cipush_state_i(State_info *si, Lex_state *old_end)
1800c84f3f3cSopenharmony_ci{
1801c84f3f3cSopenharmony_ci	Lex_state *news = alloc2(STATE_BSIZE, sizeof(Lex_state), ATEMP);
1802c84f3f3cSopenharmony_ci
1803c84f3f3cSopenharmony_ci	news[0].ls_base = old_end;
1804c84f3f3cSopenharmony_ci	si->base = &news[0];
1805c84f3f3cSopenharmony_ci	si->end = &news[STATE_BSIZE];
1806c84f3f3cSopenharmony_ci	return (&news[1]);
1807c84f3f3cSopenharmony_ci}
1808c84f3f3cSopenharmony_ci
1809c84f3f3cSopenharmony_cistatic Lex_state *
1810c84f3f3cSopenharmony_cipop_state_i(State_info *si, Lex_state *old_end)
1811c84f3f3cSopenharmony_ci{
1812c84f3f3cSopenharmony_ci	Lex_state *old_base = si->base;
1813c84f3f3cSopenharmony_ci
1814c84f3f3cSopenharmony_ci	si->base = old_end->ls_base - STATE_BSIZE;
1815c84f3f3cSopenharmony_ci	si->end = old_end->ls_base;
1816c84f3f3cSopenharmony_ci
1817c84f3f3cSopenharmony_ci	afree(old_base, ATEMP);
1818c84f3f3cSopenharmony_ci
1819c84f3f3cSopenharmony_ci	return (si->base + STATE_BSIZE - 1);
1820c84f3f3cSopenharmony_ci}
1821