sh: Save/restore changed variables in optimized command substitution.
authorPeter Avalos <pavalos@dragonflybsd.org>
Sun, 21 Aug 2011 20:54:19 +0000 (13:54 -0700)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sun, 21 Aug 2011 20:54:19 +0000 (13:54 -0700)
In optimized command substitution, save and restore any variables
changed by expansions (${var=value} and $((var=assigned))), instead of
trying to determine if an expansion may cause such changes.

If $! is referenced in optimized command substitution, do not cause jobs
to be remembered longer.

This fixes $(jobs $!) again, simplifies the man page and shortens the
code.

Obtained-from:   FreeBSD 223024

bin/sh/eval.c
bin/sh/expand.c
bin/sh/expand.h
bin/sh/jobs.c
bin/sh/sh.1
bin/sh/var.c
bin/sh/var.h

index 1bf6a0a..6f0615e 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  * @(#)eval.c  8.9 (Berkeley) 6/8/95
- * $FreeBSD: src/bin/sh/eval.c,v 1.108 2011/06/09 23:12:23 jilles Exp $
+ * $FreeBSD: src/bin/sh/eval.c,v 1.109 2011/06/12 23:06:04 jilles Exp $
  */
 
 #include <sys/time.h>
@@ -573,14 +573,8 @@ evalpipe(union node *n)
 static int
 is_valid_fast_cmdsubst(union node *n)
 {
-       union node *argp;
 
-       if (n->type != NCMD)
-               return 0;
-       for (argp = n->ncmd.args ; argp ; argp = argp->narg.next)
-               if (expandhassideeffects(argp->narg.text))
-                       return 0;
-       return 1;
+       return (n->type == NCMD);
 }
 
 /*
@@ -598,6 +592,7 @@ evalbackcmd(union node *n, struct backcmd *result)
        struct stackmark smark;         /* unnecessary */
        struct jmploc jmploc;
        struct jmploc *savehandler;
+       struct localvar *savelocalvars;
 
        setstackmark(&smark);
        result->fd = -1;
@@ -610,12 +605,18 @@ evalbackcmd(union node *n, struct backcmd *result)
        }
        if (is_valid_fast_cmdsubst(n)) {
                exitstatus = oexitstatus;
+               savelocalvars = localvars;
+               localvars = NULL;
+               forcelocal++;
                savehandler = handler;
                if (setjmp(jmploc.loc)) {
                        if (exception == EXERROR || exception == EXEXEC)
                                exitstatus = 2;
                        else if (exception != 0) {
                                handler = savehandler;
+                               forcelocal--;
+                               poplocalvars();
+                               localvars = savelocalvars;
                                longjmp(handler->loc, 1);
                        }
                } else {
@@ -623,6 +624,9 @@ evalbackcmd(union node *n, struct backcmd *result)
                        evalcommand(n, EV_BACKCMD, result);
                }
                handler = savehandler;
+               forcelocal--;
+               poplocalvars();
+               localvars = savelocalvars;
        } else {
                exitstatus = 0;
                if (pipe(pip) < 0)
index 1f82985..4293319 100644 (file)
@@ -36,7 +36,7 @@
  * SUCH DAMAGE.
  *
  * @(#)expand.c        8.5 (Berkeley) 5/15/95
- * $FreeBSD: src/bin/sh/expand.c,v 1.87 2011/06/09 23:12:23 jilles Exp $
+ * $FreeBSD: src/bin/sh/expand.c,v 1.89 2011/06/12 23:06:04 jilles Exp $
  */
 
 #include <sys/types.h>
@@ -1620,78 +1620,6 @@ cvtnum(int num, char *buf)
 }
 
 /*
- * Check statically if expanding a string may have side effects.
- */
-int
-expandhassideeffects(const char *p)
-{
-       int c;
-       int arinest;
-
-       arinest = 0;
-       while ((c = *p++) != '\0') {
-               switch (c) {
-               case CTLESC:
-                       p++;
-                       break;
-               case CTLVAR:
-                       c = *p++;
-                       /* Expanding $! sets the job to remembered. */
-                       if (*p == '!')
-                               return 1;
-                       if ((c & VSTYPE) == VSASSIGN)
-                               return 1;
-                       /*
-                        * If we are in arithmetic, the parameter may contain
-                        * '=' which may cause side effects. Exceptions are
-                        * the length of a parameter and $$, $# and $? which
-                        * are always numeric.
-                        */
-                       if ((c & VSTYPE) == VSLENGTH) {
-                               while (*p != '=')
-                                       p++;
-                               p++;
-                               break;
-                       }
-                       if ((*p == '$' || *p == '#' || *p == '?') &&
-                           p[1] == '=') {
-                               p += 2;
-                               break;
-                       }
-                       if (arinest > 0)
-                               return 1;
-                       break;
-               case CTLBACKQ:
-               case CTLBACKQ | CTLQUOTE:
-                       if (arinest > 0)
-                               return 1;
-                       break;
-               case CTLARI:
-                       arinest++;
-                       break;
-               case CTLENDARI:
-                       arinest--;
-                       break;
-               case '=':
-                       if (*p == '=') {
-                               /* Allow '==' operator. */
-                               p++;
-                               continue;
-                       }
-                       if (arinest > 0)
-                               return 1;
-                       break;
-               case '!': case '<': case '>':
-                       /* Allow '!=', '<=', '>=' operators. */
-                       if (*p == '=')
-                               p++;
-                       break;
-               }
-       }
-       return 0;
-}
-
-/*
  * Do most of the work for wordexp(3).
  */
 
index 3de59b5..34c3a59 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)expand.h    8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/expand.h,v 1.15 2010/12/28 21:27:08 jilles Exp $
+ * $FreeBSD: src/bin/sh/expand.h,v 1.16 2011/06/12 23:06:04 jilles Exp $
  */
 
 struct strlist {
@@ -67,5 +67,4 @@ void expari(int);
 int patmatch(const char *, const char *, int);
 void rmescapes(char *);
 int casematch(union node *, const char *);
-int expandhassideeffects(const char *);
 int wordexpcmd(int, char **);
index ae3bd03..39dba19 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  * @(#)jobs.c  8.5 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/jobs.c,v 1.93 2011/06/04 15:05:52 jilles Exp $
+ * $FreeBSD: src/bin/sh/jobs.c,v 1.94 2011/06/12 23:06:04 jilles Exp $
  */
 
 #include <sys/ioctl.h>
@@ -69,6 +69,7 @@
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
+#include "var.h"
 
 
 static struct job *jobtab;     /* array of jobs */
@@ -797,6 +798,7 @@ forkshell(struct job *jp, union node *n, int mode)
                handler = &main_handler;
                closescript();
                INTON;
+               forcelocal = 0;
                clear_traps();
 #if JOBS
                jobctl = 0;             /* do job control only in root shell */
@@ -1124,7 +1126,7 @@ backgndpidset(void)
 pid_t
 backgndpidval(void)
 {
-       if (bgjob != NULL)
+       if (bgjob != NULL && !forcelocal)
                bgjob->remembered = 1;
        return backgndpid;
 }
index 6a5b051..eecb026 100644 (file)
@@ -34,7 +34,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    from: @(#)sh.1  8.6 (Berkeley) 5/4/95
-.\" $FreeBSD: src/bin/sh/sh.1,v 1.167 2011/06/10 22:42:00 jilles Exp $
+.\" $FreeBSD: src/bin/sh/sh.1,v 1.168 2011/06/12 23:06:04 jilles Exp $
 .\"
 .Dd August 21, 2011
 .Dt SH 1
@@ -1547,10 +1547,7 @@ except that the built-in commands
 and
 .Ic trap
 return information about the main shell environment
-if they are the only command in a command substitution
-and the substitutions in the command cannot cause side effects
-(such as from assigning values to variables or referencing
-.Li $! ).
+if they are the only command in a command substitution.
 .Ss Arithmetic Expansion
 Arithmetic expansion provides a mechanism for evaluating an arithmetic
 expression and substituting its value.
index 16552a3..54420b6 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  * @(#)var.c   8.3 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/var.c,v 1.60 2011/05/15 22:09:27 jilles Exp $
+ * $FreeBSD: src/bin/sh/var.c,v 1.61 2011/06/12 23:06:04 jilles Exp $
  */
 
 #include <unistd.h>
@@ -93,6 +93,8 @@ struct var vps4;
 struct var vvers;
 static struct var voptind;
 
+int forcelocal;
+
 static const struct varinit varinit[] = {
 #ifndef NO_HISTORY
        { &vhistsize,   VUNSET,                         "HISTSIZE=",
@@ -322,6 +324,8 @@ setvareq(char *s, int flags)
 
        if (aflag)
                flags |= VEXPORT;
+       if (forcelocal && !(flags & (VNOSET | VNOLOCAL)))
+               mklocal(s);
        vp = find_var(s, &vpp, &nlen);
        if (vp != NULL) {
                if (vp->flags & VREADONLY)
@@ -737,9 +741,9 @@ mklocal(char *name)
                vp = find_var(name, &vpp, NULL);
                if (vp == NULL) {
                        if (strchr(name, '='))
-                               setvareq(savestr(name), VSTRFIXED);
+                               setvareq(savestr(name), VSTRFIXED | VNOLOCAL);
                        else
-                               setvar(name, NULL, VSTRFIXED);
+                               setvar(name, NULL, VSTRFIXED | VNOLOCAL);
                        vp = *vpp;      /* the new variable */
                        lvp->text = NULL;
                        lvp->flags = VUNSET;
@@ -748,7 +752,7 @@ mklocal(char *name)
                        lvp->flags = vp->flags;
                        vp->flags |= VSTRFIXED|VTEXTFIXED;
                        if (name[vp->name_len] == '=')
-                               setvareq(savestr(name), 0);
+                               setvareq(savestr(name), VNOLOCAL);
                }
        }
        lvp->vp = vp;
index d23ae32..7274b2b 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)var.h       8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/var.h,v 1.22 2011/05/08 17:40:10 jilles Exp $
+ * $FreeBSD: src/bin/sh/var.h,v 1.23 2011/06/12 23:06:04 jilles Exp $
  */
 
 /*
@@ -50,6 +50,7 @@
 #define VUNSET         0x20    /* the variable is not set */
 #define VNOFUNC                0x40    /* don't call the callback function */
 #define VNOSET         0x80    /* do not set variable - just readonly test */
+#define VNOLOCAL       0x100   /* ignore forcelocal */
 
 
 struct var {
@@ -72,6 +73,7 @@ struct localvar {
 
 
 struct localvar *localvars;
+extern int forcelocal;
 
 extern struct var vifs;
 extern struct var vmail;