Author: jilles
Date: Sun Jun 12 23:06:04 2011
New Revision: 223024
URL: http://svn.freebsd.org/changeset/base/223024

Log:
  sh: Save/restore changed variables in optimized command substitution.
  
  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.

Modified:
  head/bin/sh/eval.c
  head/bin/sh/expand.c
  head/bin/sh/expand.h
  head/bin/sh/jobs.c
  head/bin/sh/sh.1
  head/bin/sh/var.c
  head/bin/sh/var.h

Modified: head/bin/sh/eval.c
==============================================================================
--- head/bin/sh/eval.c  Sun Jun 12 22:47:04 2011        (r223023)
+++ head/bin/sh/eval.c  Sun Jun 12 23:06:04 2011        (r223024)
@@ -571,14 +571,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);
 }
 
 /*
@@ -596,6 +590,7 @@ evalbackcmd(union node *n, struct backcm
        struct stackmark smark;         /* unnecessary */
        struct jmploc jmploc;
        struct jmploc *savehandler;
+       struct localvar *savelocalvars;
 
        setstackmark(&smark);
        result->fd = -1;
@@ -608,12 +603,18 @@ evalbackcmd(union node *n, struct backcm
        }
        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 {
@@ -621,6 +622,9 @@ evalbackcmd(union node *n, struct backcm
                        evalcommand(n, EV_BACKCMD, result);
                }
                handler = savehandler;
+               forcelocal--;
+               poplocalvars();
+               localvars = savelocalvars;
        } else {
                exitstatus = 0;
                if (pipe(pip) < 0)

Modified: head/bin/sh/expand.c
==============================================================================
--- head/bin/sh/expand.c        Sun Jun 12 22:47:04 2011        (r223023)
+++ head/bin/sh/expand.c        Sun Jun 12 23:06:04 2011        (r223024)
@@ -1621,78 +1621,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).
  */
 

Modified: head/bin/sh/expand.h
==============================================================================
--- head/bin/sh/expand.h        Sun Jun 12 22:47:04 2011        (r223023)
+++ head/bin/sh/expand.h        Sun Jun 12 23:06:04 2011        (r223024)
@@ -63,5 +63,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 **);

Modified: head/bin/sh/jobs.c
==============================================================================
--- head/bin/sh/jobs.c  Sun Jun 12 22:47:04 2011        (r223023)
+++ head/bin/sh/jobs.c  Sun Jun 12 23:06:04 2011        (r223024)
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
+#include "var.h"
 
 
 static struct job *jobtab;     /* array of jobs */
@@ -798,6 +799,7 @@ forkshell(struct job *jp, union node *n,
                handler = &main_handler;
                closescript();
                INTON;
+               forcelocal = 0;
                clear_traps();
 #if JOBS
                jobctl = 0;             /* do job control only in root shell */
@@ -1121,7 +1123,7 @@ backgndpidset(void)
 pid_t
 backgndpidval(void)
 {
-       if (bgjob != NULL)
+       if (bgjob != NULL && !forcelocal)
                bgjob->remembered = 1;
        return backgndpid;
 }

Modified: head/bin/sh/sh.1
==============================================================================
--- head/bin/sh/sh.1    Sun Jun 12 22:47:04 2011        (r223023)
+++ head/bin/sh/sh.1    Sun Jun 12 23:06:04 2011        (r223024)
@@ -32,7 +32,7 @@
 .\"    from: @(#)sh.1  8.6 (Berkeley) 5/4/95
 .\" $FreeBSD$
 .\"
-.Dd June 10, 2011
+.Dd June 12, 2011
 .Dt SH 1
 .Os
 .Sh NAME
@@ -1536,10 +1536,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.

Modified: head/bin/sh/var.c
==============================================================================
--- head/bin/sh/var.c   Sun Jun 12 22:47:04 2011        (r223023)
+++ head/bin/sh/var.c   Sun Jun 12 23:06:04 2011        (r223024)
@@ -94,6 +94,8 @@ struct var vps4;
 struct var vvers;
 static struct var voptind;
 
+int forcelocal;
+
 static const struct varinit varinit[] = {
 #ifndef NO_HISTORY
        { &vhistsize,   VUNSET,                         "HISTSIZE=",
@@ -325,6 +327,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)
@@ -740,9 +744,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;
@@ -751,7 +755,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;

Modified: head/bin/sh/var.h
==============================================================================
--- head/bin/sh/var.h   Sun Jun 12 22:47:04 2011        (r223023)
+++ head/bin/sh/var.h   Sun Jun 12 23:06:04 2011        (r223024)
@@ -46,6 +46,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 {
@@ -68,6 +69,7 @@ struct localvar {
 
 
 struct localvar *localvars;
+extern int forcelocal;
 
 extern struct var vifs;
 extern struct var vmail;
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to