parent
4466b6d1b0
commit
c088d38a57
|
@ -52,11 +52,10 @@ namespace epee
|
||||||
, m_has_read_request(false)
|
, m_has_read_request(false)
|
||||||
, m_read_status(state_init)
|
, m_read_status(state_init)
|
||||||
{
|
{
|
||||||
m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
|
|
||||||
#ifdef HAVE_READLINE
|
#ifdef HAVE_READLINE
|
||||||
m_readline_buffer.start();
|
m_readline_buffer.start();
|
||||||
m_readline_thread = boost::thread(std::bind(&async_stdin_reader::readline_thread_func, this));
|
|
||||||
#endif
|
#endif
|
||||||
|
m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
~async_stdin_reader()
|
~async_stdin_reader()
|
||||||
|
@ -115,7 +114,6 @@ namespace epee
|
||||||
m_reader_thread.join();
|
m_reader_thread.join();
|
||||||
#ifdef HAVE_READLINE
|
#ifdef HAVE_READLINE
|
||||||
m_readline_buffer.stop();
|
m_readline_buffer.stop();
|
||||||
m_readline_thread.join();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,16 +191,6 @@ namespace epee
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_READLINE
|
|
||||||
void readline_thread_func()
|
|
||||||
{
|
|
||||||
while (m_run.load(std::memory_order_relaxed))
|
|
||||||
{
|
|
||||||
m_readline_buffer.process();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void reader_thread_func()
|
void reader_thread_func()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -212,12 +200,20 @@ namespace epee
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
bool read_ok = true;
|
bool read_ok = true;
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
reread:
|
||||||
|
#endif
|
||||||
if (wait_stdin_data())
|
if (wait_stdin_data())
|
||||||
{
|
{
|
||||||
if (m_run.load(std::memory_order_relaxed))
|
if (m_run.load(std::memory_order_relaxed))
|
||||||
{
|
{
|
||||||
#ifdef HAVE_READLINE
|
#ifdef HAVE_READLINE
|
||||||
m_readline_buffer.get_line(line);
|
switch (m_readline_buffer.get_line(line))
|
||||||
|
{
|
||||||
|
case rdln::empty: goto eof;
|
||||||
|
case rdln::partial: goto reread;
|
||||||
|
case rdln::full: break;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
std::getline(std::cin, line);
|
std::getline(std::cin, line);
|
||||||
#endif
|
#endif
|
||||||
|
@ -229,6 +225,9 @@ namespace epee
|
||||||
read_ok = false;
|
read_ok = false;
|
||||||
}
|
}
|
||||||
if (std::cin.eof()) {
|
if (std::cin.eof()) {
|
||||||
|
#ifdef HAVE_READLINE
|
||||||
|
eof:
|
||||||
|
#endif
|
||||||
m_read_status = state_eos;
|
m_read_status = state_eos;
|
||||||
m_response_cv.notify_one();
|
m_response_cv.notify_one();
|
||||||
break;
|
break;
|
||||||
|
@ -263,7 +262,6 @@ namespace epee
|
||||||
boost::thread m_reader_thread;
|
boost::thread m_reader_thread;
|
||||||
std::atomic<bool> m_run;
|
std::atomic<bool> m_run;
|
||||||
#ifdef HAVE_READLINE
|
#ifdef HAVE_READLINE
|
||||||
boost::thread m_readline_thread;
|
|
||||||
rdln::readline_buffer m_readline_buffer;
|
rdln::readline_buffer m_readline_buffer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -8,18 +8,18 @@
|
||||||
|
|
||||||
namespace rdln
|
namespace rdln
|
||||||
{
|
{
|
||||||
|
typedef enum { empty, partial, full } linestatus;
|
||||||
class readline_buffer : public std::stringbuf
|
class readline_buffer : public std::stringbuf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
readline_buffer();
|
readline_buffer();
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
int process();
|
|
||||||
bool is_running() const
|
bool is_running() const
|
||||||
{
|
{
|
||||||
return m_cout_buf != NULL;
|
return m_cout_buf != NULL;
|
||||||
}
|
}
|
||||||
void get_line(std::string& line) const;
|
linestatus get_line(std::string& line) const;
|
||||||
void set_prompt(const std::string& prompt);
|
void set_prompt(const std::string& prompt);
|
||||||
static void add_completion(const std::string& command);
|
static void add_completion(const std::string& command);
|
||||||
static const std::vector<std::string>& get_completions();
|
static const std::vector<std::string>& get_completions();
|
||||||
|
|
|
@ -3,19 +3,15 @@
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <mutex>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
static int process_input();
|
|
||||||
static void install_line_handler();
|
static void install_line_handler();
|
||||||
static void remove_line_handler();
|
static void remove_line_handler();
|
||||||
|
|
||||||
static std::string last_line;
|
static boost::mutex sync_mutex;
|
||||||
static std::string last_prompt;
|
static rdln::linestatus line_stat;
|
||||||
static std::mutex line_mutex, sync_mutex, process_mutex;
|
static char *the_line;
|
||||||
static std::condition_variable have_line;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -55,7 +51,6 @@ rdln::readline_buffer::readline_buffer()
|
||||||
|
|
||||||
void rdln::readline_buffer::start()
|
void rdln::readline_buffer::start()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(process_mutex);
|
|
||||||
if(m_cout_buf != NULL)
|
if(m_cout_buf != NULL)
|
||||||
return;
|
return;
|
||||||
m_cout_buf = std::cout.rdbuf();
|
m_cout_buf = std::cout.rdbuf();
|
||||||
|
@ -65,9 +60,6 @@ void rdln::readline_buffer::start()
|
||||||
|
|
||||||
void rdln::readline_buffer::stop()
|
void rdln::readline_buffer::stop()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock_process(process_mutex);
|
|
||||||
std::unique_lock<std::mutex> lock_sync(sync_mutex);
|
|
||||||
have_line.notify_all();
|
|
||||||
if(m_cout_buf == NULL)
|
if(m_cout_buf == NULL)
|
||||||
return;
|
return;
|
||||||
std::cout.rdbuf(m_cout_buf);
|
std::cout.rdbuf(m_cout_buf);
|
||||||
|
@ -75,20 +67,26 @@ void rdln::readline_buffer::stop()
|
||||||
remove_line_handler();
|
remove_line_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void rdln::readline_buffer::get_line(std::string& line) const
|
rdln::linestatus rdln::readline_buffer::get_line(std::string& line) const
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(line_mutex);
|
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||||
have_line.wait(lock);
|
line_stat = rdln::partial;
|
||||||
line = last_line;
|
rl_callback_read_char();
|
||||||
|
if (line_stat == rdln::full)
|
||||||
|
{
|
||||||
|
line = the_line;
|
||||||
|
free(the_line);
|
||||||
|
the_line = NULL;
|
||||||
|
}
|
||||||
|
return line_stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rdln::readline_buffer::set_prompt(const std::string& prompt)
|
void rdln::readline_buffer::set_prompt(const std::string& prompt)
|
||||||
{
|
{
|
||||||
last_prompt = prompt;
|
|
||||||
if(m_cout_buf == NULL)
|
if(m_cout_buf == NULL)
|
||||||
return;
|
return;
|
||||||
std::lock_guard<std::mutex> lock(sync_mutex);
|
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||||
rl_set_prompt(last_prompt.c_str());
|
rl_set_prompt(prompt.c_str());
|
||||||
rl_redisplay();
|
rl_redisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,33 +102,30 @@ const std::vector<std::string>& rdln::readline_buffer::get_completions()
|
||||||
return completion_commands();
|
return completion_commands();
|
||||||
}
|
}
|
||||||
|
|
||||||
int rdln::readline_buffer::process()
|
|
||||||
{
|
|
||||||
process_mutex.lock();
|
|
||||||
if(m_cout_buf == NULL)
|
|
||||||
{
|
|
||||||
process_mutex.unlock();
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds( 1 ));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int count = process_input();
|
|
||||||
process_mutex.unlock();
|
|
||||||
boost::this_thread::sleep_for(boost::chrono::milliseconds( 1 ));
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rdln::readline_buffer::sync()
|
int rdln::readline_buffer::sync()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(sync_mutex);
|
boost::lock_guard<boost::mutex> lock(sync_mutex);
|
||||||
char* saved_line;
|
#if RL_READLINE_VERSION < 0x0700
|
||||||
int saved_point;
|
char lbuf[2] = {0,0};
|
||||||
|
char *line = NULL;
|
||||||
|
int end = 0, point = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
saved_point = rl_point;
|
if (rl_end || *rl_prompt)
|
||||||
saved_line = rl_copy_text(0, rl_end);
|
{
|
||||||
|
#if RL_READLINE_VERSION >= 0x0700
|
||||||
rl_set_prompt("");
|
rl_clear_visible_line();
|
||||||
rl_replace_line("", 0);
|
#else
|
||||||
|
line = rl_line_buffer;
|
||||||
|
end = rl_end;
|
||||||
|
point = rl_point;
|
||||||
|
rl_line_buffer = lbuf;
|
||||||
|
rl_end = 0;
|
||||||
|
rl_point = 0;
|
||||||
|
rl_save_prompt();
|
||||||
rl_redisplay();
|
rl_redisplay();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -138,92 +133,47 @@ int rdln::readline_buffer::sync()
|
||||||
}
|
}
|
||||||
while ( this->snextc() != EOF );
|
while ( this->snextc() != EOF );
|
||||||
|
|
||||||
rl_set_prompt(last_prompt.c_str());
|
#if RL_READLINE_VERSION < 0x0700
|
||||||
rl_replace_line(saved_line, 0);
|
if (end || *rl_prompt)
|
||||||
rl_point = saved_point;
|
{
|
||||||
|
rl_restore_prompt();
|
||||||
|
rl_line_buffer = line;
|
||||||
|
rl_end = end;
|
||||||
|
rl_point = point;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
rl_on_new_line();
|
||||||
rl_redisplay();
|
rl_redisplay();
|
||||||
free(saved_line);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_input()
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
struct timeval t;
|
|
||||||
fd_set fds;
|
|
||||||
|
|
||||||
t.tv_sec = 0;
|
|
||||||
t.tv_usec = 1000;
|
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(STDIN_FILENO, &fds);
|
|
||||||
count = select(STDIN_FILENO + 1, &fds, NULL, NULL, &t);
|
|
||||||
if (count < 1)
|
|
||||||
{
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
rl_callback_read_char();
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_line(char* line)
|
static void handle_line(char* line)
|
||||||
{
|
{
|
||||||
free(line);
|
bool exit = false;
|
||||||
rl_done = 1;
|
if (line)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_enter(int x, int y)
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(sync_mutex);
|
line_stat = rdln::full;
|
||||||
char* line = NULL;
|
the_line = line;
|
||||||
|
|
||||||
line = rl_copy_text(0, rl_end);
|
|
||||||
std::string test_line = line;
|
std::string test_line = line;
|
||||||
free(line);
|
|
||||||
boost::trim_right(test_line);
|
boost::trim_right(test_line);
|
||||||
|
|
||||||
rl_crlf();
|
|
||||||
rl_on_new_line();
|
|
||||||
|
|
||||||
if(test_line.empty())
|
|
||||||
{
|
|
||||||
last_line = "";
|
|
||||||
rl_set_prompt(last_prompt.c_str());
|
|
||||||
rl_replace_line("", 1);
|
|
||||||
rl_redisplay();
|
|
||||||
have_line.notify_one();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rl_set_prompt("");
|
|
||||||
rl_replace_line("", 1);
|
|
||||||
rl_redisplay();
|
|
||||||
|
|
||||||
if(!test_line.empty())
|
if(!test_line.empty())
|
||||||
{
|
{
|
||||||
last_line = test_line;
|
|
||||||
add_history(test_line.c_str());
|
add_history(test_line.c_str());
|
||||||
history_set_pos(history_length);
|
history_set_pos(history_length);
|
||||||
|
if (test_line == "exit" || test_line == "q")
|
||||||
|
exit = true;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
if(last_line != "exit" && last_line != "q")
|
/* EOF */
|
||||||
{
|
{
|
||||||
rl_set_prompt(last_prompt.c_str());
|
line_stat = rdln::empty;
|
||||||
rl_replace_line("", 1);
|
exit = true;
|
||||||
rl_redisplay();
|
|
||||||
}
|
}
|
||||||
|
rl_done = 1;
|
||||||
have_line.notify_one();
|
if (exit)
|
||||||
return 0;
|
rl_set_prompt("");
|
||||||
}
|
return;
|
||||||
|
|
||||||
static int startup_hook()
|
|
||||||
{
|
|
||||||
rl_bind_key(RETURN, handle_enter);
|
|
||||||
rl_bind_key(NEWLINE, handle_enter);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* completion_matches(const char* text, int state)
|
static char* completion_matches(const char* text, int state)
|
||||||
|
@ -258,7 +208,6 @@ static char** attempted_completion(const char* text, int start, int end)
|
||||||
|
|
||||||
static void install_line_handler()
|
static void install_line_handler()
|
||||||
{
|
{
|
||||||
rl_startup_hook = startup_hook;
|
|
||||||
rl_attempted_completion_function = attempted_completion;
|
rl_attempted_completion_function = attempted_completion;
|
||||||
rl_callback_handler_install("", handle_line);
|
rl_callback_handler_install("", handle_line);
|
||||||
stifle_history(500);
|
stifle_history(500);
|
||||||
|
@ -269,8 +218,6 @@ static void remove_line_handler()
|
||||||
rl_replace_line("", 0);
|
rl_replace_line("", 0);
|
||||||
rl_set_prompt("");
|
rl_set_prompt("");
|
||||||
rl_redisplay();
|
rl_redisplay();
|
||||||
rl_unbind_key(RETURN);
|
|
||||||
rl_unbind_key(NEWLINE);
|
|
||||||
rl_callback_handler_remove();
|
rl_callback_handler_remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue