mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-31 20:31:19 -03:00
printf: Don't die on incomplete conversions
POSIX dictates here that incomplete conversions, like in
printf %d\n 15.2
or
printf %d 14g
are still printed along with any error.
This seems alright, as it allows users to silence stderr to accept incomplete conversions.
This commit implements it, but what's a bit weird is the ordering between stdout and stderr,
causing the error to be printed _after_, like
15
14
15.1: value not completely converted
14,2: value not completely converted
but that seems like a general issue with how we buffer the streams.
(I know that nonfatal_error is a copy of most of fatal_error - I tried
differently, and va_* is weird)
Fixes #5532.
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
- `math` now accepts `--scale=max` for the maximum scale (#5579).
|
- `math` now accepts `--scale=max` for the maximum scale (#5579).
|
||||||
- `complete --do-complete` now also does fuzzy matches (#5467).
|
- `complete --do-complete` now also does fuzzy matches (#5467).
|
||||||
- `count` now also counts lines fed on stdin (#5744).
|
- `count` now also counts lines fed on stdin (#5744).
|
||||||
|
- `printf` prints what it can when input hasn't been fully converted to a number, but still prints an error (#5532).
|
||||||
|
|
||||||
### Interactive improvements
|
### Interactive improvements
|
||||||
- Major improvements in performance and functionality to the 'sorin' sample prompt (#5411).
|
- Major improvements in performance and functionality to the 'sorin' sample prompt (#5411).
|
||||||
|
|||||||
@@ -90,8 +90,10 @@ struct builtin_printf_state_t {
|
|||||||
|
|
||||||
int print_formatted(const wchar_t *format, int argc, wchar_t **argv);
|
int print_formatted(const wchar_t *format, int argc, wchar_t **argv);
|
||||||
|
|
||||||
|
void nonfatal_error(const wchar_t *fmt, ...);
|
||||||
void fatal_error(const wchar_t *format, ...);
|
void fatal_error(const wchar_t *format, ...);
|
||||||
|
|
||||||
|
|
||||||
long print_esc(const wchar_t *escstart, bool octal_0);
|
long print_esc(const wchar_t *escstart, bool octal_0);
|
||||||
void print_esc_string(const wchar_t *str);
|
void print_esc_string(const wchar_t *str);
|
||||||
void print_esc_char(wchar_t c);
|
void print_esc_char(wchar_t c);
|
||||||
@@ -193,6 +195,22 @@ static int octal_to_bin(wchar_t c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void builtin_printf_state_t::nonfatal_error(const wchar_t *fmt, ...) {
|
||||||
|
// Don't error twice.
|
||||||
|
if (early_exit) return;
|
||||||
|
|
||||||
|
va_list va;
|
||||||
|
va_start(va, fmt);
|
||||||
|
wcstring errstr = vformat_string(fmt, va);
|
||||||
|
va_end(va);
|
||||||
|
streams.err.append(errstr);
|
||||||
|
if (!string_suffixes_string(L"\n", errstr)) streams.err.push_back(L'\n');
|
||||||
|
|
||||||
|
// We set the exit code to error, because one occured,
|
||||||
|
// but we don't do an early exit so we still print what we can.
|
||||||
|
this->exit_code = STATUS_CMD_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...) {
|
void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...) {
|
||||||
// Don't error twice.
|
// Don't error twice.
|
||||||
if (early_exit) return;
|
if (early_exit) return;
|
||||||
@@ -207,7 +225,6 @@ void builtin_printf_state_t::fatal_error(const wchar_t *fmt, ...) {
|
|||||||
this->exit_code = STATUS_CMD_ERROR;
|
this->exit_code = STATUS_CMD_ERROR;
|
||||||
this->early_exit = true;
|
this->early_exit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void builtin_printf_state_t::append_output(wchar_t c) {
|
void builtin_printf_state_t::append_output(wchar_t c) {
|
||||||
// Don't output if we're done.
|
// Don't output if we're done.
|
||||||
if (early_exit) return;
|
if (early_exit) return;
|
||||||
@@ -241,10 +258,12 @@ void builtin_printf_state_t::verify_numeric(const wchar_t *s, const wchar_t *end
|
|||||||
this->fatal_error(L"%ls: %s", s, std::strerror(errcode));
|
this->fatal_error(L"%ls: %s", s, std::strerror(errcode));
|
||||||
}
|
}
|
||||||
} else if (*end) {
|
} else if (*end) {
|
||||||
if (s == end)
|
if (s == end) {
|
||||||
this->fatal_error(_(L"%ls: expected a numeric value"), s);
|
this->fatal_error(_(L"%ls: expected a numeric value"), s);
|
||||||
else
|
} else {
|
||||||
this->fatal_error(_(L"%ls: value not completely converted"), s);
|
// This isn't entirely fatal - the value should still be printed.
|
||||||
|
this->nonfatal_error(_(L"%ls: value not completely converted"), s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
2,34: value not completely converted
|
2,34: value not completely converted
|
||||||
0xABCDEF12345678901: Number out of range
|
0xABCDEF12345678901: Number out of range
|
||||||
|
15.1: value not completely converted
|
||||||
|
|||||||
@@ -72,3 +72,7 @@ printf 'long hex4 %X\n' 0xABCDEF12345678901
|
|||||||
printf 'long decimal %d\n' 498216206594
|
printf 'long decimal %d\n' 498216206594
|
||||||
printf 'long signed %d\n' -498216206595
|
printf 'long signed %d\n' -498216206595
|
||||||
printf 'long signed to unsigned %u\n' -498216206596
|
printf 'long signed to unsigned %u\n' -498216206596
|
||||||
|
|
||||||
|
# Verify numeric conversion still happens even if it couldn't be fully converted
|
||||||
|
printf '%d\n' 15.1
|
||||||
|
echo $status
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ a
|
|||||||
a
|
a
|
||||||
0000000 376
|
0000000 376
|
||||||
0000001
|
0000001
|
||||||
|
1.230000e+00
|
||||||
2.000000e+00
|
2.000000e+00
|
||||||
3,450000e+00
|
3,450000e+00
|
||||||
4,560000e+00
|
4,560000e+00
|
||||||
@@ -24,3 +25,5 @@ long hex3 ABCDEF1234567890
|
|||||||
long hex3 ABCDEF1234567890
|
long hex3 ABCDEF1234567890
|
||||||
long hex4 long decimal 498216206594
|
long hex4 long decimal 498216206594
|
||||||
long signed -498216206595
|
long signed -498216206595
|
||||||
|
long signed to unsigned 18446743575493345020
|
||||||
|
15
|
||||||
|
|||||||
Reference in New Issue
Block a user