sh: Do parameter expansion before printing PS4 (set -x).

The function name expandstr() and the general idea of doing this kind of
expansion by treating the text as a here document without end marker is from
dash.

All variants of parameter expansion and arithmetic expansion also work (the
latter is not required by POSIX but it does not take extra code and many
other shells also allow it).

Command substitution is prevented because I think it causes too much code to
be re-entered (for example creating an unbounded recursion of trace lines).

Unfortunately, our LINENO is somewhat crude, otherwise PS4='$LINENO+ ' would
be quite useful.
This commit is contained in:
Jilles Tjoelker 2011-06-09 23:12:23 +00:00
parent b24bfc5ae8
commit 292e667663
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=222907
6 changed files with 60 additions and 4 deletions

View File

@ -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(' ');

View File

@ -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);

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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

View File

@ -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