Make it so that drivenengine never changes (only appends) output bytes.

This commit is contained in:
2022-01-06 17:24:32 -05:00
parent 3306281dcc
commit dc2237e5c1
4 changed files with 59 additions and 42 deletions

View File

@@ -3,32 +3,33 @@
Channel::Channel(DrivenEngine *de, int chid, int port, const std::string &target, bool stop) {
chid_ = chid;
sb_in_.reset(new StreamBuffer);
sb_out_.reset(new StreamBuffer);
port_ = port;
closed_ = false;
target_ = target;
readline_enabled_ = (chid == 0);
readline_enabled_ = false;
readline_lastc_ = 0;
desired_prompt_ = "";
stop_driver_ = stop;
sb_in_ = std::make_shared<StreamBuffer>();
sb_out_ = std::make_shared<StreamBuffer>();
sb_drvout_ = sb_out_;
}
void Channel::show_or_hide_command(bool ignore_sb_out) {
bool sb_out_empty = (sb_out_->fill() == 0) || ignore_sb_out;
if (!sb_out_empty || (!readline_enabled_) || (stop_driver_)) {
int ccsize = current_prompt_.size() + current_command_.size();
readline_echo_ += util::repeat_string("\b \b", ccsize);
void Channel::erase_command() {
int ccsize = current_prompt_.size() + current_command_.size();
if (ccsize > 0) {
sb_drvout_->write_bytes(util::repeat_string("\b \b", ccsize));
current_prompt_ = "";
current_command_ = "";
return;
}
}
void Channel::echo_command() {
// If the prompt has changed, erase everything and start over.
if (desired_prompt_ != current_prompt_) {
int ccsize = current_prompt_.size() + current_command_.size();
readline_echo_ += util::repeat_string("\b \b", ccsize);
readline_echo_ += desired_prompt_;
sb_drvout_->write_bytes(util::repeat_string("\b \b", ccsize));
sb_drvout_->write_bytes(desired_prompt_);
current_command_ = "";
current_prompt_ = desired_prompt_;
}
@@ -39,21 +40,20 @@ void Channel::show_or_hide_command(bool ignore_sb_out) {
// Echo backspaces to remove the non-matching part.
int remove = current_command_.size() - match;
if (remove > 0) {
readline_echo_ += util::repeat_string("\b \b", remove);
sb_drvout_->write_bytes(util::repeat_string("\b \b", remove));
current_command_ = current_command_.substr(0, match);
}
// Echo the new part.
std::string newpart = desired_command_.substr(current_command_.size());
if (newpart != "") {
readline_echo_ += newpart;
sb_drvout_->write_bytes(newpart);
current_command_ = desired_command_;
}
}
void Channel::set_prompt(const std::string &p) {
desired_prompt_ = p;
show_or_hide_command(false);
}
void Channel::feed_readline(int nbytes, const char *bytes) {
@@ -63,8 +63,8 @@ void Channel::feed_readline(int nbytes, const char *bytes) {
// Ignore newline immediately after carriage return.
// Otherwise, crlf produces two newlines.
} else if ((c == '\r') || (c == '\n')) {
show_or_hide_command(true);
readline_echo_ = readline_echo_ + " \n";
echo_command();
sb_drvout_->write_bytes(std::string(" \n"));
sb_in_->write_bytes(desired_command_);
sb_in_->write_uint8('\n');
desired_command_ = "";
@@ -86,35 +86,33 @@ void Channel::feed_readline(int nbytes, const char *bytes) {
}
void Channel::peek_outgoing(int *nbytes, const char **bytes) {
show_or_hide_command(false);
if (readline_echo_.size() > 0) {
*nbytes = readline_echo_.size();
*bytes = readline_echo_.c_str();
} else {
*nbytes = sb_out_->fill();
*bytes = sb_out_->data();
if (readline_enabled_) {
if (!sb_out_->empty()) {
erase_command();
sb_out_->transfer_into(sb_drvout_.get());
}
echo_command();
}
*nbytes = sb_drvout_->fill();
*bytes = sb_drvout_->data();
}
void Channel::sent_outgoing(int nbytes) {
if (nbytes > 0) {
if (readline_echo_.size() > 0) {
if (nbytes < int(readline_echo_.size())) {
readline_echo_ = readline_echo_.substr(nbytes);
return;
}
nbytes -= readline_echo_.size();
readline_echo_ = "";
}
sb_out_->read_bytes(nbytes);
}
sb_drvout_->read_bytes(nbytes);
}
void Channel::set_readline(bool e) {
if (e != readline_enabled_) {
readline_enabled_ = e;
if (readline_enabled_) {
sb_drvout_ = std::make_shared<StreamBuffer>();
} else {
sb_out_->transfer_into(sb_drvout_.get());
sb_out_->clear();
sb_drvout_->transfer_into(sb_out_.get());
sb_drvout_ = sb_out_;
}
desired_command_ = "";
show_or_hide_command(false);
}
}
@@ -196,7 +194,9 @@ const std::string &DrivenEngine::drv_get_target(int chid) {
}
bool DrivenEngine::drv_outgoing_empty(int chid) {
return get_chid(chid)->sb_out_->empty();
int nbytes; const char *bytes;
drv_peek_outgoing(chid, &nbytes, &bytes);
return (nbytes > 0);
}
bool DrivenEngine::drv_get_channel_released(int chid) {
@@ -264,6 +264,7 @@ bool DrivenEngine::drv_get_stop_driver() {
DrivenEngine::DrivenEngine() {
next_unused_chid_ = 1;
stdio_channel_ = std::make_shared<Channel>(this, 0, 0, "", false);
stdio_channel_->set_readline(true);
channels_[0] = stdio_channel_;
rescan_lua_source_ = true;
clock_ = 0.0;

View File

@@ -164,13 +164,22 @@ private:
void feed_readline(int nbytes, const char *bytes);
void peek_outgoing(int *nbytes, const char **bytes);
void sent_outgoing(int nbytes);
void show_or_hide_command(bool ignore_sb_out);
void erase_command();
void echo_command();
private:
static const int READLINE_MAX=512;
int chid_;
std::unique_ptr<StreamBuffer> sb_in_;
std::unique_ptr<StreamBuffer> sb_out_;
// These are the in/out buffers presented to the user.
std::shared_ptr<StreamBuffer> sb_in_;
std::shared_ptr<StreamBuffer> sb_out_;
// In readline mode, we inject tty echoes into the output stream.
// This buffer holds the users output interleaved with the tty echoes.
// In non-readline mode, this is just another pointer to sb_out.
std::shared_ptr<StreamBuffer> sb_drvout_;
int port_;
bool closed_;
std::string error_;
@@ -182,7 +191,6 @@ private:
std::string current_command_;
std::string desired_prompt_;
std::string current_prompt_;
std::string readline_echo_;
char readline_lastc_;
bool readline_enabled_;

View File

@@ -352,7 +352,7 @@ std::string StreamBuffer::read_string_limit(int64_t max_allowed) {
std::string StreamBuffer::read_entire_contents() {
std::string result(read_cursor_, fill());
clear();
read_cursor_ = write_cursor_;
return result;
}
@@ -438,6 +438,11 @@ void StreamBuffer::copy_into(StreamBuffer *sb) {
sb->write_bytes(read_cursor_, write_cursor_ - read_cursor_);
}
void StreamBuffer::transfer_into(StreamBuffer *sb) {
sb->write_bytes(read_cursor_, write_cursor_ - read_cursor_);
read_cursor_ = write_cursor_;
}
bool StreamBuffer::contents_equal(const StreamBuffer *other) const {
int64_t len = fill();
if (len != other->fill()) {

View File

@@ -347,7 +347,7 @@ public:
// Read the entire contents of the buffer as a string.
//
std::string read_entire_contents();
// Overwrite values previously written to the buffer.
//
// See the comment at the top of this file for an explanation.
@@ -384,6 +384,9 @@ public:
// Copy the entire contents of this streambuffer into another one.
void copy_into(StreamBuffer *sb);
// Transfer the entire contents of this streambuffer into another one.
void transfer_into(StreamBuffer *sb);
// Compare the contents of this streambuffer to another one.
bool contents_equal(const StreamBuffer *sb) const;