OSDN Git Service

Upgrade to mksh 50e.
[android-x86/external-mksh.git] / src / eval.c
index 49a4c33..f9c189d 100644 (file)
@@ -2,7 +2,7 @@
 
 /*-
  * 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
@@ -23,7 +23,7 @@
 
 #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
@@ -59,10 +59,11 @@ typedef struct {
 #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);
@@ -70,7 +71,7 @@ static char *valsub(struct op *, Area *);
 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
@@ -237,7 +238,7 @@ expand(
        /* 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;
 
@@ -246,7 +247,7 @@ expand(
        /* 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;
@@ -290,7 +291,17 @@ expand(
                                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;
@@ -383,6 +394,8 @@ expand(
                                if (f & DOBLANK)
                                        doblank++;
                                tilde_ok = 0;
+                               if (word == IFS_QUOTE && type != XNULLSUB)
+                                       word = IFS_WORD;
                                if (type == XBASE) {
                                        /* expand? */
                                        if (!st->next) {
@@ -516,7 +529,6 @@ expand(
 
                                                /* check for special cases */
                                                d = str_val(st->var);
-                                               mkssert(d != NULL);
                                                switch (*pat) {
                                                case '#':
                                                        /* anchor at begin */
@@ -622,7 +634,7 @@ expand(
                                        case '%':
                                                /* ! DOBLANK,DOBRACE,DOTILDE */
                                                f = (f & DONTRUNCOMMAND) |
-                                                   DOPAT | DOTEMP;
+                                                   DOPAT | DOTEMP | DOSCALAR;
                                                st->quotew = quote = 0;
                                                /*
                                                 * Prepend open pattern (so |
@@ -631,7 +643,7 @@ expand(
                                                 */
                                                if (!Flag(FSH)) {
                                                        *dp++ = MAGIC;
-                                                       *dp++ = '@' | 0x80;
+                                                       *dp++ = 0x80 | '@';
                                                }
                                                break;
                                        case '=':
@@ -664,7 +676,11 @@ expand(
                                                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;
@@ -704,10 +720,16 @@ expand(
                                        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;
@@ -743,7 +765,7 @@ expand(
                                        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);
@@ -759,11 +781,12 @@ expand(
                                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;
@@ -799,8 +822,8 @@ expand(
                        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;
 
@@ -834,15 +857,20 @@ expand(
                                        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)
@@ -867,7 +895,7 @@ expand(
                                /* $(<...) failed */
                                subst_exstat = 1;
                                /* fake EOF */
-                               c = EOF;
+                               c = -1;
                        } else if (newlines) {
                                /* spit out saved NLs */
                                c = '\n';
@@ -877,13 +905,13 @@ expand(
                                        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);
@@ -911,7 +939,7 @@ expand(
                         *      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:
@@ -1023,7 +1051,7 @@ expand(
 
                                                tcp = maybe_expand_tilde(sp,
                                                    &ds, &tdp,
-                                                   f & DOASNTILDE);
+                                                   tobool(f & DOASNTILDE));
                                                if (tcp) {
                                                        if (dp != tdp)
                                                                word = IFS_WORD;
@@ -1659,7 +1687,7 @@ debunk(char *dp, const char *sp, size_t dlen)
  * 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;
@@ -1676,7 +1704,7 @@ maybe_expand_tilde(const char *p, XString *dsp, char **dpp, int isassign)
        }
        *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) {
@@ -1698,7 +1726,7 @@ maybe_expand_tilde(const char *p, XString *dsp, char **dpp, int isassign)
  */
 
 char *
-tilde(char *cp)
+do_tilde(char *cp)
 {
        char *dp = null;
 
@@ -1745,28 +1773,30 @@ homedir(char *name)
 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;
                        }
                }
        }
@@ -1795,7 +1825,7 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
        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;