echo: Buffer output and write it in one go

`streams.out.push_back` for fd_streams_t writes to the
fd *immediately*. We might want to introduce a general buffering
strategy, but in this case writing it in one go is the simplest and
seems acceptable - we already have constrained the argument size, so
just pushing it out should work well enough.

See #7836
This commit is contained in:
Fabian Homborg 2021-03-21 17:46:43 +01:00
parent e4fd664bbb
commit 1018cb2a81

View file

@ -207,16 +207,19 @@ maybe_t<int> builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **arg
bool continue_output = true;
const wchar_t *const *args_to_echo = argv + optind;
// We buffer output so we can write in one go,
// this matters when writing to an fd.
wcstring out;
for (size_t idx = 0; continue_output && args_to_echo[idx] != nullptr; idx++) {
if (opts.print_spaces && idx > 0) {
streams.out.push_back(' ');
out.push_back(' ');
}
const wchar_t *str = args_to_echo[idx];
for (size_t j = 0; continue_output && str[j]; j++) {
if (!opts.interpret_special_chars || str[j] != L'\\') {
// Not an escape.
streams.out.push_back(str[j]);
out.push_back(str[j]);
} else {
// Most escapes consume one character in addition to the backslash; the numeric
// sequences may consume more, while an unrecognized escape sequence consumes none.
@ -286,13 +289,18 @@ maybe_t<int> builtin_echo(parser_t &parser, io_streams_t &streams, wchar_t **arg
j += consumed;
if (continue_output) {
streams.out.push_back(wc);
out.push_back(wc);
}
}
}
}
if (opts.print_newline && continue_output) {
streams.out.push_back('\n');
out.push_back('\n');
}
if (!out.empty()) {
streams.out.append(out);
}
return STATUS_CMD_OK;
}