Electroneum
Loading...
Searching...
No Matches
readline_buffer.cpp
Go to the documentation of this file.
1#include "readline_buffer.h"
2#include <readline/readline.h>
3#include <readline/history.h>
4#include <iostream>
5#include <boost/thread/mutex.hpp>
6#include <boost/thread/lock_guard.hpp>
7#include <boost/algorithm/string.hpp>
8
9static void install_line_handler();
10static void remove_line_handler();
11
12static boost::mutex sync_mutex;
13static rdln::linestatus line_stat;
14static char *the_line;
15
16namespace
17{
18 rdln::readline_buffer* current = NULL;
19}
20
22: m_buffer(NULL), m_restart(false)
23{
24 m_buffer = current;
25 if(!m_buffer)
26 return;
27 m_restart = m_buffer->is_running();
28 if(m_restart)
29 m_buffer->stop();
30}
31
33{
34 if(!m_buffer)
35 return;
36 if(m_restart)
37 m_buffer->start();
38}
39
40std::vector<std::string>& rdln::readline_buffer::completion_commands()
41{
42 static std::vector<std::string> commands = {"exit"};
43 return commands;
44}
45
47: std::stringbuf(), m_cout_buf(NULL), m_prompt_length(0)
48{
49 current = this;
50}
51
53{
54 if(m_cout_buf != NULL)
55 return;
56 m_cout_buf = std::cout.rdbuf();
57 std::cout.rdbuf(this);
58 install_line_handler();
59}
60
62{
63 if(m_cout_buf == NULL)
64 return;
65 std::cout.rdbuf(m_cout_buf);
66 m_cout_buf = NULL;
67 remove_line_handler();
68}
69
71{
72 boost::lock_guard<boost::mutex> lock(sync_mutex);
73 line_stat = rdln::partial;
74 rl_callback_read_char();
75 if (line_stat == rdln::full)
76 {
77 line = the_line;
78 free(the_line);
79 the_line = NULL;
80 }
81 return line_stat;
82}
83
84void rdln::readline_buffer::set_prompt(const std::string& prompt)
85{
86 if(m_cout_buf == NULL)
87 return;
88 boost::lock_guard<boost::mutex> lock(sync_mutex);
89 rl_set_prompt(std::string(m_prompt_length, ' ').c_str());
90 rl_redisplay();
91 rl_set_prompt(prompt.c_str());
92 rl_redisplay();
93 m_prompt_length = prompt.size();
94}
95
96void rdln::readline_buffer::add_completion(const std::string& command)
97{
98 if(std::find(completion_commands().begin(), completion_commands().end(), command) != completion_commands().end())
99 return;
100 completion_commands().push_back(command);
101}
102
103const std::vector<std::string>& rdln::readline_buffer::get_completions()
104{
105 return completion_commands();
106}
107
109{
110 boost::lock_guard<boost::mutex> lock(sync_mutex);
111#if RL_READLINE_VERSION < 0x0700
112 char lbuf[2] = {0,0};
113 char *line = NULL;
114 int end = 0, point = 0;
115#endif
116
117 if (rl_end || (rl_prompt && *rl_prompt))
118 {
119#if RL_READLINE_VERSION >= 0x0700
120 rl_clear_visible_line();
121#else
122 line = rl_line_buffer;
123 end = rl_end;
124 point = rl_point;
125 rl_line_buffer = lbuf;
126 rl_end = 0;
127 rl_point = 0;
128 rl_save_prompt();
129 rl_redisplay();
130#endif
131 }
132
133 do
134 {
135 m_cout_buf->sputc( this->sgetc() );
136 }
137 while ( this->snextc() != EOF );
138
139#if RL_READLINE_VERSION < 0x0700
140 if (end || (rl_prompt && *rl_prompt))
141 {
142 rl_restore_prompt();
143 rl_line_buffer = line;
144 rl_end = end;
145 rl_point = point;
146 }
147#endif
148 rl_on_new_line();
149 rl_redisplay();
150
151 return 0;
152}
153
154static void handle_line(char* line)
155{
156 bool exit = false;
157 if (line)
158 {
159 line_stat = rdln::full;
160 the_line = line;
161 std::string test_line = line;
162 boost::trim_right(test_line);
163 if(!test_line.empty())
164 {
165 add_history(test_line.c_str());
166 history_set_pos(history_length);
167 if (test_line == "exit" || test_line == "q")
168 exit = true;
169 }
170 } else
171 /* EOF */
172 {
173 line_stat = rdln::empty;
174 exit = true;
175 }
176 rl_done = 1;
177 if (exit)
178 rl_set_prompt("");
179 return;
180}
181
182static char* completion_matches(const char* text, int state)
183{
184 static size_t list_index;
185 static size_t len;
186
187 if(state == 0)
188 {
189 list_index = 0;
190 len = strlen(text);
191 }
192
193 const std::vector<std::string>& completions = rdln::readline_buffer::get_completions();
194 for(; list_index<completions.size(); )
195 {
196 const std::string& cmd = completions[list_index++];
197 if(cmd.compare(0, len, text) == 0)
198 {
199 return strdup(cmd.c_str());
200 }
201 }
202
203 return NULL;
204}
205
206static char** attempted_completion(const char* text, int start, int end)
207{
208 rl_attempted_completion_over = 1;
209 return rl_completion_matches(text, completion_matches);
210}
211
212static void install_line_handler()
213{
214 rl_attempted_completion_function = attempted_completion;
215 rl_callback_handler_install("", handle_line);
216 stifle_history(500);
217}
218
219static void remove_line_handler()
220{
221 rl_replace_line("", 0);
222 rl_set_prompt("");
223 rl_redisplay();
224 rl_callback_handler_remove();
225}
226
static const std::vector< std::string > & get_completions()
void set_prompt(const std::string &prompt)
static void add_completion(const std::string &command)
linestatus get_line(std::string &line) const
STL namespace.
#define false