1 /* $OpenBSD: lex.c,v 1.51 2015/09/10 22:48:58 nicm Exp $ */
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5 * 2011, 2012, 2013, 2014, 2015, 2016, 2017
6 * mirabilos <m@mirbsd.org>
8 * Provided that these terms and disclaimer and all copyright notices
9 * are retained or reproduced in an accompanying document, permission
10 * is granted to deal in this work without restriction, including un-
11 * limited rights to use, publicly perform, distribute, sell, modify,
12 * merge, give away, or sublicence.
14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15 * the utmost extent permitted by applicable law, neither express nor
16 * implied; without malicious intent or gross negligence. In no event
17 * may a licensor, author or contributor be held liable for indirect,
18 * direct, other damage, loss, or other issues arising in any way out
19 * of dealing in the work, even if advised of the possibility of such
20 * damage or existence of a defect, except proven that it results out
21 * of said person's immediate fault when using the work as intended.
26 __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.234 2017/04/06 01:59:55 tg Exp $");
29 * states while lexing word
31 #define SBASE 0 /* outside any lexical constructs */
32 #define SWORD 1 /* implicit quoting for substitute() */
33 #define SLETPAREN 2 /* inside (( )), implicit quoting */
34 #define SSQUOTE 3 /* inside '' */
35 #define SDQUOTE 4 /* inside "" */
36 #define SEQUOTE 5 /* inside $'' */
37 #define SBRACE 6 /* inside ${} */
38 #define SQBRACE 7 /* inside "${}" */
39 #define SBQUOTE 8 /* inside `` */
40 #define SASPAREN 9 /* inside $(( )) */
41 #define SHEREDELIM 10 /* parsing << or <<- delimiter */
42 #define SHEREDQUOTE 11 /* parsing " in << or <<- delimiter */
43 #define SPATTERN 12 /* parsing *(...|...) pattern (*+?@!) */
44 #define SADELIM 13 /* like SBASE, looking for delimiter */
45 #define STBRACEKORN 14 /* parsing ${...[#%]...} !FSH */
46 #define STBRACEBOURNE 15 /* parsing ${...[#%]...} FSH */
47 #define SINVALID 255 /* invalid state */
49 struct sretrace_info {
50 struct sretrace_info *next;
56 * Structure to keep track of the lexing state and the various pieces of info
57 * needed for each particular state.
59 typedef struct lex_state {
61 /* point to the next state block */
62 struct lex_state *base;
63 /* marks start of state output in output string */
65 /* SBQUOTE: true if in double quotes: "`...`" */
66 /* SEQUOTE: got NUL, ignore rest of string */
68 /* SADELIM information */
70 /* character to search for */
71 unsigned char delimiter;
72 /* max. number of delimiters */
76 /* count open parentheses */
78 /* type of this state */
81 #define ls_base u.base
82 #define ls_start u.start
83 #define ls_bool u.abool
84 #define ls_adelim u.adelim
91 static void readhere(struct ioword *);
92 static void ungetsc(int);
93 static void ungetsc_i(int);
94 static int getsc_uu(void);
95 static void getsc_line(Source *);
96 static int getsc_bn(void);
97 static int getsc_i(void);
98 static char *get_brace_var(XString *, char *);
99 static bool arraysub(char **);
100 static void gethere(void);
101 static Lex_state *push_state_i(State_info *, Lex_state *);
102 static Lex_state *pop_state_i(State_info *, Lex_state *);
104 static int backslash_skip;
105 static int ignore_backslash_newline;
107 /* optimised getsc_bn() */
108 #define o_getsc() (*source->str != '\0' && *source->str != '\\' && \
109 !backslash_skip ? *source->str++ : getsc_bn())
110 /* optimised getsc_uu() */
111 #define o_getsc_u() ((*source->str != '\0') ? *source->str++ : getsc_uu())
114 #define o_getsc_r(carg) \
116 struct sretrace_info *rp = retrace_info; \
119 Xcheck(rp->xs, rp->xp); \
130 o_getsc_r(o_getsc());
133 #if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
134 #define getsc getsc_i
136 static int getsc_r(int);
144 #define getsc() getsc_r(o_getsc())
147 #define STATE_BSIZE 8
149 #define PUSH_STATE(s) do { \
150 if (++statep == state_info.end) \
151 statep = push_state_i(&state_info, statep); \
152 state = statep->type = (s); \
153 } while (/* CONSTCOND */ 0)
155 #define POP_STATE() do { \
156 if (--statep == state_info.base) \
157 statep = pop_state_i(&state_info, statep); \
158 state = statep->type; \
159 } while (/* CONSTCOND */ 0)
161 #define PUSH_SRETRACE(s) do { \
162 struct sretrace_info *ri; \
165 statep->ls_start = Xsavepos(ws, wp); \
166 ri = alloc(sizeof(struct sretrace_info), ATEMP); \
167 Xinit(ri->xs, ri->xp, 64, ATEMP); \
168 ri->next = retrace_info; \
170 } while (/* CONSTCOND */ 0)
172 #define POP_SRETRACE() do { \
173 wp = Xrestpos(ws, wp, statep->ls_start); \
174 *retrace_info->xp = '\0'; \
175 sp = Xstring(retrace_info->xs, retrace_info->xp); \
176 dp = (void *)retrace_info; \
177 retrace_info = retrace_info->next; \
180 } while (/* CONSTCOND */ 0)
185 * tokens are not regular expressions, they are LL(1).
186 * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
187 * hence the state stack. Note "$(...)" are now parsed recursively.
193 Lex_state states[STATE_BSIZE], *statep, *s2, *base;
194 State_info state_info;
197 XString ws; /* expandable output word */
198 char *wp; /* output word pointer */
202 states[0].type = SINVALID;
203 states[0].ls_base = NULL;
205 state_info.base = states;
206 state_info.end = &state_info.base[STATE_BSIZE];
208 Xinit(ws, wp, 64, ATEMP);
211 ignore_backslash_newline = 0;
215 else if (cf & LETEXPR) {
216 /* enclose arguments in (double) quotes */
222 state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
223 while ((c = getsc()) == ' ' || c == '\t')
226 ignore_backslash_newline++;
227 while ((c = getsc()) != '\0' && c != '\n')
229 ignore_backslash_newline--;
233 if (source->flags & SF_ALIAS) {
234 /* trailing ' ' in alias definition */
235 source->flags &= ~SF_ALIAS;
236 /* POSIX: trailing space only counts if parsing simple cmd */
237 if (!Flag(FPOSIX) || (cf & CMDWORD))
241 /* Initial state: one of SWORD SLETPAREN SHEREDELIM SBASE */
242 statep->type = state;
244 /* collect non-special or quoted characters to form word */
245 while (!((c = getsc()) == 0 ||
246 ((state == SBASE || state == SHEREDELIM) && ctype(c, C_LEX1)))) {
247 if (state == SBASE &&
248 subshell_nesting_type == /*{*/ '}' &&
250 /* possibly end ${ :;} */
259 else if (statep->nparen == 0 && (c == /*{*/ '}' ||
260 c == (int)statep->ls_adelim.delimiter)) {
263 if (c == /*{*/ '}' || --statep->ls_adelim.num == 0)
271 if (c == '[' && (cf & CMDASN)) {
274 if (is_wdvarname(Xstring(ws, wp), false)) {
277 if (arraysub(&tmp)) {
280 for (p = tmp; *p; ) {
303 Sbase1: /* includes *(...|...) pattern (*+?@!) */
304 if (c == '*' || c == '@' || c == '+' || c == '?' ||
307 if (c2 == '(' /*)*/ ) {
310 PUSH_STATE(SPATTERN);
316 Sbase2: /* doesn't include *(...|...) pattern (*+?@!) */
321 /* trailing \ is lost */
327 open_ssquote_unless_heredoc:
331 ignore_backslash_newline++;
341 * processing of dollar sign belongs into
342 * Subst, except for those which can open
343 * a string: $'…' and $"…"
379 /* trailing \ is lost */
391 if (c == '(') /*)*/ {
393 if (c == '(') /*)*/ {
395 PUSH_SRETRACE(SASPAREN);
397 *retrace_info->xp++ = '(';
410 } else if (c == '{') /*}*/ {
411 if ((c = getsc()) == '|') {
418 } else if (ctype(c, C_IFSWS)) {
421 * "command" substitution
429 wp = get_brace_var(&ws, wp);
431 /* allow :# and :% (ksh88 compat) */
443 statep->ls_adelim.delimiter = ':';
444 statep->ls_adelim.num = 1;
447 } else if (ksh_isdigit(c) ||
448 c == '('/*)*/ || c == ' ' ||
451 /* substring subst. */
459 statep->ls_adelim.delimiter = ':';
460 statep->ls_adelim.num = 2;
464 } else if (c == '/') {
469 if ((c = getsc()) == '/') {
476 statep->ls_adelim.delimiter = '/';
477 statep->ls_adelim.num = 1;
480 } else if (c == '@') {
485 goto parse_adelim_slash;
489 * If this is a trim operation,
490 * treat (,|,) specially in STBRACE.
492 if (ksh_issubop2(c)) {
495 PUSH_STATE(STBRACEBOURNE);
497 PUSH_STATE(STBRACEKORN);
500 if (state == SDQUOTE ||
506 } else if (ksh_isalphx(c)) {
513 } while (ksh_isalnux(c));
518 } else if (ctype(c, C_VAR1 | C_DIGIT)) {
537 * We need to know whether we are within double
538 * quotes in order to translate \" to " within
539 * "…`…\"…`…" because, unlike for COMSUBs, the
540 * outer double quoteing changes the backslash
541 * meaning for the inside. For more details:
542 * http://austingroupbugs.net/view.php?id=1015
544 statep->ls_bool = false;
546 base = state_info.base;
547 while (/* CONSTCOND */ 1) {
548 for (; s2 != base; s2--) {
549 if (s2->type == SDQUOTE) {
550 statep->ls_bool = true;
556 if (!(s2 = s2->ls_base))
558 base = s2-- - STATE_BSIZE;
579 ignore_backslash_newline--;
580 } else if (c == '\\') {
581 if ((c2 = unbksl(true, getsc_i, ungetsc)) == -1)
584 statep->ls_bool = true;
585 if (!statep->ls_bool) {
588 if ((unsigned int)c2 < 0x100) {
592 cz = utf_wctomb(ts, c2 - 0x100);
601 } else if (!statep->ls_bool) {
610 if ((cf & HEREDOC) || state == SQBRACE)
613 ignore_backslash_newline--;
634 if (statep->nparen == 1) {
638 if ((c2 = getsc()) == /*(*/ ')') {
641 memcpy(wp, sp + 1, cz);
651 * mismatched parenthesis -
652 * assume we were really
653 * parsing a $(...) expression
666 /* reuse existing state machine */
672 * perform POSIX "quote removal" if the back-
673 * slash is "special", i.e. same cases as the
674 * {case '\\':} in Subst: plus closing brace;
675 * in mksh code "quote removal" on '\c' means
676 * write QCHAR+c, otherwise CHAR+\+CHAR+c are
677 * emitted (in heredocquote:)
679 if ((c = getsc()) == '"' || c == '\\' ||
680 c == '$' || c == '`' || c == /*{*/'}')
688 goto open_ssquote_unless_heredoc;
695 goto subst_dollar_ex;
698 else if (c != /*{*/ '}')
705 /* Same as SBASE, except (,|,) treated specially */
713 PUSH_STATE(SPATTERN);
714 } else /* FALLTHROUGH */
716 if (c == /*{*/ '}') {
728 } else if (c == '\\') {
729 switch (c = getsc()) {
731 /* trailing \ is lost */
739 if (statep->ls_bool) {
757 /* LETEXPR: (( ... )) */
759 if (c == /*(*/ ')') {
760 if (statep->nparen > 0)
762 else if ((c2 = getsc()) == /*(*/ ')') {
772 * mismatched parenthesis -
773 * assume we were really
774 * parsing a (...) expression
777 sp = Xstring(ws, wp);
778 dp = wdstrip(sp + 1, WDS_TPUTS);
779 s = pushs(SREREAD, source->areap);
780 s->start = s->str = s->u.freeme = dp;
788 * parentheses inside quotes and
789 * backslashes are lost, but AT&T ksh
790 * doesn't count them either
795 /* << or <<- delimiter */
798 * here delimiters need a special case since
799 * $ and `...` are not to be treated specially
804 /* trailing \ is lost */
810 goto open_ssquote_unless_heredoc;
812 if ((c2 = getsc()) == '\'') {
815 ignore_backslash_newline++;
817 statep->ls_bool = false;
819 } else if (c2 == '"') {
822 PUSH_SRETRACE(SHEREDQUOTE);
833 /* " in << or <<- delimiter */
839 /* remove the trailing double quote */
841 /* store the quoted string */
843 XcheckN(ws, wp, (dp - sp) * 2);
845 while ((c = *dp++)) {
847 switch ((c = *dp++)) {
864 state = statep->type = SHEREDELIM;
867 /* in *(...|...) pattern (*+?@!) */
869 if (c == /*(*/ ')') {
872 } else if (c == '|') {
874 } else if (c == '(') {
878 PUSH_STATE(SPATTERN);
886 if (statep != &states[1])
887 /* XXX figure out what is missing */
888 yyerror("no closing quote");
890 /* This done to avoid tests for SHEREDELIM wherever SBASE tested */
891 if (state == SHEREDELIM)
894 dp = Xstring(ws, wp);
895 if (state == SBASE && (
896 (c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
897 c == '<' || c == '>') && ((c2 = Xlength(ws, wp)) == 0 ||
898 (c2 == 2 && dp[0] == CHAR && ksh_isdigit(dp[1])))) {
899 struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
901 iop->unit = c2 == 2 ? ksh_numdig(dp[1]) : c == '<' ? 0 : 1;
904 if ((c2 = getsc()) != '>') {
909 iop->ioflag = IOBASH;
914 /* <<, >>, <> are ok, >< is not */
915 if (c == c2 || (c == '<' && c2 == '>')) {
916 iop->ioflag |= c == c2 ?
917 (c == '>' ? IOCAT : IOHERE) : IORDWR;
918 if (iop->ioflag == IOHERE) {
919 if ((c2 = getsc()) == '-')
920 iop->ioflag |= IOSKIP;
922 iop->ioflag |= IOHERESTR;
926 } else if (c2 == '&')
927 iop->ioflag |= IODUP | (c == '<' ? IORDUP : 0);
929 iop->ioflag |= c == '>' ? IOWRITE : IOREAD;
930 if (c == '>' && c2 == '|')
931 iop->ioflag |= IOCLOB;
947 if (wp == dp && state == SBASE) {
950 /* no word, process LEX1 character */
951 if ((c == '|') || (c == '&') || (c == ';') || (c == '('/*)*/)) {
952 if ((c2 = getsc()) == c)
953 c = (c == ';') ? BREAK :
955 (c == '&') ? LOGAND :
956 /* c == '(' ) */ MDPAREN;
957 else if (c == '|' && c2 == '&')
959 else if (c == ';' && c2 == '|')
961 else if (c == ';' && c2 == '&')
967 if ((c2 = getsc()) == '&')
973 } else if (c == '\n') {
981 } else if (c == '\0' && !(cf & HEREDELIM)) {
982 struct ioword **p = heres;
985 if ((*p)->ioflag & IOHERESTR)
988 /* ksh -c 'cat <<EOF' can cause this */
990 evalstr((*p)->delim, 0));
997 yylval.cp = Xclose(ws, wp);
998 if (state == SWORD || state == SLETPAREN
1002 /* unget terminator */
1006 * note: the alias-vs-function code below depends on several
1007 * interna: starting from here, source->str is not modified;
1008 * the way getsc() and ungetsc() operate; etc.
1011 /* copy word to unprefixed string ident */
1014 while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
1017 /* word is not unquoted, or space ran out */
1019 /* make sure the ident array stays NUL padded */
1020 memset(dp, 0, (ident + IDENT) - dp + 1);
1022 if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
1024 uint32_t h = hash(ident);
1026 if ((cf & KEYWORD) && (p = ktsearch(&keywords, ident, h)) &&
1027 (!(cf & ESACONLY) || p->val.i == ESAC ||
1028 p->val.i == /*{*/ '}')) {
1029 afree(yylval.cp, ATEMP);
1032 if ((cf & ALIAS) && (p = ktsearch(&aliases, ident, h)) &&
1033 (p->flag & ISSET)) {
1035 * this still points to the same character as the
1036 * ungetsc'd terminator from above
1038 const char *cp = source->str;
1040 /* prefer POSIX but not Korn functions over aliases */
1041 while (*cp == ' ' || *cp == '\t')
1043 * this is like getsc() without skipping
1044 * over Source boundaries (including not
1045 * parsing ungetsc'd characters that got
1046 * pushed into an SREREAD) which is what
1047 * we want here anyway: find out whether
1048 * the alias name is followed by a POSIX
1049 * function definition
1052 /* prefer functions over aliases */
1053 if (cp[0] != '(' || cp[1] != ')') {
1056 while (s && (s->flags & SF_HASALIAS))
1061 /* push alias expansion */
1062 s = pushs(SALIAS, source->areap);
1063 s->start = s->str = p->val.s;
1065 s->flags |= SF_HASALIAS;
1066 s->line = source->line;
1068 if (source->type == SEOF) {
1069 /* prevent infinite recursion at EOS */
1071 source->flags |= SF_HASALIAS;
1074 afree(yylval.cp, ATEMP);
1078 } else if (*ident == '\0') {
1079 /* retain typeset et al. even when quoted */
1080 struct tbl *tt = get_builtin((dp = wdstrip(yylval.cp, 0)));
1081 uint32_t flag = tt ? tt->flag : 0;
1083 if (flag & (DECL_UTIL | DECL_FWDR))
1084 strlcpy(ident, dp, sizeof(ident));
1096 for (p = heres; p < herep; p++)
1097 if (!((*p)->ioflag & IOHERESTR))
1103 * read "<<word" text into temp file
1107 readhere(struct ioword *iop)
1110 const char *eof, *eofp;
1115 eof = evalstr(iop->delim, 0);
1117 if (!(iop->ioflag & IOEVAL))
1118 ignore_backslash_newline++;
1120 Xinit(xs, xp, 256, ATEMP);
1123 /* beginning of line */
1125 xpos = Xsavepos(xs, xp);
1126 if (iop->ioflag & IOSKIP) {
1127 /* skip over leading tabs */
1128 while ((c = getsc()) == '\t')
1130 goto heredoc_parse_char;
1135 /* compare with here document marker */
1137 /* end of here document marker, what to do? */
1140 if (!subshell_nesting_type)
1142 * not allowed outside $(...) or (...)
1146 /* allow $(...) or (...) to close here */
1151 * Allow EOF here to commands without trailing
1152 * newlines (mksh -c '...') will work as well.
1155 /* Newline terminates here document marker */
1156 goto heredoc_found_terminator;
1158 } else if (c == *eofp++)
1159 /* store; then read and compare next character */
1160 goto heredoc_store_and_loop;
1161 /* nope, mismatch; read until end of line */
1164 /* oops, reached EOF */
1165 yyerror(Tf_heredoc, eof);
1166 /* store character */
1169 /* read next character */
1172 /* we read a newline as last character */
1173 heredoc_store_and_loop:
1174 /* store character */
1178 goto heredoc_read_line;
1179 goto heredoc_read_char;
1181 heredoc_found_terminator:
1182 /* jump back to saved beginning of line */
1183 xp = Xrestpos(xs, xp, xpos);
1184 /* terminate, close and store */
1186 iop->heredoc = Xclose(xs, xp);
1188 if (!(iop->ioflag & IOEVAL))
1189 ignore_backslash_newline--;
1193 yyerror(const char *fmt, ...)
1197 /* pop aliases and re-reads */
1198 while (source->type == SALIAS || source->type == SREREAD)
1199 source = source->next;
1200 /* zap pending input */
1205 shf_vfprintf(shl_out, fmt, va);
1206 shf_putc('\n', shl_out);
1212 * input for yylex with alias expansion
1216 pushs(int type, Area *areap)
1220 s = alloc(sizeof(Source), areap);
1221 memset(s, 0, sizeof(Source));
1225 if (type == SFILE || type == SSTDIN)
1226 XinitN(s->xs, 256, s->areap);
1236 while ((c = *s->str++) == 0) {
1237 /* return 0 for EOF by default */
1253 case SSTRINGCMDLINE:
1257 s->start = s->str = *s->u.strv++;
1262 if (*s->u.strv == NULL) {
1263 s->start = s->str = "\n";
1266 s->start = s->str = T1space;
1272 if (s->flags & SF_ALIASEND) {
1273 /* pass on an unused SF_ALIAS flag */
1275 source->flags |= s->flags & SF_ALIAS;
1277 } else if (*s->u.tblp->val.s &&
1278 (c = strnul(s->u.tblp->val.s)[-1], ksh_isspace(c))) {
1279 /* pop source stack */
1280 source = s = s->next;
1282 * Note that this alias ended with a
1283 * space, enabling alias expansion on
1284 * the following word.
1286 s->flags |= SF_ALIAS;
1289 * At this point, we need to keep the current
1290 * alias in the source list so recursive
1291 * aliases can be detected and we also need to
1292 * return the next character. Do this by
1293 * temporarily popping the alias to get the
1294 * next character and then put it back in the
1295 * source list with the SF_ALIASEND flag set.
1297 /* pop source stack */
1299 source->flags |= s->flags & SF_ALIAS;
1302 s->flags |= SF_ALIASEND;
1303 s->ugbuf[0] = c; s->ugbuf[1] = '\0';
1304 s->start = s->str = s->ugbuf;
1309 /* avoid reading EOF twice */
1317 if (s->start != s->ugbuf)
1319 afree(s->u.freeme, ATEMP);
1320 source = s = s->next;
1323 if (s->str == NULL) {
1325 s->start = s->str = null;
1328 if (s->flags & SF_ECHO) {
1329 shf_puts(s->str, shl_out);
1337 getsc_line(Source *s)
1339 char *xp = Xstring(s->xs, xp), *cp;
1340 bool interactive = Flag(FTALKING) && s->type == SSTDIN;
1341 bool have_tty = tobool(interactive && (s->flags & SF_TTY));
1343 /* Done here to ensure nothing odd happens when a timeout occurs */
1344 XcheckN(s->xs, xp, LINE);
1346 s->start = s->str = xp;
1348 if (have_tty && ksh_tmout) {
1349 ksh_tmout_state = TMOUT_READING;
1353 if (cur_prompt == PS1)
1354 histsave(&s->line, NULL, HIST_FLUSH, true);
1357 #ifndef MKSH_NO_CMDLINE_EDITING
1362 Flag(FEMACS) || Flag(FGMACS))) {
1379 while (/* CONSTCOND */ 1) {
1380 char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
1382 if (!p && shf_error(s->u.shf) &&
1383 shf_errno(s->u.shf) == EINTR) {
1384 shf_clearerr(s->u.shf);
1389 if (!p || (xp = p, xp[-1] == '\n'))
1391 /* double buffer size */
1392 /* move past NUL so doubling works... */
1394 XcheckN(s->xs, xp, Xlength(s->xs, xp));
1395 /* ...and move back again */
1399 * flush any unwanted input so other programs/builtins
1400 * can read it. Not very optimal, but less error prone
1401 * than flushing else where, dealing with redirections,
1403 * TODO: reduce size of shf buffer (~128?) if SSTDIN
1405 if (s->type == SSTDIN)
1406 shf_flush(s->u.shf);
1409 * XXX: temporary kludge to restore source after a
1410 * trap may have been executed.
1413 if (have_tty && ksh_tmout) {
1414 ksh_tmout_state = TMOUT_EXECUTING;
1417 cp = Xstring(s->xs, xp);
1419 s->start = s->str = cp;
1420 strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
1421 /* Note: if input is all nulls, this is not eof */
1422 if (Xlength(s->xs, xp) == 0) {
1424 if (s->type == SFILE)
1425 shf_fdclose(s->u.shf);
1427 } else if (interactive && *s->str) {
1428 if (cur_prompt != PS1)
1429 histsave(&s->line, s->str, HIST_APPEND, true);
1430 else if (!ctype(*s->str, C_IFS | C_IFSWS))
1431 histsave(&s->line, s->str, HIST_QUEUE, true);
1432 #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
1434 goto check_for_sole_return;
1435 } else if (interactive && cur_prompt == PS1) {
1436 check_for_sole_return:
1437 cp = Xstring(s->xs, xp);
1438 while (*cp && ctype(*cp, C_IFSWS))
1441 histsave(&s->line, NULL, HIST_FLUSH, true);
1447 set_prompt(PS2, NULL);
1451 set_prompt(int to, Source *s)
1453 cur_prompt = (uint8_t)to;
1459 * Substitute ! and !! here, before substitutions are done
1460 * so ! in expanded variables are not expanded.
1461 * NOTE: this is not what AT&T ksh does (it does it after
1462 * substitutions, POSIX doesn't say which is to be done.
1466 char * volatile ps1;
1470 ps1 = str_val(global("PS1"));
1471 shf = shf_sopen(NULL, strlen(ps1) * 2,
1472 SHF_WR | SHF_DYNAMIC, NULL);
1474 if (*ps1 != '!' || *++ps1 == '!')
1475 shf_putchar(*ps1++, shf);
1477 shf_fprintf(shf, Tf_lu, s ?
1478 (unsigned long)s->line + 1 : 0UL);
1479 ps1 = shf_sclose(shf);
1480 saved_lineno = current_lineno;
1482 current_lineno = s->line + 1;
1483 saved_atemp = ATEMP;
1485 if (kshsetjmp(e->jbuf)) {
1486 prompt = safe_prompt;
1488 * Don't print an error - assume it has already
1489 * been printed. Reason is we may have forked
1490 * to run a command and the child may be
1491 * unwinding its stack through this code as it
1495 char *cp = substitute(ps1, 0);
1496 strdupx(prompt, cp, saved_atemp);
1498 current_lineno = saved_lineno;
1502 /* command continuation */
1504 prompt = str_val(global("PS2"));
1510 pprompt(const char *cp, int ntruncate)
1513 bool doprint = (ntruncate != -1);
1514 bool indelimit = false;
1515 int columns = 0, lines = 0;
1518 * Undocumented AT&T ksh feature:
1519 * If the second char in the prompt string is \r then the first
1520 * char is taken to be a non-printing delimiter and any chars
1521 * between two instances of the delimiter are not considered to
1522 * be part of the prompt length
1524 if (*cp && cp[1] == '\r') {
1529 if (indelimit && *cp != delimiter)
1531 else if (*cp == '\n' || *cp == '\r') {
1532 lines += columns / x_cols + ((*cp == '\n') ? 1 : 0);
1534 } else if (*cp == '\t') {
1535 columns = (columns | 7) + 1;
1536 } else if (*cp == '\b') {
1539 } else if (*cp == delimiter)
1540 indelimit = !indelimit;
1541 else if (UTFMODE && ((unsigned char)*cp > 0x7F)) {
1543 columns += utf_widthadj(cp, &cp2);
1544 if (doprint && (indelimit ||
1545 (ntruncate < (x_cols * lines + columns))))
1546 shf_write(cp, cp2 - cp, shl_out);
1547 cp = cp2 - /* loop increment */ 1;
1551 if (doprint && (*cp != delimiter) &&
1552 (indelimit || (ntruncate < (x_cols * lines + columns))))
1553 shf_putc(*cp, shl_out);
1557 return (x_cols * lines + columns);
1561 * Read the variable part of a ${...} expression (i.e. up to but not
1562 * including the :[-+?=#%] or close-brace).
1565 get_brace_var(XString *wsp, char *wp)
1569 PS_INITIAL, PS_SAW_PERCENT, PS_SAW_HASH, PS_SAW_BANG,
1570 PS_IDENT, PS_NUMBER, PS_VAR1
1571 } state = PS_INITIAL;
1573 while (/* CONSTCOND */ 1) {
1575 /* State machine to figure out where the variable part ends. */
1578 if (ctype(c, C_VAR1)) {
1583 if (c2 != /*{*/ '}') {
1601 state = PS_SAW_PERCENT;
1604 state = PS_SAW_HASH;
1607 state = PS_SAW_BANG;
1611 case PS_SAW_PERCENT:
1615 else if (ksh_isdigit(c))
1617 else if (ctype(c, C_VAR1))
1623 if (!ksh_isalnux(c)) {
1627 if (!arraysub(&tmp))
1628 yyerror("missing ]");
1630 for (p = tmp; *p; ) {
1643 if (!ksh_isdigit(c))
1653 /* end of variable part */
1660 * Save an array subscript - returns true if matching bracket found, false
1661 * if eof or newline was found.
1662 * (Returned string double null terminated)
1665 arraysub(char **strp)
1669 /* we are just past the initial [ */
1670 unsigned int depth = 1;
1672 Xinit(ws, wp, 32, ATEMP);
1682 } while (depth > 0 && c && c != '\n');
1685 *strp = Xclose(ws, wp);
1687 return (tobool(depth == 0));
1690 /* Unget a char: handles case when we are already at the start of the buffer */
1694 struct sretrace_info *rp = retrace_info;
1698 /* Don't unget EOF... */
1699 if (source->str == null && c == '\0')
1702 if (Xlength(rp->xs, rp->xp))
1711 if (source->str > source->start)
1716 s = pushs(SREREAD, source->areap);
1717 s->ugbuf[0] = c; s->ugbuf[1] = '\0';
1718 s->start = s->str = s->ugbuf;
1725 /* Called to get a char that isn't a \newline sequence. */
1731 if (ignore_backslash_newline)
1732 return (o_getsc_u());
1734 if (backslash_skip == 1) {
1736 return (o_getsc_u());
1741 while (/* CONSTCOND */ 1) {
1744 if ((c2 = o_getsc_u()) == '\n')
1745 /* ignore the \newline; get the next char... */
1759 if ((unsigned char)(c = o_getsc_u()) != 0xEF) {
1763 if ((unsigned char)(c = o_getsc_u()) != 0xBB) {
1768 if ((unsigned char)(c = o_getsc_u()) != 0xBF) {
1778 push_state_i(State_info *si, Lex_state *old_end)
1780 Lex_state *news = alloc2(STATE_BSIZE, sizeof(Lex_state), ATEMP);
1782 news[0].ls_base = old_end;
1783 si->base = &news[0];
1784 si->end = &news[STATE_BSIZE];
1789 pop_state_i(State_info *si, Lex_state *old_end)
1791 Lex_state *old_base = si->base;
1793 si->base = old_end->ls_base - STATE_BSIZE;
1794 si->end = old_end->ls_base;
1796 afree(old_base, ATEMP);
1798 return (si->base + STATE_BSIZE - 1);