sh: Do tilde expansion in substitutions.

This applies to word in ${v-word}, ${v+word}, ${v=word}, ${v?word} (which
inherits quoting from the outside) and in ${v%word}, ${v%%word}, ${v#word},
${v##word} (which does not inherit any quoting).

In all cases tilde expansion is only attempted at the start of word, even if
word contains spaces. This agrees with POSIX and other shells.

This is the last part of the patch tested in the exp-run.

Exp-run done by: erwin (with some other sh(1) changes)
This commit is contained in:
jilles 2010-04-03 22:04:44 +00:00
parent 2b94976ff7
commit d21d692410
2 changed files with 93 additions and 3 deletions

View File

@ -273,7 +273,6 @@ exptilde(char *p, int flag)
switch(c) {
case CTLESC: /* This means CTL* are always considered quoted. */
case CTLVAR:
case CTLENDVAR:
case CTLBACKQ:
case CTLBACKQ | CTLQUOTE:
case CTLARI:
@ -285,6 +284,7 @@ exptilde(char *p, int flag)
goto done;
break;
case '/':
case CTLENDVAR:
goto done;
}
p++;
@ -506,9 +506,9 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
int amount;
herefd = -1;
argstr(p, subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ?
EXP_CASE : 0);
EXP_CASE : 0) | EXP_TILDE);
STACKSTRNUL(expdest);
herefd = saveherefd;
argbackq = saveargbackq;

View File

@ -0,0 +1,90 @@
# $FreeBSD$
HOME=/tmp
roothome=~root
if [ "$roothome" = "~root" ]; then
echo "~root is not expanded!"
exit 2
fi
testcase() {
code="$1"
expected="$2"
oIFS="$IFS"
eval "$code"
IFS='|'
result="$#|$*"
IFS="$oIFS"
if [ "x$result" = "x$expected" ]; then
ok=x$ok
else
failures=x$failures
echo "For $code, expected $expected actual $result"
fi
}
testcase 'set -- ${$+~}' '1|/tmp'
testcase 'set -- ${$+~/}' '1|/tmp/'
testcase 'set -- ${$+~/foo}' '1|/tmp/foo'
testcase 'set -- ${$+x~}' '1|x~'
testcase 'set -- ${$+~root}' "1|$roothome"
testcase 'set -- ${$+"~"}' '1|~'
testcase 'set -- ${$+"~/"}' '1|~/'
testcase 'set -- ${$+"~/foo"}' '1|~/foo'
testcase 'set -- ${$+"x~"}' '1|x~'
testcase 'set -- ${$+"~root"}' "1|~root"
testcase 'set -- "${$+~}"' '1|~'
testcase 'set -- "${$+~/}"' '1|~/'
testcase 'set -- "${$+~/foo}"' '1|~/foo'
testcase 'set -- "${$+x~}"' '1|x~'
testcase 'set -- "${$+~root}"' "1|~root"
testcase 'set -- ${HOME#~}' '0|'
h=~
testcase 'set -- "$h"' '1|/tmp'
f=~/foo
testcase 'set -- "$f"' '1|/tmp/foo'
testcase 'set -- ${f#~}' '1|/foo'
testcase 'set -- ${f#~/}' '1|foo'
ooIFS=$IFS
IFS=m
testcase 'set -- ${$+~}' '1|/tmp'
testcase 'set -- ${$+~/foo}' '1|/tmp/foo'
testcase 'set -- ${$+$h}' '2|/t|p'
testcase 'set -- ${HOME#~}' '0|'
IFS=$ooIFS
t=\~
testcase 'set -- ${$+$t}' '1|~'
r=$(cat <<EOF
${HOME#~}
EOF
)
testcase 'set -- $r' '0|'
r=$(cat <<EOF
${HOME#'~'}
EOF
)
testcase 'set -- $r' '1|/tmp'
r=$(cat <<EOF
${t#'~'}
EOF
)
testcase 'set -- $r' '0|'
r=$(cat <<EOF
${roothome#~root}
EOF
)
testcase 'set -- $r' '0|'
r=$(cat <<EOF
${f#~}
EOF
)
testcase 'set -- $r' '1|/foo'
r=$(cat <<EOF
${f#~/}
EOF
)
testcase 'set -- $r' '1|foo'
test "x$failures" = x