Move readline functionality into device-independent code

This commit is contained in:
2021-10-12 12:46:11 -04:00
parent 315bf6e3b1
commit 995219d965
6 changed files with 122 additions and 42 deletions

View File

@@ -9,6 +9,10 @@ Channel::Channel(DrivenEngine *de, int chid, int port, const std::string &target
port_ = port;
closed_ = false;
target_ = target;
readline_enabled_ = (chid == 0);
readline_len_ = 0;
readline_lastc_ = 0;
echo_len_ = 0;
assert(driven_->channels_[chid_] == nullptr);
driven_->channels_[chid_] = this;
}
@@ -20,6 +24,50 @@ Channel::~Channel() {
driven_->channels_[chid_] = nullptr;
}
void Channel::feed_readline(int nbytes, const char *bytes) {
for (int i = 0; i < nbytes; i++) {
char c = bytes[i];
if ((c == '\n') && (readline_lastc_ == '\r')) {
// Ignore newline immediately after carriage return.
// Otherwise, crlf produces two newlines.
} else if ((c == '\r') || (c == '\n')) {
if ((echo_space() >= 3) && (readline_space() >= 1)) {
echo_buf_[echo_len_++] = ' ';
echo_buf_[echo_len_++] = '\r';
echo_buf_[echo_len_++] = '\n';
readline_buf_[readline_len_++] = '\n';
sb_in_->write_bytes(readline_buf_, readline_len_);
readline_len_ = 0;
}
} else if (c == '\b') {
if ((readline_len_ >= 1) && (echo_space() >= 3)) {
echo_buf_[echo_len_++] = '\b';
echo_buf_[echo_len_++] = ' ';
echo_buf_[echo_len_++] = '\b';
readline_len_ -= 1;
}
} else if (c >= 32) {
// Don't use up the last character in the readline buffer: save
// it for the newline.
if ((readline_space() >= 2) && (echo_space() >= 1)) {
echo_buf_[echo_len_++] = c;
readline_buf_[readline_len_++] = c;
}
}
readline_lastc_ = c;
}
}
void Channel::set_readline(bool e) {
if (e != readline_enabled_) {
readline_enabled_ = e;
readline_len_ = 0;
readline_lastc_ = 0;
echo_len_ = 0;
}
}
int DrivenEngine::find_unused_chid() {
// Note: channel ID zero is special, it is never reused.
for (int i = 0; i < MAX_CHAN; i++) {
@@ -101,17 +149,40 @@ bool DrivenEngine::drv_outgoing_empty(int chid) {
void DrivenEngine::drv_peek_outgoing(int chid, int *nbytes, const char **bytes) {
Channel *ch = get_chid(chid);
*nbytes = ch->sb_out_->fill();
*bytes = ch->sb_out_->data();
if (ch->echo_len_ > 0) {
*nbytes = ch->echo_len_;
*bytes = ch->echo_buf_;
} else {
*nbytes = ch->sb_out_->fill();
*bytes = ch->sb_out_->data();
}
}
void DrivenEngine::drv_sent_outgoing(int chid, int nbytes) {
get_chid(chid)->sb_out_->read_bytes(nbytes);
Channel *ch = get_chid(chid);
if (nbytes > 0) {
if (ch->echo_len_ > 0) {
if (nbytes >= ch->echo_len_) {
ch->sb_out_->read_bytes(nbytes - ch->echo_len_);
ch->echo_len_ = 0;
} else {
ch->echo_len_ -= nbytes;
memmove(ch->echo_buf_, ch->echo_buf_ + nbytes, ch->echo_len_);
}
} else {
ch->sb_out_->read_bytes(nbytes);
}
}
}
void DrivenEngine::drv_recv_incoming(int chid, int nbytes, const char *bytes) {
if (nbytes > 0) {
get_chid(chid)->sb_in_->write_bytes(bytes, nbytes);
Channel *ch = get_chid(chid);
if (ch->readline_enabled_) {
ch->feed_readline(nbytes, bytes);
} else {
ch->sb_in_->write_bytes(bytes, nbytes);
}
}
}