diff options
author | Riccardo Spagni <ric@spagni.net> | 2017-08-26 23:45:50 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2017-08-26 23:45:50 +0200 |
commit | d8f402ad8f9ed458420473d4fa4a1ddbb1c6ad5e (patch) | |
tree | 9f2686b749595a2cc8f328a104cfc74c2b7bbf34 | |
parent | Merge pull request #2319 (diff) | |
parent | Fix refresh counter display (diff) | |
download | monero-d8f402ad8f9ed458420473d4fa4a1ddbb1c6ad5e.tar.xz |
Merge pull request #2343
c656dd0e Fix refresh counter display (Howard Chu)
c088d38a Simplify readline support (Howard Chu)
-rw-r--r-- | contrib/epee/include/console_handler.h | 28 | ||||
-rw-r--r-- | contrib/epee/include/readline_buffer.h | 6 | ||||
-rw-r--r-- | contrib/epee/src/readline_buffer.cpp | 191 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 8 |
4 files changed, 93 insertions, 140 deletions
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index a3b2d30eb..b8336b270 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -52,11 +52,10 @@ namespace epee , m_has_read_request(false) , m_read_status(state_init) { - m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this)); #ifdef HAVE_READLINE m_readline_buffer.start(); - m_readline_thread = boost::thread(std::bind(&async_stdin_reader::readline_thread_func, this)); #endif + m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this)); } ~async_stdin_reader() @@ -115,7 +114,6 @@ namespace epee m_reader_thread.join(); #ifdef HAVE_READLINE m_readline_buffer.stop(); - m_readline_thread.join(); #endif } } @@ -193,16 +191,6 @@ namespace epee 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() { while (true) @@ -212,12 +200,20 @@ namespace epee std::string line; bool read_ok = true; +#ifdef HAVE_READLINE +reread: +#endif if (wait_stdin_data()) { if (m_run.load(std::memory_order_relaxed)) { #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 std::getline(std::cin, line); #endif @@ -229,6 +225,9 @@ namespace epee read_ok = false; } if (std::cin.eof()) { +#ifdef HAVE_READLINE +eof: +#endif m_read_status = state_eos; m_response_cv.notify_one(); break; @@ -263,7 +262,6 @@ namespace epee boost::thread m_reader_thread; std::atomic<bool> m_run; #ifdef HAVE_READLINE - boost::thread m_readline_thread; rdln::readline_buffer m_readline_buffer; #endif diff --git a/contrib/epee/include/readline_buffer.h b/contrib/epee/include/readline_buffer.h index 28a153414..cda7e34f9 100644 --- a/contrib/epee/include/readline_buffer.h +++ b/contrib/epee/include/readline_buffer.h @@ -8,25 +8,25 @@ namespace rdln { + typedef enum { empty, partial, full } linestatus; class readline_buffer : public std::stringbuf { public: readline_buffer(); void start(); void stop(); - int process(); bool is_running() const { 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); static void add_completion(const std::string& command); static const std::vector<std::string>& get_completions(); protected: virtual int sync(); - + private: std::streambuf* m_cout_buf; static std::vector<std::string>& completion_commands(); diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp index 42b474052..291bba94c 100644 --- a/contrib/epee/src/readline_buffer.cpp +++ b/contrib/epee/src/readline_buffer.cpp @@ -3,19 +3,15 @@ #include <readline/history.h> #include <sys/select.h> #include <unistd.h> -#include <mutex> -#include <condition_variable> #include <boost/thread.hpp> #include <boost/algorithm/string.hpp> -static int process_input(); static void install_line_handler(); static void remove_line_handler(); -static std::string last_line; -static std::string last_prompt; -static std::mutex line_mutex, sync_mutex, process_mutex; -static std::condition_variable have_line; +static boost::mutex sync_mutex; +static rdln::linestatus line_stat; +static char *the_line; namespace { @@ -55,7 +51,6 @@ rdln::readline_buffer::readline_buffer() void rdln::readline_buffer::start() { - std::unique_lock<std::mutex> lock(process_mutex); if(m_cout_buf != NULL) return; m_cout_buf = std::cout.rdbuf(); @@ -65,9 +60,6 @@ void rdln::readline_buffer::start() 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) return; std::cout.rdbuf(m_cout_buf); @@ -75,20 +67,26 @@ void rdln::readline_buffer::stop() 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); - have_line.wait(lock); - line = last_line; + boost::lock_guard<boost::mutex> lock(sync_mutex); + line_stat = rdln::partial; + 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) { - last_prompt = prompt; if(m_cout_buf == NULL) return; - std::lock_guard<std::mutex> lock(sync_mutex); - rl_set_prompt(last_prompt.c_str()); + boost::lock_guard<boost::mutex> lock(sync_mutex); + rl_set_prompt(prompt.c_str()); rl_redisplay(); } @@ -104,126 +102,78 @@ const std::vector<std::string>& rdln::readline_buffer::get_completions() return completion_commands(); } -int rdln::readline_buffer::process() +int rdln::readline_buffer::sync() { - process_mutex.lock(); - if(m_cout_buf == NULL) + boost::lock_guard<boost::mutex> lock(sync_mutex); +#if RL_READLINE_VERSION < 0x0700 + char lbuf[2] = {0,0}; + char *line = NULL; + int end = 0, point = 0; +#endif + + if (rl_end || *rl_prompt) { - process_mutex.unlock(); - boost::this_thread::sleep_for(boost::chrono::milliseconds( 1 )); - return 0; +#if RL_READLINE_VERSION >= 0x0700 + rl_clear_visible_line(); +#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(); +#endif } - int count = process_input(); - process_mutex.unlock(); - boost::this_thread::sleep_for(boost::chrono::milliseconds( 1 )); - return count; -} -int rdln::readline_buffer::sync() -{ - std::lock_guard<std::mutex> lock(sync_mutex); - char* saved_line; - int saved_point; - - saved_point = rl_point; - saved_line = rl_copy_text(0, rl_end); - - rl_set_prompt(""); - rl_replace_line("", 0); - rl_redisplay(); - do { m_cout_buf->sputc( this->sgetc() ); } while ( this->snextc() != EOF ); - - rl_set_prompt(last_prompt.c_str()); - rl_replace_line(saved_line, 0); - rl_point = saved_point; - rl_redisplay(); - free(saved_line); - - 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) +#if RL_READLINE_VERSION < 0x0700 + if (end || *rl_prompt) { - return count; + rl_restore_prompt(); + rl_line_buffer = line; + rl_end = end; + rl_point = point; } - rl_callback_read_char(); - return count; -} - -static void handle_line(char* line) -{ - free(line); - rl_done = 1; - return; -} - -static int handle_enter(int x, int y) -{ - std::lock_guard<std::mutex> lock(sync_mutex); - char* line = NULL; - - line = rl_copy_text(0, rl_end); - std::string test_line = line; - free(line); - boost::trim_right(test_line); - - rl_crlf(); +#endif 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()) - { - last_line = test_line; - add_history(test_line.c_str()); - history_set_pos(history_length); - } - if(last_line != "exit" && last_line != "q") - { - rl_set_prompt(last_prompt.c_str()); - rl_replace_line("", 1); - rl_redisplay(); - } - - have_line.notify_one(); return 0; } -static int startup_hook() +static void handle_line(char* line) { - rl_bind_key(RETURN, handle_enter); - rl_bind_key(NEWLINE, handle_enter); - return 0; + bool exit = false; + if (line) + { + line_stat = rdln::full; + the_line = line; + std::string test_line = line; + boost::trim_right(test_line); + if(!test_line.empty()) + { + add_history(test_line.c_str()); + history_set_pos(history_length); + if (test_line == "exit" || test_line == "q") + exit = true; + } + } else + /* EOF */ + { + line_stat = rdln::empty; + exit = true; + } + rl_done = 1; + if (exit) + rl_set_prompt(""); + return; } 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() { - rl_startup_hook = startup_hook; rl_attempted_completion_function = attempted_completion; rl_callback_handler_install("", handle_line); stifle_history(500); @@ -269,8 +218,6 @@ static void remove_line_handler() rl_replace_line("", 0); rl_set_prompt(""); rl_redisplay(); - rl_unbind_key(RETURN); - rl_unbind_key(NEWLINE); rl_callback_handler_remove(); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 59916c30a..479adcafc 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -63,6 +63,10 @@ #include "wallet/wallet_args.h" #include <stdexcept> +#ifdef HAVE_READLINE +#include "readline_buffer.h" +#endif + using namespace std; using namespace epee; using namespace cryptonote; @@ -1848,6 +1852,10 @@ bool simple_wallet::refresh_main(uint64_t start_height, bool reset) if (reset) m_wallet->rescan_blockchain(false); +#ifdef HAVE_READLINE + rdln::suspend_readline pause_readline; +#endif + message_writer() << tr("Starting refresh..."); uint64_t fetched_blocks = 0; |