OSDN Git Service

Update to mksh R48
[android-x86/external-mksh.git] / src / eval.c
index 4b1f5a0..b6ff1dc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: eval.c,v 1.37 2011/10/11 14:32:43 otto Exp $  */
+/*     $OpenBSD: eval.c,v 1.39 2013/07/01 17:25:27 jca Exp $   */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.142 2013/07/24 18:03:57 tg Exp $");
 
 /*
  * string expansion
@@ -33,15 +33,21 @@ __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
  */
 
 /* expansion generator state */
-typedef struct Expand {
-       /* int type; */                 /* see expand() */
-       const char *str;                /* string */
+typedef struct {
+       /* not including an "int type;" member, see expand() */
+       /* string */
+       const char *str;
+       /* source */
        union {
-               const char **strv;      /* string[] */
-               struct shf *shf;        /* file */
-       } u;                            /* source */
-       struct tbl *var;                /* variable in ${var..} */
-       bool split;                     /* split "$@" / call waitlast $() */
+               /* string[] */
+               const char **strv;
+               /* file */
+               struct shf *shf;
+       } u;
+       /* variable in ${var...} */
+       struct tbl *var;
+       /* split "$@" / call waitlast in $() */
+       bool split;
 } Expand;
 
 #define        XBASE           0       /* scanning original */
@@ -59,7 +65,7 @@ typedef struct Expand {
 
 static int varsub(Expand *, const char *, const char *, int *, int *);
 static int comsub(Expand *, const char *, int);
-static void funsub(struct op *);
+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);
@@ -198,33 +204,46 @@ typedef struct SubType {
 } SubType;
 
 void
