From owner-svn-src-all@FreeBSD.ORG Sun Jun 12 23:06:05 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 39F37106564A; Sun, 12 Jun 2011 23:06:05 +0000 (UTC) (envelope-from jilles@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2A7A78FC13; Sun, 12 Jun 2011 23:06:05 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p5CN65DT045065; Sun, 12 Jun 2011 23:06:05 GMT (envelope-from jilles@svn.freebsd.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p5CN64s2045057; Sun, 12 Jun 2011 23:06:04 GMT (envelope-from jilles@svn.freebsd.org) Message-Id: <201106122306.p5CN64s2045057@svn.freebsd.org> From: Jilles Tjoelker Date: Sun, 12 Jun 2011 23:06:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r223024 - head/bin/sh X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Jun 2011 23:06:05 -0000 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;