/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014
+ * 2011, 2012, 2013, 2014, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.153 2014/10/07 15:22:16 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.158.2.4 2015/03/01 15:42:58 tg Exp $");
/*
* string expansion
#define XSUBMID 6 /* middle of expanding ${} */
/* States used for field splitting */
-#define IFS_WORD 0 /* word has chars (or quotes) */
+#define IFS_WORD 0 /* word has chars (or quotes except "$@") */
#define IFS_WS 1 /* have seen IFS white-space */
#define IFS_NWS 2 /* have seen IFS non-white-space */
#define IFS_IWS 3 /* begin of word, ignore IFS WS */
+#define IFS_QUOTE 4 /* beg.w/quote, become IFS_WORD unless "$@" */
static int varsub(Expand *, const char *, const char *, int *, int *);
static int comsub(Expand *, const char *, int);
static char *trimsub(char *, char *, int);
static void glob(char *, XPtrV *, bool);
static void globit(XString *, char **, char *, XPtrV *, int);
-static const char *maybe_expand_tilde(const char *, XString *, char **, int);
+static const char *maybe_expand_tilde(const char *, XString *, char **, bool);
#ifndef MKSH_NOPWNAM
static char *homedir(char *);
#endif
/* record number of trailing newlines in COMSUB */
int newlines = 0;
bool saw_eq, make_magic;
- int tilde_ok;
+ unsigned int tilde_ok;
size_t len;
char *cp;
/* for alias, readonly, set, typeset commands */
if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE);
- f |= DOASNTILDE | DOASNFIELD;
+ f |= DOASNTILDE | DOSCALAR;
}
if (Flag(FNOGLOB))
f &= ~DOGLOB;
c = *sp++;
break;
case OQUOTE:
- word = IFS_WORD;
+ switch (word) {
+ case IFS_QUOTE:
+ /* """something */
+ word = IFS_WORD;
+ break;
+ case IFS_WORD:
+ break;
+ default:
+ word = IFS_QUOTE;
+ break;
+ }
tilde_ok = 0;
quote = 1;
continue;
if (f & DOBLANK)
doblank++;
tilde_ok = 0;
+ if (word == IFS_QUOTE && type != XNULLSUB)
+ word = IFS_WORD;
if (type == XBASE) {
/* expand? */
if (!st->next) {
/* check for special cases */
d = str_val(st->var);
- mkssert(d != NULL);
switch (*pat) {
case '#':
/* anchor at begin */
case '%':
/* ! DOBLANK,DOBRACE,DOTILDE */
f = (f & DONTRUNCOMMAND) |
- DOPAT | DOTEMP;
+ DOPAT | DOTEMP | DOSCALAR;
st->quotew = quote = 0;
/*
* Prepend open pattern (so |
*/
if (!Flag(FSH)) {
*dp++ = MAGIC;
- *dp++ = '@' | 0x80;
+ *dp++ = 0x80 | '@';
}
break;
case '=':
f |= DOTEMP;
/* FALLTHROUGH */
default:
- word = quote ? IFS_WORD : IFS_IWS;
+ /* '-' '+' '?' */
+ if (quote)
+ word = IFS_WORD;
+ else if (dp == Xstring(ds, dp))
+ word = IFS_IWS;
/* Enable tilde expansion */
tilde_ok = 1;
f |= DOTILDE;
x.str = trimsub(str_val(st->var),
dp, st->stype);
if (x.str[0] != '\0') {
- word = IFS_WS;
+ word = IFS_IWS;
type = XSUB;
- } else
- type = quote ? XSUB : XNULLSUB;
+ } else if (quote) {
+ word = IFS_WORD;
+ type = XSUB;
+ } else {
+ if (dp == Xstring(ds, dp))
+ word = IFS_IWS;
+ type = XNULLSUB;
+ }
if (f & DOBLANK)
doblank++;
st = st->prev;
if (f & DOBLANK)
doblank++;
st = st->prev;
- word = quote || (!*x.str && (f & DOASNFIELD)) ? IFS_WORD : IFS_WS;
+ word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
continue;
case '?': {
char *s = Xrestpos(ds, dp, st->base);
case 0x100 | 'Q':
dp = Xrestpos(ds, dp, st->base);
type = XSUB;
- word = quote || (!*x.str && (f & DOASNFIELD)) ? IFS_WORD : IFS_WS;
+ word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
if (f & DOBLANK)
doblank++;
st = st->prev;
continue;
+ /* default: '-' '+' */
}
st = st->prev;
type = XBASE;
type = XBASE;
if (f & DOBLANK) {
doblank--;
- if (dp == Xstring(ds, dp))
- word = IFS_WS;
+ if (dp == Xstring(ds, dp) && word != IFS_WORD)
+ word = IFS_IWS;
}
continue;
continue;
}
c = ifs0;
- if ((f & DOASNFIELD)) {
- /* assignment, do not field-split */
+ if ((f & DOHEREDOC)) {
+ /* pseudo-field-split reliably */
+ if (c == 0)
+ c = ' ';
+ break;
+ }
+ if ((f & DOSCALAR)) {
+ /* do not field-split */
if (x.split) {
c = ' ';
break;
}
- if (c == 0) {
+ if (c == 0)
continue;
- }
}
if (c == 0) {
if (quote && !x.split)
/* $(<...) failed */
subst_exstat = 1;
/* fake EOF */
- c = EOF;
+ c = -1;
} else if (newlines) {
/* spit out saved NLs */
c = '\n';
if (c == '\n')
/* save newlines */
newlines++;
- if (newlines && c != EOF) {
+ if (newlines && c != -1) {
shf_ungetc(c, x.u.shf);
c = '\n';
--newlines;
}
}
- if (c == EOF) {
+ if (c == -1) {
newlines = 0;
if (x.u.shf)
shf_close(x.u.shf);
* IFS_IWS -/WS w/NWS -
* (w means generate a word)
*/
- if ((word == IFS_WORD) || (c &&
+ if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c &&
(word == IFS_IWS || word == IFS_NWS) &&
!ctype(c, C_IFSWS))) {
emit_word:
tcp = maybe_expand_tilde(sp,
&ds, &tdp,
- f & DOASNTILDE);
+ tobool(f & DOASNTILDE));
if (tcp) {
if (dp != tdp)
word = IFS_WORD;
* past the name, otherwise returns 0.
*/
static const char *
-maybe_expand_tilde(const char *p, XString *dsp, char **dpp, int isassign)
+maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign)
{
XString ts;
char *dp = *dpp;
}
*tp = '\0';
r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ?
- tilde(Xstring(ts, tp)) : NULL;
+ do_tilde(Xstring(ts, tp)) : NULL;
Xfree(ts, tp);
if (r) {
while (*r) {
*/
char *
-tilde(char *cp)
+do_tilde(char *cp)
{
char *dp = null;
static void
alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
{
- int count = 0;
+ unsigned int count = 0;
char *brace_start, *brace_end, *comma = NULL;
char *field_start;
- char *p;
+ char *p = exp_start;
/* search for open brace */
- for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != '{' /*}*/; p += 2)
- ;
+ while ((p = strchr(p, MAGIC)) && p[1] != '{' /*}*/)
+ p += 2;
brace_start = p;
/* find matching close brace, if any */
if (p) {
comma = NULL;
count = 1;
- for (p += 2; *p && count; p++) {
- if (ISMAGIC(*p)) {
- if (*++p == '{' /*}*/)
- count++;
+ p += 2;
+ while (*p && count) {
+ if (ISMAGIC(*p++)) {
+ if (*p == '{' /*}*/)
+ ++count;
else if (*p == /*{*/ '}')
--count;
else if (*p == ',' && count == 1)
comma = p;
+ ++p;
}
}
}
for (p = brace_start + 2; p != brace_end; p++) {
if (ISMAGIC(*p)) {
if (*++p == '{' /*}*/)
- count++;
+ ++count;
else if ((*p == /*{*/ '}' && --count == 0) ||
(*p == ',' && count == 1)) {
char *news;