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