mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
'echo -' should output a dash instead of treating it as options
Fixes #1459
This commit is contained in:
parent
c7aca5cc35
commit
3cbace98a7
3 changed files with 53 additions and 39 deletions
90
builtin.cpp
90
builtin.cpp
|
@ -1610,62 +1610,70 @@ static int builtin_echo(parser_t &parser, wchar_t **argv)
|
||||||
if (! *argv++)
|
if (! *argv++)
|
||||||
return STATUS_BUILTIN_ERROR;
|
return STATUS_BUILTIN_ERROR;
|
||||||
|
|
||||||
/* Process options */
|
/* Process options. Options must come at the beginning - the first non-option kicks us out. */
|
||||||
bool print_newline = true, print_spaces = true, interpret_special_chars = false;
|
bool print_newline = true, print_spaces = true, interpret_special_chars = false;
|
||||||
while (*argv)
|
size_t option_idx = 0;
|
||||||
|
for (option_idx = 0; argv[option_idx] != NULL; option_idx++)
|
||||||
{
|
{
|
||||||
wchar_t *s = *argv, c = *s;
|
const wchar_t *arg = argv[option_idx];
|
||||||
if (c == L'-')
|
assert(arg != NULL);
|
||||||
|
bool arg_is_valid_option = false;
|
||||||
|
if (arg[0] == L'-')
|
||||||
{
|
{
|
||||||
/* Ensure that option is valid */
|
// We have a leading dash. Ensure that every subseqnent character is a valid option.
|
||||||
for (++s, c = *s; c != L'\0'; c = *(++s))
|
size_t i = 1;
|
||||||
|
while (arg[i] != L'\0' && wcschr(L"nesE", arg[i]) != NULL)
|
||||||
{
|
{
|
||||||
if (c != L'n' && c != L'e' && c != L's' && c != L'E')
|
i++;
|
||||||
{
|
|
||||||
goto invalid_echo_option;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse option */
|
|
||||||
for (s = *argv, ++s, c = *s; c != L'\0'; c = *(++s))
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case L'n':
|
|
||||||
print_newline = false;
|
|
||||||
break;
|
|
||||||
case L'e':
|
|
||||||
interpret_special_chars = true;
|
|
||||||
break;
|
|
||||||
case L's':
|
|
||||||
// fish-specific extension,
|
|
||||||
// which we should try to nix
|
|
||||||
print_spaces = false;
|
|
||||||
break;
|
|
||||||
case L'E':
|
|
||||||
interpret_special_chars = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// We must have at least two characters to be a valid option, and have consumed the whole string
|
||||||
|
arg_is_valid_option = (i >= 2 && arg[i] == L'\0');
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (! arg_is_valid_option)
|
||||||
{
|
{
|
||||||
invalid_echo_option:
|
// This argument is not an option, so there are no more options
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
argv++;
|
|
||||||
|
// Ok, we are sure the argument is an option. Parse it.
|
||||||
|
assert(arg_is_valid_option);
|
||||||
|
for (size_t i=1; arg[i] != L'\0'; i++)
|
||||||
|
{
|
||||||
|
switch (arg[i])
|
||||||
|
{
|
||||||
|
case L'n':
|
||||||
|
print_newline = false;
|
||||||
|
break;
|
||||||
|
case L'e':
|
||||||
|
interpret_special_chars = true;
|
||||||
|
break;
|
||||||
|
case L's':
|
||||||
|
print_spaces = false;
|
||||||
|
break;
|
||||||
|
case L'E':
|
||||||
|
interpret_special_chars = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "Unexpected character in builtin_echo argument");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The special character \c can be used to indicate no more output */
|
/* The special character \c can be used to indicate no more output */
|
||||||
bool continue_output = true;
|
bool continue_output = true;
|
||||||
|
|
||||||
for (size_t idx = 0; continue_output && argv[idx] != NULL; idx++)
|
/* Skip over the options */
|
||||||
|
const wchar_t * const *args_to_echo = argv + option_idx;
|
||||||
|
for (size_t idx = 0; continue_output && args_to_echo[idx] != NULL; idx++)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (print_spaces && idx > 0)
|
if (print_spaces && idx > 0)
|
||||||
|
{
|
||||||
stdout_buffer.push_back(' ');
|
stdout_buffer.push_back(' ');
|
||||||
|
}
|
||||||
|
|
||||||
const wchar_t *str = argv[idx];
|
const wchar_t *str = args_to_echo[idx];
|
||||||
for (size_t j=0; continue_output && str[j]; j++)
|
for (size_t j=0; continue_output && str[j]; j++)
|
||||||
{
|
{
|
||||||
if (! interpret_special_chars || str[j] != L'\\')
|
if (! interpret_special_chars || str[j] != L'\\')
|
||||||
|
@ -1736,12 +1744,16 @@ invalid_echo_option:
|
||||||
j += consumed;
|
j += consumed;
|
||||||
|
|
||||||
if (continue_output)
|
if (continue_output)
|
||||||
|
{
|
||||||
stdout_buffer.push_back(wc);
|
stdout_buffer.push_back(wc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (print_newline && continue_output)
|
if (print_newline && continue_output)
|
||||||
|
{
|
||||||
stdout_buffer.push_back('\n');
|
stdout_buffer.push_back('\n');
|
||||||
|
}
|
||||||
return STATUS_BUILTIN_OK;
|
return STATUS_BUILTIN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ echo -e 'abc\121def'
|
||||||
echo -e 'abc\1212def'
|
echo -e 'abc\1212def'
|
||||||
echo -e 'abc\cdef' # won't output a newline!
|
echo -e 'abc\cdef' # won't output a newline!
|
||||||
echo ''
|
echo ''
|
||||||
|
echo -
|
||||||
|
|
||||||
echo -e Catch your breath
|
echo -e Catch your breath
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ abc!def
|
||||||
abcQdef
|
abcQdef
|
||||||
abcQ2def
|
abcQ2def
|
||||||
abc
|
abc
|
||||||
|
-
|
||||||
Catch your breath
|
Catch your breath
|
||||||
abc!def
|
abc!def
|
||||||
abc!1def
|
abc!1def
|
||||||
|
|
Loading…
Reference in a new issue