aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--builtin.cpp95
-rw-r--r--builtin_commandline.cpp9
-rw-r--r--common.cpp9
-rw-r--r--common.h3
-rw-r--r--doc_src/function.txt2
-rw-r--r--fish.xcodeproj/project.pbxproj6
-rw-r--r--osx/config.h4
-rw-r--r--tests/function.in14
-rw-r--r--tests/function.out4
9 files changed, 97 insertions, 49 deletions
diff --git a/builtin.cpp b/builtin.cpp
index 71ba8a32..59778862 100644
--- a/builtin.cpp
+++ b/builtin.cpp
@@ -1655,7 +1655,7 @@ static int builtin_functions(parser_t &parser, wchar_t **argv)
return STATUS_BUILTIN_ERROR;
}
- if ((wcsfuncname(new_func.c_str()) != 0) || parser_keywords_is_reserved(new_func))
+ if ((wcsfuncname(new_func) != 0) || parser_keywords_is_reserved(new_func))
{
append_format(stderr_buffer,
_(L"%ls: Illegal function name '%ls'\n"),
@@ -2002,16 +2002,24 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
int res=STATUS_BUILTIN_OK;
wchar_t *desc=0;
std::vector<event_t> events;
- std::auto_ptr<wcstring_list_t> named_arguments(NULL);
+
+ bool has_named_arguments = false;
+ wcstring_list_t named_arguments;
wcstring_list_t inherit_vars;
- wchar_t *name = 0;
bool shadows = true;
woptind=0;
wcstring_list_t wrap_targets;
-
+
+ /* If -a/--argument-names is specified before the function name,
+ then the function name is the last positional, e.g. `function -a arg1 arg2 name`.
+ If it is specified after the function name (or not specified at all) then the
+ function name is the first positional. This is the common case. */
+ bool name_is_first_positional = true;
+ wcstring_list_t positionals;
+
const struct woption long_options[] =
{
{ L"description", required_argument, 0, 'd' },
@@ -2032,9 +2040,10 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
{
int opt_index = 0;
+ // The leading - here specifies RETURN_IN_ORDER
int opt = wgetopt_long(argc,
argv,
- L"d:s:j:p:v:e:haSV:",
+ L"-d:s:j:p:v:e:haSV:",
long_options,
&opt_index);
if (opt == -1)
@@ -2176,8 +2185,9 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
}
case 'a':
- if (named_arguments.get() == NULL)
- named_arguments.reset(new wcstring_list_t);
+ has_named_arguments = true;
+ /* The function name is the first positional unless -a comes before all positionals */
+ name_is_first_positional = ! positionals.empty();
break;
case 'S':
@@ -2204,6 +2214,11 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
case 'h':
builtin_print_help(parser, argv[0], stdout_buffer);
return STATUS_BUILTIN_OK;
+
+ case 1:
+ assert(woptarg != NULL);
+ positionals.push_back(woptarg);
+ break;
case '?':
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
@@ -2216,87 +2231,93 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
if (!res)
{
-
- if (argc == woptind)
+ /* Determine the function name, and remove it from the list of positionals */
+ wcstring function_name;
+ bool name_is_missing = positionals.empty();
+ if (! name_is_missing)
+ {
+ if (name_is_first_positional)
+ {
+ function_name = positionals.front();
+ positionals.erase(positionals.begin());
+ }
+ else
+ {
+ function_name = positionals.back();
+ positionals.erase(positionals.end() - 1);
+ }
+ }
+
+ if (name_is_missing)
{
append_format(*out_err,
_(L"%ls: Expected function name\n"),
argv[0]);
res=1;
}
- else if (wcsfuncname(argv[woptind]))
+ else if (wcsfuncname(function_name))
{
append_format(*out_err,
_(L"%ls: Illegal function name '%ls'\n"),
argv[0],
- argv[woptind]);
+ function_name.c_str());
res=1;
}
- else if (parser_keywords_is_reserved(argv[woptind]))
+ else if (parser_keywords_is_reserved(function_name))
{
append_format(*out_err,
_(L"%ls: The name '%ls' is reserved,\nand can not be used as a function name\n"),
argv[0],
- argv[woptind]);
+ function_name.c_str());
res=1;
}
- else if (! wcslen(argv[woptind]))
+ else if (function_name.empty())
{
append_format(*out_err, _(L"%ls: No function name given\n"), argv[0]);
res=1;
}
else
{
-
- name = argv[woptind++];
-
- if (named_arguments.get())
+ if (has_named_arguments)
{
- while (woptind < argc)
+ /* All remaining positionals are named arguments */
+ named_arguments.swap(positionals);
+ for (size_t i=0; i < named_arguments.size(); i++)
{
- if (wcsvarname(argv[woptind]))
+ if (wcsvarname(named_arguments.at(i)))
{
append_format(*out_err,
_(L"%ls: Invalid variable name '%ls'\n"),
argv[0],
- argv[woptind]);
+ named_arguments.at(i).c_str());
res = STATUS_BUILTIN_ERROR;
break;
}
-
- named_arguments->push_back(argv[woptind++]);
}
}
- else if (woptind != argc)
+ else if (! positionals.empty())
{
+ // +1 because we already got the function name
append_format(*out_err,
_(L"%ls: Expected one argument, got %d\n"),
argv[0],
- argc);
+ positionals.size() + 1);
res=1;
-
}
}
- }
- if (res)
- {
- builtin_print_help(parser, argv[0], *out_err);
- }
- else
- {
+ /* Here we actually define the function! */
function_data_t d;
- d.name = name;
+ d.name = function_name;
if (desc)
d.description = desc;
d.events.swap(events);
d.shadows = shadows;
- if (named_arguments.get())
- d.named_arguments.swap(*named_arguments);
+ d.named_arguments.swap(named_arguments);
d.inherit_vars.swap(inherit_vars);
for (size_t i=0; i<d.events.size(); i++)
@@ -2312,7 +2333,7 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
// Handle wrap targets
for (size_t w=0; w < wrap_targets.size(); w++)
{
- complete_add_wrapper(name, wrap_targets.at(w));
+ complete_add_wrapper(function_name, wrap_targets.at(w));
}
}
diff --git a/builtin_commandline.cpp b/builtin_commandline.cpp
index 339cb0d1..01bc123a 100644
--- a/builtin_commandline.cpp
+++ b/builtin_commandline.cpp
@@ -206,7 +206,9 @@ static void write_part(const wchar_t *begin,
{
case TOK_STRING:
{
- out.append(escape_string(tok_last(&tok), UNESCAPE_INCOMPLETE));
+ wcstring tmp = tok_last(&tok);
+ unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
+ out.append(tmp);
out.push_back(L'\n');
break;
}
@@ -230,8 +232,9 @@ static void write_part(const wchar_t *begin,
}
// debug( 0, L"woot2 %ls -> %ls", buff, esc );
-
- stdout_buffer.append(begin, end - begin);
+ wcstring tmp = wcstring(begin, end - begin);
+ unescape_string_in_place(&tmp, UNESCAPE_INCOMPLETE);
+ stdout_buffer.append(tmp);
stdout_buffer.append(L"\n");
}
diff --git a/common.cpp b/common.cpp
index 3440f075..6767e351 100644
--- a/common.cpp
+++ b/common.cpp
@@ -481,9 +481,14 @@ const wchar_t *wcsvarname(const wchar_t *str)
return NULL;
}
-const wchar_t *wcsfuncname(const wchar_t *str)
+const wchar_t *wcsvarname(const wcstring &str)
{
- return wcschr(str, L'/');
+ return wcsvarname(str.c_str());
+}
+
+const wchar_t *wcsfuncname(const wcstring &str)
+{
+ return wcschr(str.c_str(), L'/');
}
diff --git a/common.h b/common.h
index a4bee08f..f0d55894 100644
--- a/common.h
+++ b/common.h
@@ -696,6 +696,7 @@ void append_formatv(wcstring &str, const wchar_t *format, va_list ap);
*/
const wchar_t *wcsvarname(const wchar_t *str);
+const wchar_t *wcsvarname(const wcstring &str);
/**
@@ -704,7 +705,7 @@ const wchar_t *wcsvarname(const wchar_t *str);
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
-const wchar_t *wcsfuncname(const wchar_t *str);
+const wchar_t *wcsfuncname(const wcstring &str);
/**
Test if the given string is valid in a variable name
diff --git a/doc_src/function.txt b/doc_src/function.txt
index 1f9fb47d..e58d6513 100644
--- a/doc_src/function.txt
+++ b/doc_src/function.txt
@@ -2,7 +2,7 @@
\subsection function-synopsis Synopsis
\fish{synopsis}
-function [OPTIONS] NAME; BODY; end
+function NAME [OPTIONS]; BODY; end
\endfish
\subsection function-description Description
diff --git a/fish.xcodeproj/project.pbxproj b/fish.xcodeproj/project.pbxproj
index 037563bc..74b55a76 100644
--- a/fish.xcodeproj/project.pbxproj
+++ b/fish.xcodeproj/project.pbxproj
@@ -1327,7 +1327,7 @@
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
"BINDIR=L\\\"/usr/local/bin\\\"",
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
- "FISH_BUILD_VERSION=\\\"2.2b1\\\"",
+ "FISH_BUILD_VERSION=\\\"2.2b1-git\\\"",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
@@ -1455,7 +1455,7 @@
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
"BINDIR=L\\\"/usr/local/bin\\\"",
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
- "FISH_BUILD_VERSION=\\\"2.2b1\\\"",
+ "FISH_BUILD_VERSION=\\\"2.2b1-git\\\"",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -1483,7 +1483,7 @@
"SYSCONFDIR=L\\\"/usr/local/etc\\\"",
"BINDIR=L\\\"/usr/local/bin\\\"",
"DOCDIR=L\\\"/usr/local/share/doc\\\"",
- "FISH_BUILD_VERSION=\\\"2.2b1\\\"",
+ "FISH_BUILD_VERSION=\\\"2.2b1-git\\\"",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
diff --git a/osx/config.h b/osx/config.h
index a5b0df28..5a8e6b26 100644
--- a/osx/config.h
+++ b/osx/config.h
@@ -222,7 +222,7 @@
#define PACKAGE_NAME "fish"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "fish 2.2b1"
+#define PACKAGE_STRING "fish 2.2b1-git"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "fish"
@@ -231,7 +231,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "2.2b1"
+#define PACKAGE_VERSION "2.2b1-git"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
diff --git a/tests/function.in b/tests/function.in
index e533b25b..747bbcec 100644
--- a/tests/function.in
+++ b/tests/function.in
@@ -30,3 +30,17 @@ set foo 'bad foo'
set bar 'bad bar'
set baz 'bad baz'
frob
+
+# Test that -a does not mix up the function name with arguments
+# See #2068
+function name1 -a arg1 arg2 ; end
+function -a arg1 arg2 name2 ; end
+function name3 --argument-names arg1 arg2 ; end
+function --argument-names arg1 arg2 name4 ; end
+for i in (seq 4)
+ if functions -q name$i
+ echo "Function name$i found"
+ else
+ echo "Function name$i not found, but should have been"
+ end
+end
diff --git a/tests/function.out b/tests/function.out
index 3fa70990..5a3da619 100644
--- a/tests/function.out
+++ b/tests/function.out
@@ -18,3 +18,7 @@ $bar: (5)
4: ''
5: '3'
$baz: (0)
+Function name1 found
+Function name2 found
+Function name3 found
+Function name4 found