Make octal/hex escapes in printf and echo output literal bytes

Fixes #1894
This commit is contained in:
ridiculousfish 2015-01-15 11:21:07 -08:00
parent 20974edc14
commit d4eded2376
6 changed files with 13 additions and 4 deletions

View file

@ -1937,8 +1937,8 @@ static int builtin_echo(parser_t &parser, wchar_t **argv)
unsigned char narrow_val = 0; unsigned char narrow_val = 0;
if (builtin_echo_parse_numeric_sequence(str + j + 1, &consumed, &narrow_val)) if (builtin_echo_parse_numeric_sequence(str + j + 1, &consumed, &narrow_val))
{ {
/* Here consumed must have been set to something */ /* Here consumed must have been set to something. The narrow_val is a literal byte that we want to output (#1894) */
wc = narrow_val; //is this OK for conversion? wc = ENCODE_DIRECT_BASE + narrow_val % 256;
} }
else else
{ {

View file

@ -357,16 +357,17 @@ long builtin_printf_state_t::print_esc(const wchar_t *escstart, bool octal_0)
esc_value = esc_value * 16 + hex_to_bin(*p); esc_value = esc_value * 16 + hex_to_bin(*p);
if (esc_length == 0) if (esc_length == 0)
this->fatal_error(_(L"missing hexadecimal number in escape")); this->fatal_error(_(L"missing hexadecimal number in escape"));
this->append_output(esc_value); this->append_output(ENCODE_DIRECT_BASE + esc_value % 256);
} }
else if (is_octal_digit(*p)) else if (is_octal_digit(*p))
{ {
/* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise). /* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise).
Allow \ooo if octal_0 && *p != L'0'; this is an undocumented Allow \ooo if octal_0 && *p != L'0'; this is an undocumented
extension to POSIX that is compatible with Bash 2.05b. */ extension to POSIX that is compatible with Bash 2.05b. */
/* Wrap mod 256, which matches historic behavior */
for (esc_length = 0, p += octal_0 && *p == L'0'; esc_length < 3 && is_octal_digit(*p); ++esc_length, ++p) for (esc_length = 0, p += octal_0 && *p == L'0'; esc_length < 3 && is_octal_digit(*p); ++esc_length, ++p)
esc_value = esc_value * 8 + octal_to_bin(*p); esc_value = esc_value * 8 + octal_to_bin(*p);
this->append_output(esc_value); this->append_output(ENCODE_DIRECT_BASE + esc_value % 256);
} }
else if (*p && wcschr(L"\"\\abcefnrtv", *p)) else if (*p && wcschr(L"\"\\abcefnrtv", *p))
{ {

View file

@ -30,4 +30,8 @@ echo
# Bogus printf specifier, should produce no stdout # Bogus printf specifier, should produce no stdout
printf "%5" 10 ^ /dev/null printf "%5" 10 ^ /dev/null
# Octal escapes produce literal bytes, not characters
# \376 is 0xFE
printf '\376' | xxd -p
true true

View file

@ -13,3 +13,4 @@ foo bar baz
I P Q R I P Q R
Test escapes Test escapes
a a
fe

View file

@ -118,6 +118,8 @@ echo -e 'abc\cdef' # won't output a newline!
echo '' echo ''
echo - echo -
echo -ne '\376' | xxd -p
echo -e Catch your breath echo -e Catch your breath
echo -e 'abc\x21def' echo -e 'abc\x21def'

View file

@ -34,6 +34,7 @@ abcQdef
abcQ2def abcQ2def
abc abc
- -
fe
Catch your breath Catch your breath
abc!def abc!def
abc!1def abc!1def