aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--expand.cpp57
-rw-r--r--expand.h5
-rw-r--r--tests/expansion.err0
-rw-r--r--tests/expansion.in64
-rw-r--r--tests/expansion.out38
-rw-r--r--tests/expansion.status1
-rw-r--r--tests/top.out1
7 files changed, 153 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);
diff --git a/expand.h b/expand.h
index 3956b1f1..14a4f477 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 00000000..e69de29b
--- /dev/null
+++ b/tests/expansion.err
diff --git a/tests/expansion.in b/tests/expansion.in
new file mode 100644
index 00000000..d362e789
--- /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 00000000..3e763180
--- /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 00000000..573541ac
--- /dev/null
+++ b/tests/expansion.status
@@ -0,0 +1 @@
+0
diff --git a/tests/top.out b/tests/top.out
index 768526c6..acf52d42 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