-expand(const char *cp, /* input word */
-    XPtrV *wp,         /* output words */
-    int f)             /* DO* flags */
+expand(
+    /* input word */
+    const char *ccp,
+    /* output words */
+    XPtrV *wp,
+    /* DO* flags */
+    int f)
 {
        int c = 0;
-       int type;               /* expansion type */
-       int quote = 0;          /* quoted */
-       XString ds;             /* destination string */
-       char *dp;               /* destination */
-       const char *sp;         /* source */
-       int fdo, word;          /* second pass flags; have word */
-       int doblank;            /* field splitting of parameter/command subst */
+       /* expansion type */
+       int type;
+       /* quoted */
+       int quote = 0;
+       /* destination string and live pointer */
+       XString ds;
+       char *dp;
+       /* source */
+       const char *sp;
+       /* second pass flags */
+       int fdo;
+       /* have word */
+       int word;
+       /* field splitting of parameter/command substitution */
+       int doblank;
+       /* expansion variables */
        Expand x = {
-               /* expansion variables */
                NULL, { NULL }, NULL, 0
        };
        SubType st_head, *st;
-       /* For trailing newlines in COMSUB */
+       /* record number of trailing newlines in COMSUB */
        int newlines = 0;
        bool saw_eq, make_magic;
        int tilde_ok;
        size_t len;
+       char *cp;
 
-       if (cp == NULL)
+       if (ccp == NULL)
                internal_errorf("expand(NULL)");
        /* for alias, readonly, set, typeset commands */
-       if ((f & DOVACHECK) && is_wdvarassign(cp)) {
+       if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
                f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
                f |= DOASNTILDE;
        }
@@ -238,7 +257,7 @@ expand(const char *cp,      /* input word */
        /* init destination string */
        Xinit(ds, dp, 128, ATEMP);
        type = XBASE;
-       sp = cp;
+       sp = ccp;
        fdo = 0;
        saw_eq = false;
        /* must be 1/0 */
@@ -279,27 +298,26 @@ expand(const char *cp,    /* input word */
                                continue;
                        case COMSUB:
                        case FUNSUB:
+                       case VALSUB:
                                tilde_ok = 0;
                                if (f & DONTRUNCOMMAND) {
                                        word = IFS_WORD;
                                        *dp++ = '$';
-                                       if (c == FUNSUB) {
-                                               *dp++ = '{';
-                                               *dp++ = ' ';
-                                       } else
-                                               *dp++ = '(';
+                                       *dp++ = c == COMSUB ? '(' : '{';
+                                       if (c != COMSUB)
+                                               *dp++ = c == FUNSUB ? ' ' : '|';
                                        while (*sp != '\0') {
                                                Xcheck(ds, dp);
                                                *dp++ = *sp++;
                                        }
-                                       if (c == FUNSUB) {
+                                       if (c != COMSUB) {
                                                *dp++ = ';';
                                                *dp++ = '}';
                                        } else
                                                *dp++ = ')';
                                } else {
                                        type = comsub(&x, sp, c);
-                                       if (type == XCOM && (f&DOBLANK))
+                                       if (type != XBASE && (f & DOBLANK))
                                                doblank++;
                                        sp = strnul(sp) + 1;
                                        newlines = 0;
@@ -317,7 +335,6 @@ expand(const char *cp,      /* input word */
                                        *dp++ = ')'; *dp++ = ')';
                                } else {
                                        struct tbl v;
-                                       char *p;
 
                                        v.flag = DEFINED|ISSET|INTEGER;
                                        /* not default */
@@ -326,9 +343,10 @@ expand(const char *cp,     /* input word */
                                        v_evaluate(&v, substitute(sp, 0),
                                            KSH_UNWIND_ERROR, true);
                                        sp = strnul(sp) + 1;
-                                       for (p = str_val(&v); *p; ) {
+                                       cp = str_val(&v);
+                                       while (*cp) {
                                                Xcheck(ds, dp);
-                                               *dp++ = *p++;
+                                               *dp++ = *cp++;
                                        }
                                }
                                continue;
@@ -394,8 +412,7 @@ expand(const char *cp,      /* input word */
                                        if (stype)
                                                sp += slen;
                                        switch (stype & 0x17F) {
-                                       case 0x100 | '#':
-                                           {
+                                       case 0x100 | '#': {
                                                char *beg, *end;
                                                mksh_ari_t seed;
                                                register uint32_t h;
@@ -416,8 +433,7 @@ expand(const char *cp,      /* input word */
                                                    (unsigned int)h);
                                                break;
                                        }
-                                       case 0x100 | 'Q':
-                                           {
+                                       case 0x100 | 'Q': {
                                                struct shf shf;
 
                                                shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
@@ -839,7 +855,10 @@ expand(const char *cp,     /* input word */
                                if (c == 0) {
                                        if (quote && !x.split)
                                                continue;
+                                       /* this is so we don't terminate */
                                        c = ' ';
+                                       /* now force-emit a word */
+                                       goto emit_word;
                                }
                                if (quote && x.split) {
                                        /* terminate word for "$@" */
@@ -850,14 +869,19 @@ expand(const char *cp,    /* input word */
                        break;
 
                case XCOM:
-                       if (newlines) {
-                               /* Spit out saved NLs */
+                       if (x.u.shf == NULL) {
+                               /* $(<...) failed */
+                               subst_exstat = 1;
+                               /* fake EOF */
+                               c = EOF;
+                       } else if (newlines) {
+                               /* spit out saved NLs */
                                c = '\n';
                                --newlines;
                        } else {
                                while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
                                        if (c == '\n')
-                                               /* Save newlines */
+                                               /* save newlines */
                                                newlines++;
                                if (newlines && c != EOF) {
                                        shf_ungetc(c, x.u.shf);
@@ -867,7 +891,8 @@ expand(const char *cp,      /* input word */
                        }
                        if (c == EOF) {
                                newlines = 0;
-                               shf_close(x.u.shf);
+                               if (x.u.shf)
+                                       shf_close(x.u.shf);
                                if (x.split)
                                        subst_exstat = waitlast();
                                type = XBASE;
@@ -895,21 +920,21 @@ expand(const char *cp,    /* input word */
                         */
                        if (word == IFS_WORD ||
                            (!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
-                               char *p;
-
+ emit_word:
                                *dp++ = '\0';
-                               p = Xclose(ds, dp);
+                               cp = Xclose(ds, dp);
                                if (fdo & DOBRACE)
                                        /* also does globbing */
-                                       alt_expand(wp, p, p,
-                                           p + Xlength(ds, (dp - 1)),
+                                       alt_expand(wp, cp, cp,
+                                           cp + Xlength(ds, (dp - 1)),
                                            fdo | (f & DOMARKDIRS));
                                else if (fdo & DOGLOB)
-                                       glob(p, wp, tobool(f & DOMARKDIRS));
+                                       glob(cp, wp, tobool(f & DOMARKDIRS));
                                else if ((f & DOPAT) || !(fdo & DOMAGIC))
-                                       XPput(*wp, p);
+                                       XPput(*wp, cp);
                                else
-                                       XPput(*wp, debunk(p, p, strlen(p) + 1));
+                                       XPput(*wp, debunk(cp, cp,
+                                           strlen(cp) + 1));
                                fdo = 0;
                                saw_eq = false;
                                tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
@@ -920,10 +945,8 @@ expand(const char *cp,     /* input word */
                                return;
                        } else if (type == XSUB && ctype(c, C_IFS) &&
                            !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
-                               char *p;
-
-                               *(p = alloc(1, ATEMP)) = '\0';
-                               XPput(*wp, p);
+                               *(cp = alloc(1, ATEMP)) = '\0';
+                               XPput(*wp, cp);
                                type = XSUBMID;
                        }
                        if (word != IFS_NWS)
@@ -932,10 +955,8 @@ expand(const char *cp,     /* input word */
                        if (type == XSUB) {
                                if (word == IFS_NWS &&
                                    Xlength(ds, dp) == 0) {
-                                       char *p;
-
-                                       *(p = alloc(1, ATEMP)) = '\0';
-                                       XPput(*wp, p);
+                                       *(cp = alloc(1, ATEMP)) = '\0';
+                                       XPput(*wp, cp);
                                }
                                type = XSUBMID;
                        }
@@ -1002,18 +1023,17 @@ expand(const char *cp,  /* input word */
                                        if (type == XBASE &&
                                            (f & (DOTILDE|DOASNTILDE)) &&
                                            (tilde_ok & 2)) {
-                                               const char *p;
-                                               char *dp_x;
+                                               const char *tcp;
+                                               char *tdp = dp;
 
-                                               dp_x = dp;
-                                               p = maybe_expand_tilde(sp,
-                                                   &ds, &dp_x,
+                                               tcp = maybe_expand_tilde(sp,
+                                                   &ds, &tdp,
                                                    f & DOASNTILDE);
-                                               if (p) {
-                                                       if (dp != dp_x)
+                                               if (tcp) {
+                                                       if (dp != tdp)
                                                                word = IFS_WORD;
-                                                       dp = dp_x;
-                                                       sp = p;
+                                                       dp = tdp;
+                                                       sp = tcp;
                                                        continue;
                                                }
                                        }
@@ -1176,8 +1196,10 @@ varsub(Expand *xp, const char *sp, const char *word,
        c = sp[0];
        if (c == '*' || c == '@') {
                switch (stype & 0x17F) {
-               case '=':       /* can't assign to a vector */
-               case '%':       /* can't trim a vector (yet) */
+               /* can't assign to a vector */
+               case '=':
+               /* can't trim a vector (yet) */
+               case '%':
                case '#':
                case '0':
                case '/':
@@ -1204,8 +1226,10 @@ varsub(Expand *xp, const char *sp, const char *word,
                        XPtrV wv;
 
                        switch (stype & 0x17F) {
-                       case '=':       /* can't assign to a vector */
-                       case '%':       /* can't trim a vector (yet) */
+                       /* can't assign to a vector */
+                       case '=':
+                       /* can't trim a vector (yet) */
+                       case '%':
                        case '#':
                        case '?':
                        case '0':
@@ -1317,33 +1341,41 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
                shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
                        SHF_MAPHI|SHF_CLEXEC);
                if (shf == NULL)
-                       errorf("%s: %s %s", name, "can't open", "$() input");
+                       warningf(!Flag(FTALKING), "%s: %s %s: %s", name,
+                           "can't open", "$(<...) input", cstrerror(errno));
        } else if (fn == FUNSUB) {
                int ofd1;
                struct temp *tf = NULL;
 
-               /* create a temporary file, open for writing */
+               /*
+                * create a temporary file, open for reading and writing,
+                * with an shf open for reading (buffered) but yet unused
+                */
                maketemp(ATEMP, TT_FUNSUB, &tf);
                if (!tf->shf) {
                        errorf("can't %s temporary file %s: %s",
                            "create", tf->tffn, cstrerror(errno));
                }
-               /* save stdout and make the temporary file it */
+               /* extract shf from temporary file, unlink and free it */
+               shf = tf->shf;
+               unlink(tf->tffn);
+               afree(tf, ATEMP);
+               /* save stdout and let it point to the tempfile */
                ofd1 = savefd(1);
-               ksh_dup2(shf_fileno(tf->shf), 1, false);
+               ksh_dup2(shf_fileno(shf), 1, false);
                /*
                 * run tree, with output thrown into the tempfile,
                 * in a new function block
                 */
-               funsub(t);
+               valsub(t, NULL);
                subst_exstat = exstat & 0xFF;
-               /* close the tempfile and restore regular stdout */
-               shf_close(tf->shf);
+               /* rewind the tempfile and restore regular stdout */
+               lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
                restfd(1, ofd1);
-               /* now open, unlink and free the tempfile for reading */
-               shf = shf_open(tf->tffn, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
-               unlink(tf->tffn);
-               afree(tf, ATEMP);
+       } else if (fn == VALSUB) {
+               xp->str = valsub(t, ATEMP);
+               subst_exstat = exstat & 0xFF;
+               return (XSUB);
        } else {
                int ofd1, pv[2];
 
@@ -1495,11 +1527,11 @@ globit(XString *xs,     /* dest string */
                 */
                if ((check & GF_EXCHECK) ||
                    ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
-#define stat_check()   (stat_done ? stat_done : \
-                           (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
-                               ? -1 : 1))
+#define stat_check()   (stat_done ? stat_done : (stat_done = \
+                           stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1))
                        struct stat lstatb, statb;
-                       int stat_done = 0;       /* -1: failed, 1 ok */
+                       /* -1: failed, 1 ok, 0 not yet done */
+                       int stat_done = 0;
 
                        if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
                                return;
@@ -1801,12 +1833,21 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
 }
 
 /* helper function due to setjmp/longjmp woes */
-static void
-funsub(struct op *t)
+static char *
+valsub(struct op *t, Area *ap)
 {
+       char * volatile cp = NULL;
+       struct tbl * volatile vp = NULL;
+
+       newenv(E_FUNC);
        newblock();
-       e->type = E_FUNC;
+       if (ap)
+               vp = local("REPLY", false);
        if (!kshsetjmp(e->jbuf))
                execute(t, XXCOM | XERROK, NULL);
-       popblock();
+       if (vp)
+               strdupx(cp, str_val(vp), ap);
+       quitenv(NULL);
+
+       return (cp);
 }