Move readline functionality into device-independent code
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user