diff --git a/expand.cpp b/expand.cpp index d8cf4a1ab..d75c65723 100644 --- a/expand.cpp +++ b/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 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); diff --git a/expand.h b/expand.h index 3956b1f16..14a4f4772 100644 --- a/expand.h +++ b/expand.h @@ -102,6 +102,11 @@ enum */ INTERNAL_SEPARATOR, + /** + Character representing an empty variable expansion. + Only used transitively while expanding variables. + */ + VARIABLE_EXPAND_EMPTY, } ; diff --git a/tests/expansion.err b/tests/expansion.err new file mode 100644 index 000000000..e69de29bb diff --git a/tests/expansion.in b/tests/expansion.in new file mode 100644 index 000000000..d362e7895 --- /dev/null +++ b/tests/expansion.in @@ -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 diff --git a/tests/expansion.out b/tests/expansion.out new file mode 100644 index 000000000..3e7631804 --- /dev/null +++ b/tests/expansion.out @@ -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 diff --git a/tests/expansion.status b/tests/expansion.status new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/expansion.status @@ -0,0 +1 @@ +0 diff --git a/tests/top.out b/tests/top.out index 768526c66..acf52d424 100644 --- a/tests/top.out +++ b/tests/top.out @@ -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