mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-12 21:18:53 +00:00
Fix double expansions ($$foo
)
Double expansions of variables had the following issues: * `"$$foo"` threw an error no matter what the value of `$foo` was. * `set -l foo ''; echo $$foo` threw an error because of the expansion of `$foo` to `''`. With this change, double expansion always works properly. When double-expanding a multi-valued variable, in a double-quoted string the first word of the inner expansion is used for the outer expansion, and outside of a quoted string every word is used for the double-expansion in each of the arguments. > set -l foo bar baz > set -l bar one two > set -l baz three four > echo "$$foo" one two baz > echo $$foo one two three four
This commit is contained in:
parent
d0c85471b4
commit
3981b644d6
7 changed files with 153 additions and 13 deletions
57
expand.cpp
57
expand.cpp
|
@ -1086,10 +1086,15 @@ static int expand_variables_internal(parser_t &parser, wchar_t * const in, std::
|
|||
|
||||
while (1)
|
||||
{
|
||||
if (!(in[stop_pos ]))
|
||||
const wchar_t nc = in[stop_pos];
|
||||
if (!(nc))
|
||||
break;
|
||||
if (!(iswalnum(in[stop_pos]) ||
|
||||
(wcschr(L"_", in[stop_pos])!= 0)))
|
||||
if (nc == VARIABLE_EXPAND_EMPTY)
|
||||
{
|
||||
stop_pos++;
|
||||
break;
|
||||
}
|
||||
if (!(wcsvarchr(nc)))
|
||||
break;
|
||||
|
||||
stop_pos++;
|
||||
|
@ -1108,7 +1113,15 @@ static int expand_variables_internal(parser_t &parser, wchar_t * const in, std::
|
|||
}
|
||||
|
||||
var_tmp.append(in + start_pos, var_len);
|
||||
env_var_t var_val = expand_var(var_tmp.c_str());
|
||||
env_var_t var_val;
|
||||
if (var_len == 1 && var_tmp[0] == VARIABLE_EXPAND_EMPTY)
|
||||
{
|
||||
var_val = env_var_t::missing_var();
|
||||
}
|
||||
else
|
||||
{
|
||||
var_val = expand_var(var_tmp.c_str());
|
||||
}
|
||||
|
||||
if (! var_val.missing())
|
||||
{
|
||||
|
@ -1174,7 +1187,18 @@ static int expand_variables_internal(parser_t &parser, wchar_t * const in, std::
|
|||
{
|
||||
in[i]=0;
|
||||
wcstring res = in;
|
||||
res.push_back(INTERNAL_SEPARATOR);
|
||||
if (i > 0)
|
||||
{
|
||||
if (in[i-1] != VARIABLE_EXPAND_SINGLE)
|
||||
{
|
||||
res.push_back(INTERNAL_SEPARATOR);
|
||||
}
|
||||
else if (var_item_list.empty() || var_item_list.front().empty())
|
||||
{
|
||||
// first expansion is empty, but we need to recursively expand
|
||||
res.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j=0; j<var_item_list.size(); j++)
|
||||
{
|
||||
|
@ -1204,14 +1228,18 @@ static int expand_variables_internal(parser_t &parser, wchar_t * const in, std::
|
|||
if (is_ok)
|
||||
{
|
||||
wcstring new_in;
|
||||
new_in.append(in, i);
|
||||
|
||||
if (start_pos > 0)
|
||||
new_in.append(in, start_pos - 1);
|
||||
|
||||
// at this point new_in.size() is start_pos - 1
|
||||
if (start_pos>1 && new_in[start_pos-2]!=VARIABLE_EXPAND)
|
||||
if (i > 0)
|
||||
{
|
||||
new_in.push_back(INTERNAL_SEPARATOR);
|
||||
if (in[i-1] != VARIABLE_EXPAND)
|
||||
{
|
||||
new_in.push_back(INTERNAL_SEPARATOR);
|
||||
}
|
||||
else if (next.empty())
|
||||
{
|
||||
new_in.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
}
|
||||
new_in.append(next);
|
||||
new_in.append(in + stop_pos);
|
||||
|
@ -1243,8 +1271,11 @@ static int expand_variables_internal(parser_t &parser, wchar_t * const in, std::
|
|||
Expansion to single argument.
|
||||
*/
|
||||
wcstring res;
|
||||
in[i] = 0;
|
||||
res.append(in);
|
||||
res.append(in, i);
|
||||
if (i > 0 && in[i-1] == VARIABLE_EXPAND_SINGLE)
|
||||
{
|
||||
res.push_back(VARIABLE_EXPAND_EMPTY);
|
||||
}
|
||||
res.append(in + stop_pos);
|
||||
|
||||
is_ok &= expand_variables2(parser, res, out, i, errors);
|
||||
|
|
5
expand.h
5
expand.h
|
@ -102,6 +102,11 @@ enum
|
|||
*/
|
||||
INTERNAL_SEPARATOR,
|
||||
|
||||
/**
|
||||
Character representing an empty variable expansion.
|
||||
Only used transitively while expanding variables.
|
||||
*/
|
||||
VARIABLE_EXPAND_EMPTY,
|
||||
}
|
||||
;
|
||||
|
||||
|
|
0
tests/expansion.err
Normal file
0
tests/expansion.err
Normal file
64
tests/expansion.in
Normal file
64
tests/expansion.in
Normal file
|
@ -0,0 +1,64 @@
|
|||
# Test expansion of variables
|
||||
|
||||
function show --description 'Prints argument count followed by arguments'
|
||||
echo (count $argv) $argv
|
||||
end
|
||||
|
||||
set -l foo
|
||||
show "$foo"
|
||||
show $foo
|
||||
show "prefix$foo"
|
||||
show prefix$foo
|
||||
|
||||
show "$$foo"
|
||||
show $$foo
|
||||
show "prefix$$foo"
|
||||
show prefix$$foo
|
||||
|
||||
set -l foo ''
|
||||
show "$foo"
|
||||
show $foo
|
||||
show "prefix$foo"
|
||||
show prefix$foo
|
||||
|
||||
show "$$foo"
|
||||
show $$foo
|
||||
show "prefix$$foo"
|
||||
show prefix$$foo
|
||||
|
||||
set -l foo bar
|
||||
set -l bar
|
||||
show "$$foo"
|
||||
show $$foo
|
||||
show "prefix$$foo"
|
||||
show prefix$$foo
|
||||
|
||||
set -l bar baz
|
||||
show "$$foo"
|
||||
show $$foo
|
||||
show "prefix$$foo"
|
||||
show prefix$$foo
|
||||
|
||||
set -l bar baz quux
|
||||
show "$$foo"
|
||||
show $$foo
|
||||
show "prefix$$foo"
|
||||
show prefix$$foo
|
||||
|
||||
set -l foo bar fooer fooest
|
||||
set -l fooer
|
||||
set -l fooest
|
||||
show "$$foo"
|
||||
show $$foo
|
||||
show "prefix$$foo"
|
||||
show prefix$$foo
|
||||
|
||||
set -l fooer ''
|
||||
show $$foo
|
||||
show prefix$$foo
|
||||
|
||||
set -l foo bar '' fooest
|
||||
show "$$foo"
|
||||
show $$foo
|
||||
show "prefix$$foo"
|
||||
show prefix$$foo
|
38
tests/expansion.out
Normal file
38
tests/expansion.out
Normal file
|
@ -0,0 +1,38 @@
|
|||
1
|
||||
0
|
||||
1 prefix
|
||||
0
|
||||
1
|
||||
0
|
||||
1 prefix
|
||||
0
|
||||
1
|
||||
1
|
||||
1 prefix
|
||||
1 prefix
|
||||
1
|
||||
0
|
||||
1 prefix
|
||||
0
|
||||
1
|
||||
0
|
||||
1 prefix
|
||||
0
|
||||
1 baz
|
||||
1 baz
|
||||
1 prefixbaz
|
||||
1 prefixbaz
|
||||
1 baz quux
|
||||
2 baz quux
|
||||
1 prefixbaz quux
|
||||
2 prefixbaz prefixquux
|
||||
1 baz quux fooer fooest
|
||||
2 baz quux
|
||||
1 prefixbaz quux fooer fooest
|
||||
2 prefixbaz prefixquux
|
||||
3 baz quux
|
||||
3 prefixbaz prefixquux prefix
|
||||
1 baz quux fooest
|
||||
2 baz quux
|
||||
1 prefixbaz quux fooest
|
||||
2 prefixbaz prefixquux
|
1
tests/expansion.status
Normal file
1
tests/expansion.status
Normal file
|
@ -0,0 +1 @@
|
|||
0
|
|
@ -1,4 +1,5 @@
|
|||
Testing high level script functionality
|
||||
File expansion.in tested ok
|
||||
File printf.in tested ok
|
||||
File test1.in tested ok
|
||||
File test2.in tested ok
|
||||
|
|
Loading…
Reference in a new issue