2021-10-04 17:45:18 -04:00
|
|
|
#include "drivenengine.hpp"
|
|
|
|
|
|
|
|
|
|
|
2022-01-05 12:50:16 -05:00
|
|
|
Channel::Channel(DrivenEngine *de, int chid, int port, const std::string &target, bool stop) {
|
2021-10-04 17:45:18 -04:00
|
|
|
chid_ = chid;
|
|
|
|
|
port_ = port;
|
|
|
|
|
closed_ = false;
|
|
|
|
|
target_ = target;
|
2022-01-06 17:24:32 -05:00
|
|
|
readline_enabled_ = false;
|
2021-10-12 12:46:11 -04:00
|
|
|
readline_lastc_ = 0;
|
2021-11-04 14:03:05 -04:00
|
|
|
desired_prompt_ = "";
|
2022-01-05 12:50:16 -05:00
|
|
|
stop_driver_ = stop;
|
2022-01-06 17:24:32 -05:00
|
|
|
sb_in_ = std::make_shared<StreamBuffer>();
|
|
|
|
|
sb_out_ = std::make_shared<StreamBuffer>();
|
|
|
|
|
sb_drvout_ = sb_out_;
|
2021-10-07 14:58:20 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-06 17:24:32 -05:00
|
|
|
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));
|
2021-11-04 14:00:35 -04:00
|
|
|
current_prompt_ = "";
|
|
|
|
|
current_command_ = "";
|
|
|
|
|
}
|
2022-01-06 17:24:32 -05:00
|
|
|
}
|
2021-11-04 14:00:35 -04:00
|
|
|
|
2022-01-06 17:24:32 -05:00
|
|
|
void Channel::echo_command() {
|
2021-11-04 13:40:42 -04:00
|
|
|
// If the prompt has changed, erase everything and start over.
|
|
|
|
|
if (desired_prompt_ != current_prompt_) {
|
|
|
|
|
int ccsize = current_prompt_.size() + current_command_.size();
|
2022-01-06 17:24:32 -05:00
|
|
|
sb_drvout_->write_bytes(util::repeat_string("\b \b", ccsize));
|
|
|
|
|
sb_drvout_->write_bytes(desired_prompt_);
|
2021-11-04 13:40:42 -04:00
|
|
|
current_command_ = "";
|
|
|
|
|
current_prompt_ = desired_prompt_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find out how much of the command matches.
|
|
|
|
|
int match = util::common_prefix_length(current_command_, desired_command_);
|
|
|
|
|
|
|
|
|
|
// Echo backspaces to remove the non-matching part.
|
|
|
|
|
int remove = current_command_.size() - match;
|
|
|
|
|
if (remove > 0) {
|
2022-01-06 17:24:32 -05:00
|
|
|
sb_drvout_->write_bytes(util::repeat_string("\b \b", remove));
|
2021-11-04 13:40:42 -04:00
|
|
|
current_command_ = current_command_.substr(0, match);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Echo the new part.
|
|
|
|
|
std::string newpart = desired_command_.substr(current_command_.size());
|
|
|
|
|
if (newpart != "") {
|
2022-01-06 17:24:32 -05:00
|
|
|
sb_drvout_->write_bytes(newpart);
|
2021-11-04 13:40:42 -04:00
|
|
|
current_command_ = desired_command_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Channel::set_prompt(const std::string &p) {
|
|
|
|
|
desired_prompt_ = p;
|
|
|
|
|
}
|
2021-10-12 12:46:11 -04:00
|
|
|
|
|
|
|
|
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')) {
|
2022-01-06 17:24:32 -05:00
|
|
|
echo_command();
|
|
|
|
|
sb_drvout_->write_bytes(std::string(" \n"));
|
2021-11-04 13:40:42 -04:00
|
|
|
sb_in_->write_bytes(desired_command_);
|
|
|
|
|
sb_in_->write_uint8('\n');
|
|
|
|
|
desired_command_ = "";
|
|
|
|
|
current_prompt_ = "";
|
|
|
|
|
current_command_ = "";
|
2021-12-08 13:28:09 -05:00
|
|
|
} else if ((c == '\b') || (c == 127)) {
|
2021-11-04 13:40:42 -04:00
|
|
|
int len = desired_command_.size();
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
desired_command_ = desired_command_.substr(0, len-1);
|
2021-10-12 12:46:11 -04:00
|
|
|
}
|
|
|
|
|
} else if (c >= 32) {
|
2021-11-04 13:40:42 -04:00
|
|
|
int len = desired_command_.size();
|
|
|
|
|
if (len < READLINE_MAX) {
|
|
|
|
|
desired_command_ = desired_command_ + c;
|
2021-10-12 12:46:11 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
readline_lastc_ = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-04 13:40:42 -04:00
|
|
|
void Channel::peek_outgoing(int *nbytes, const char **bytes) {
|
2022-01-06 17:24:32 -05:00
|
|
|
if (readline_enabled_) {
|
|
|
|
|
if (!sb_out_->empty()) {
|
|
|
|
|
erase_command();
|
|
|
|
|
sb_out_->transfer_into(sb_drvout_.get());
|
|
|
|
|
}
|
|
|
|
|
echo_command();
|
2021-11-04 13:40:42 -04:00
|
|
|
}
|
2022-01-06 17:24:32 -05:00
|
|
|
*nbytes = sb_drvout_->fill();
|
|
|
|
|
*bytes = sb_drvout_->data();
|
2021-11-04 13:40:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Channel::sent_outgoing(int nbytes) {
|
2022-01-06 17:24:32 -05:00
|
|
|
sb_drvout_->read_bytes(nbytes);
|
2021-11-04 13:40:42 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-12 12:46:11 -04:00
|
|
|
void Channel::set_readline(bool e) {
|
|
|
|
|
if (e != readline_enabled_) {
|
|
|
|
|
readline_enabled_ = e;
|
2022-01-06 17:24:32 -05:00
|
|
|
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_;
|
|
|
|
|
}
|
2021-11-04 13:40:42 -04:00
|
|
|
desired_command_ = "";
|
2021-10-12 12:46:11 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-07 14:58:20 -04:00
|
|
|
int DrivenEngine::find_unused_chid() {
|
|
|
|
|
// Note: channel ID zero is special, it is never reused.
|
|
|
|
|
for (int i = 0; i < MAX_CHAN; i++) {
|
|
|
|
|
int id = next_unused_chid_++;
|
|
|
|
|
if (next_unused_chid_ == MAX_CHAN) next_unused_chid_ = 1;
|
|
|
|
|
if (channels_[id] == nullptr) return id;
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
2021-10-07 14:58:20 -04:00
|
|
|
assert(false);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Channel *DrivenEngine::get_chid(int chid) {
|
|
|
|
|
assert(unsigned(chid) < MAX_CHAN);
|
2022-01-05 12:50:16 -05:00
|
|
|
assert(channels_[chid].get() != nullptr);
|
|
|
|
|
return channels_[chid].get();
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-08 21:03:52 -04:00
|
|
|
void DrivenEngine::listen_port(int port) {
|
|
|
|
|
listen_ports_.insert(port);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-04 17:45:18 -04:00
|
|
|
double DrivenEngine::get_clock() {
|
|
|
|
|
return clock_;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 12:50:16 -05:00
|
|
|
SharedChannel DrivenEngine::new_outgoing_channel(const std::string &target) {
|
2021-10-07 14:58:20 -04:00
|
|
|
int chid = find_unused_chid();
|
|
|
|
|
new_outgoing_.insert(chid);
|
2022-01-05 12:50:16 -05:00
|
|
|
SharedChannel result = std::make_shared<Channel>(this, chid, 0, target, stop_driver_);
|
|
|
|
|
channels_[chid] = result;
|
|
|
|
|
return result;
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-05 12:50:16 -05:00
|
|
|
SharedChannel DrivenEngine::new_incoming_channel() {
|
2021-10-04 17:45:18 -04:00
|
|
|
if (accepted_channels_.empty()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
} else {
|
2022-01-05 12:50:16 -05:00
|
|
|
SharedChannel result = std::move(accepted_channels_.back());
|
2021-10-04 17:45:18 -04:00
|
|
|
accepted_channels_.pop_back();
|
2021-11-23 14:38:08 -05:00
|
|
|
return result;
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 12:50:16 -05:00
|
|
|
SharedChannel DrivenEngine::get_stdio_channel() {
|
|
|
|
|
return stdio_channel_;
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-05 12:54:37 -04:00
|
|
|
util::LuaSourcePtr DrivenEngine::get_lua_source() {
|
2021-10-04 17:45:18 -04:00
|
|
|
return std::move(lua_source_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrivenEngine::rescan_lua_source() {
|
|
|
|
|
rescan_lua_source_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrivenEngine::stop_driver() {
|
|
|
|
|
stop_driver_ = true;
|
2022-01-05 12:50:16 -05:00
|
|
|
for (int i = 0; i < MAX_CHAN; i++) {
|
|
|
|
|
if (channels_[i] != nullptr) {
|
|
|
|
|
channels_[i]->stop_driver_ = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-08 21:03:52 -04:00
|
|
|
void DrivenEngine::drv_get_listen_ports(std::set<int> &ports) {
|
|
|
|
|
ports = listen_ports_;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-07 14:58:20 -04:00
|
|
|
void DrivenEngine::drv_get_new_outgoing(std::set<int> &channels) {
|
|
|
|
|
channels = std::move(new_outgoing_);
|
|
|
|
|
new_outgoing_.clear();
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string &DrivenEngine::drv_get_target(int chid) {
|
|
|
|
|
return get_chid(chid)->target_;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-07 14:58:20 -04:00
|
|
|
bool DrivenEngine::drv_outgoing_empty(int chid) {
|
2022-01-06 17:24:32 -05:00
|
|
|
int nbytes; const char *bytes;
|
|
|
|
|
drv_peek_outgoing(chid, &nbytes, &bytes);
|
2022-01-06 17:59:59 -05:00
|
|
|
return (nbytes == 0);
|
2021-10-07 14:58:20 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-05 12:50:16 -05:00
|
|
|
bool DrivenEngine::drv_get_channel_released(int chid) {
|
|
|
|
|
return channels_[chid].use_count() == 1;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-04 17:45:18 -04:00
|
|
|
void DrivenEngine::drv_peek_outgoing(int chid, int *nbytes, const char **bytes) {
|
2021-11-04 13:40:42 -04:00
|
|
|
return get_chid(chid)->peek_outgoing(nbytes, bytes);
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrivenEngine::drv_sent_outgoing(int chid, int nbytes) {
|
2021-11-04 13:40:42 -04:00
|
|
|
return get_chid(chid)->sent_outgoing(nbytes);
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-07 14:58:20 -04:00
|
|
|
void DrivenEngine::drv_recv_incoming(int chid, int nbytes, const char *bytes) {
|
2021-10-05 12:54:37 -04:00
|
|
|
if (nbytes > 0) {
|
2021-10-12 12:46:11 -04:00
|
|
|
Channel *ch = get_chid(chid);
|
|
|
|
|
if (ch->readline_enabled_) {
|
|
|
|
|
ch->feed_readline(nbytes, bytes);
|
|
|
|
|
} else {
|
|
|
|
|
ch->sb_in_->write_bytes(bytes, nbytes);
|
|
|
|
|
}
|
2021-10-05 12:54:37 -04:00
|
|
|
}
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-12 13:54:08 -04:00
|
|
|
void DrivenEngine::drv_notify_close(int chid, const std::string &err) {
|
|
|
|
|
Channel *ch = get_chid(chid);
|
|
|
|
|
ch->closed_ = true;
|
|
|
|
|
ch->error_ = err;
|
2022-01-05 12:50:16 -05:00
|
|
|
channels_[chid].reset();
|
2021-10-04 17:45:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int DrivenEngine::drv_notify_accept(int port) {
|
2021-10-07 14:58:20 -04:00
|
|
|
int chid = find_unused_chid();
|
2022-01-05 12:50:16 -05:00
|
|
|
channels_[chid] = std::make_shared<Channel>(this, chid, port, "", stop_driver_);
|
|
|
|
|
accepted_channels_.push_back(channels_[chid]);
|
2021-10-04 17:45:18 -04:00
|
|
|
return chid;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 12:54:37 -04:00
|
|
|
void DrivenEngine::drv_set_lua_source(util::LuaSourcePtr source) {
|
|
|
|
|
lua_source_ = std::move(source);
|
2021-10-04 17:45:18 -04:00
|
|
|
rescan_lua_source_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-14 16:41:24 -04:00
|
|
|
void DrivenEngine::drv_invoke_event_init(int argc, char *argv[]) {
|
|
|
|
|
event_init(argc, argv);
|
2021-10-08 16:38:10 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-09 21:41:28 -05:00
|
|
|
void DrivenEngine::drv_invoke_event_update(double clock) {
|
|
|
|
|
clock_ = clock;
|
2021-10-05 12:54:37 -04:00
|
|
|
event_update();
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-04 17:45:18 -04:00
|
|
|
bool DrivenEngine::drv_get_rescan_lua_source() {
|
|
|
|
|
return rescan_lua_source_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DrivenEngine::drv_get_stop_driver() {
|
|
|
|
|
return stop_driver_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DrivenEngine::DrivenEngine() {
|
2021-10-07 14:58:20 -04:00
|
|
|
next_unused_chid_ = 1;
|
2022-01-05 12:50:16 -05:00
|
|
|
stdio_channel_ = std::make_shared<Channel>(this, 0, 0, "", false);
|
2022-01-06 17:24:32 -05:00
|
|
|
stdio_channel_->set_readline(true);
|
2022-01-05 12:50:16 -05:00
|
|
|
channels_[0] = stdio_channel_;
|
2021-10-04 17:45:18 -04:00
|
|
|
rescan_lua_source_ = true;
|
|
|
|
|
clock_ = 0.0;
|
|
|
|
|
stop_driver_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 12:50:16 -05:00
|
|
|
DrivenEngine::~DrivenEngine() {}
|
2021-10-04 17:45:18 -04:00
|
|
|
|
|
|
|
|
static DrivenEngine *engine_;
|
|
|
|
|
|
|
|
|
|
void DrivenEngine::set(DrivenEngine *de) {
|
|
|
|
|
engine_ = de;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DrivenEngine *DrivenEngine::get() {
|
|
|
|
|
return engine_;
|
|
|
|
|
}
|
|
|
|
|
|