Teach io_buffer_t to append from output_stream_t directly

This will simplify logic when we teach output_stream_t about explicitly
split outputs, i.e. for 'string split0'
This commit is contained in:
ridiculousfish 2018-05-27 23:56:20 -07:00
parent 369890cdd9
commit 5b9331ade0
3 changed files with 28 additions and 18 deletions

View File

@ -925,8 +925,8 @@ void exec_job(parser_t &parser, job_t *j) {
process_net_io_chain.get_io_for_fd(STDERR_FILENO);
assert(builtin_io_streams.get() != NULL);
const wcstring &stdout_buffer = builtin_io_streams->out.buffer();
const wcstring &stderr_buffer = builtin_io_streams->err.buffer();
const output_stream_t &stdout_stream = builtin_io_streams->out;
const output_stream_t &stderr_stream = builtin_io_streams->err;
// If we are outputting to a file, we have to actually do it, even if we have no
// output, so that we can truncate the file. Does not apply to /dev/null.
@ -936,9 +936,9 @@ void exec_job(parser_t &parser, job_t *j) {
// We are handling reads directly in the main loop. Note that we may still end
// up forking.
const bool stdout_is_to_buffer = stdout_io && stdout_io->io_mode == IO_BUFFER;
const bool no_stdout_output = stdout_buffer.empty();
const bool no_stderr_output = stderr_buffer.empty();
const bool stdout_discarded = builtin_io_streams->out.output_discarded();
const bool no_stdout_output = stdout_stream.empty();
const bool no_stderr_output = stderr_stream.empty();
const bool stdout_discarded = stdout_stream.output_discarded();
if (!stdout_discarded && no_stdout_output && no_stderr_output) {
// The builtin produced no output and is not inside of a pipeline. No
@ -954,19 +954,14 @@ void exec_job(parser_t &parser, job_t *j) {
p->argv0());
io_buffer_t *io_buffer = static_cast<io_buffer_t *>(stdout_io.get());
if (stdout_discarded) {
io_buffer->set_discard();
} else {
const std::string res = wcs2string(builtin_io_streams->out.buffer());
io_buffer->out_buffer_append(res.data(), res.size());
}
io_buffer->append_from_stream(stdout_stream);
fork_was_skipped = true;
} else if (stdout_io.get() == NULL && stderr_io.get() == NULL) {
// We are writing to normal stdout and stderr. Just do it - no need to fork.
debug(3, L"Skipping fork: ordinary output for internal builtin '%ls'",
p->argv0());
const std::string outbuff = wcs2string(stdout_buffer);
const std::string errbuff = wcs2string(stderr_buffer);
const std::string outbuff = wcs2string(stdout_stream.buffer());
const std::string errbuff = wcs2string(stderr_stream.buffer());
bool builtin_io_done = do_builtin_io(outbuff.data(), outbuff.size(),
errbuff.data(), errbuff.size());
if (!builtin_io_done && errno != EPIPE) {
@ -995,11 +990,11 @@ void exec_job(parser_t &parser, job_t *j) {
// in the child.
//
// These strings may contain embedded nulls, so don't treat them as C strings.
const std::string outbuff_str = wcs2string(stdout_buffer);
const std::string outbuff_str = wcs2string(stdout_stream.buffer());
const char *outbuff = outbuff_str.data();
size_t outbuff_len = outbuff_str.size();
const std::string errbuff_str = wcs2string(stderr_buffer);
const std::string errbuff_str = wcs2string(stderr_stream.buffer());
const char *errbuff = errbuff_str.data();
size_t errbuff_len = errbuff_str.size();

View File

@ -31,6 +31,17 @@ void io_buffer_t::print() const {
is_input ? "yes" : "no", (unsigned long)out_buffer_size());
}
void io_buffer_t::append_from_stream(const output_stream_t &stream) {
if (output_discarded())
return;
if (stream.output_discarded()) {
set_discard();
return;
}
const std::string str = wcs2string(stream.buffer());
out_buffer_append(str.data(), str.size());
}
void io_buffer_t::read() {
exec_close(pipe_fd[1]);

View File

@ -98,6 +98,7 @@ class io_pipe_t : public io_data_t {
};
class io_chain_t;
class output_stream_t;
class io_buffer_t : public io_pipe_t {
private:
/// True if we're discarding input.
@ -121,8 +122,7 @@ class io_buffer_t : public io_pipe_t {
void out_buffer_append(const char *ptr, size_t count) {
if (discard) return;
if (buffer_limit && out_buffer.size() + count > buffer_limit) {
discard = true;
out_buffer.clear();
set_discard();
return;
}
out_buffer.insert(out_buffer.end(), ptr, ptr + count);
@ -153,6 +153,10 @@ class io_buffer_t : public io_pipe_t {
/// Close output pipe, and read from input pipe until eof.
void read();
/// Appends data from a given output_stream_t.
/// Marks the receiver as discarded if the stream was discarded.
void append_from_stream(const output_stream_t &stream);
/// Create a IO_BUFFER type io redirection, complete with a pipe and a vector<char> for output.
/// The default file descriptor used is STDOUT_FILENO for buffering.
///
@ -258,7 +262,7 @@ class output_stream_t {
const wcstring &buffer() const { return buffer_; }
/// Function that returns true if we discarded the input because there was too much data.
bool output_discarded() { return discard; }
bool output_discarded() const { return discard; }
bool empty() const { return buffer_.empty(); }
};