diff options
author | jilles <jilles@FreeBSD.org> | 2011-06-12 23:06:04 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2011-06-12 23:06:04 +0000 |
commit | 91789615b49a87147298eee12c9b111d8c1b64c9 (patch) | |
tree | b1cbd950b159dbb3fa6211ba5a7f7fb7709a612e /bin | |
parent | 5f2600c6a978923a3904716ce73814baca63fd0f (diff) | |
download | FreeBSD-src-91789615b49a87147298eee12c9b111d8c1b64c9.zip FreeBSD-src-91789615b49a87147298eee12c9b111d8c1b64c9.tar.gz |
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.
Diffstat (limited to 'bin')
-rw-r--r-- | bin/sh/eval.c | 18 | ||||
-rw-r--r-- | bin/sh/expand.c | 72 | ||||
-rw-r--r-- | bin/sh/expand.h | 1 | ||||
-rw-r--r-- | bin/sh/jobs.c | 4 | ||||
-rw-r--r-- | bin/sh/sh.1 | 7 | ||||
-rw-r--r-- | bin/sh/var.c | 10 | ||||
-rw-r--r-- | bin/sh/var.h | 2 |
7 files changed, 25 insertions, 89 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 92a18e4..9d67b9e 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -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 backcmd *result) 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 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 { @@ -621,6 +622,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) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index beb655d..c6c54ab 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -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). */ diff --git a/bin/sh/expand.h b/bin/sh/expand.h index be08dec..a4bb198 100644 --- a/bin/sh/expand.h +++ b/bin/sh/expand.h @@ -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 **); diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c index 434af22..cbc29f1 100644 --- a/bin/sh/jobs.c +++ b/bin/sh/jobs.c @@ -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, int mode) 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; } diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index f6682e6..3b7f3d3 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -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. diff --git a/bin/sh/var.c b/bin/sh/var.c index f6d7fb1..e405b66 100644 --- a/bin/sh/var.c +++ b/bin/sh/var.c @@ -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; diff --git a/bin/sh/var.h b/bin/sh/var.h index ff21c7d..f10bfcc 100644 --- a/bin/sh/var.h +++ b/bin/sh/var.h @@ -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; |