diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 585f91ead32a..92a18e4b2b3b 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -745,8 +745,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd) /* Print the command if xflag is set. */ if (xflag) { char sep = 0; - const char *p; - out2str(ps4val()); + const char *p, *ps4; + ps4 = expandstr(ps4val()); + out2str(ps4 != NULL ? ps4 : ps4val()); for (sp = varlist.list ; sp ; sp = sp->next) { if (sep != 0) out2c(' '); diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 108a77c4be68..aaa91acc3392 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -174,6 +174,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag) ifslastp = NULL; argstr(arg->narg.text, flag); if (arglist == NULL) { + STACKSTRNUL(expdest); return; /* here document expanded */ } STPUTC('\0', expdest); diff --git a/bin/sh/parser.c b/bin/sh/parser.c index 151970b79d08..2fea1ecb5270 100644 --- a/bin/sh/parser.c +++ b/bin/sh/parser.c @@ -2029,3 +2029,47 @@ getprompt(void *unused __unused) ps[i] = '\0'; return (ps); } + + +const char * +expandstr(char *ps) +{ + union node n; + struct jmploc jmploc; + struct jmploc *const savehandler = handler; + const int saveprompt = doprompt; + struct parsefile *const savetopfile = getcurrentfile(); + struct parser_temp *const saveparser_temp = parser_temp; + const char *result = NULL; + + if (!setjmp(jmploc.loc)) { + handler = &jmploc; + parser_temp = NULL; + setinputstring(ps, 1); + doprompt = 0; + readtoken1(pgetc(), DQSYNTAX, "\n\n", 0); + if (backquotelist != NULL) + error("Command substitution not allowed here"); + + n.narg.type = NARG; + n.narg.next = NULL; + n.narg.text = wordtext; + n.narg.backquote = backquotelist; + + expandarg(&n, NULL, 0); + result = stackblock(); + INTOFF; + } + handler = savehandler; + doprompt = saveprompt; + popfilesupto(savetopfile); + if (parser_temp != saveparser_temp) { + parser_temp_free_all(); + parser_temp = saveparser_temp; + } + if (result != NULL) { + INTON; + } else if (exception == EXINT) + raise(SIGINT); + return result; +} diff --git a/bin/sh/parser.h b/bin/sh/parser.h index e213e2140617..9a996d04a603 100644 --- a/bin/sh/parser.h +++ b/bin/sh/parser.h @@ -82,3 +82,4 @@ void fixredir(union node *, const char *, int); int goodname(const char *); int isassignment(const char *); char *getprompt(void *); +const char *expandstr(char *); diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 42e55d391b3e..0ce07bd9f0ce 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 May 21, 2011 +.Dd June 9, 2011 .Dt SH 1 .Os .Sh NAME @@ -324,7 +324,7 @@ Useful for debugging. Write each command (preceded by the value of the .Va PS4 -variable) +variable subjected to parameter expansion and arithmetic expansion) to standard error before it is executed. Useful for debugging. .El diff --git a/tools/regression/bin/sh/execution/set-x3.0 b/tools/regression/bin/sh/execution/set-x3.0 new file mode 100644 index 000000000000..1ca57aca6baa --- /dev/null +++ b/tools/regression/bin/sh/execution/set-x3.0 @@ -0,0 +1,9 @@ +# $FreeBSD$ + +key='must contain this' +PS4='$key+ ' +{ r=`set -x; { :; } 2>&1 >/dev/null`; } 2>/dev/null +case $r in +*"$key"*) true ;; +*) false ;; +esac