aboutsummaryrefslogtreecommitdiffhomepage
path: root/expand.cpp
diff options
context:
space:
mode:
authorGravatar Kevin Ballard <kevin@sb.org>2014-08-20 21:19:08 -0700
committerGravatar Kevin Ballard <kevin@sb.org>2014-08-20 21:45:07 -0700
commit3981b644d68f6b6947b4a12810c2fa5e09da4e58 (patch)
treefd00d82b90283ba3810eb04ffc40b1632fc1e155 /expand.cpp
parentd0c85471b40fee548efc35a370f5d5c4b656f66a (diff)
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
Diffstat (limited to 'expand.cpp')
-rw-r--r--expand.cpp57
1 files changed, 44 insertions, 13 deletions
diff --git a/expand.cpp b/expand.cpp
index d8cf4a1a..d75c6572 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<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);