11 # include "editline.h"
18 #include <boost/regex.hpp>
20 namespace fc {
namespace rpc {
22 static boost::regex& cli_regex_secret()
24 static boost::regex regex_expr;
28 static std::vector<std::string>& cli_commands()
30 static std::vector<std::string>* cmds =
new std::vector<std::string>();
36 if( _run_complete.
valid() )
59 _result_formatters[method] = formatter;
69 cli_regex_secret() = expr;
81 getline( _prompt.c_str(), line );
83 catch (
const fc::eof_exception& e )
85 _getline_thread =
nullptr;
88 catch (
const fc::canceled_exception& e )
90 _getline_thread =
nullptr;
96 if( args.size() == 0 )
99 const string& method = args[0].get_string();
102 auto itr = _result_formatters.find( method );
103 if( itr == _result_formatters.end() )
108 std::cout << itr->second( result, args ) <<
"\n";
114 _getline_thread =
nullptr;
130 static char *my_rl_complete(
char *token,
int *match)
132 const auto& cmds = cli_commands();
133 const size_t partlen = strlen (token);
135 std::vector<std::reference_wrapper<const std::string>> matched_cmds;
136 for(
const std::string& it : cmds )
138 if( it.compare(0, partlen, token) == 0 )
140 matched_cmds.push_back( it );
144 if( matched_cmds.size() == 0 )
147 const std::string& first_matched_cmd = matched_cmds[0];
148 if( matched_cmds.size() == 1 )
151 std::string matched_cmd = first_matched_cmd +
" ";
152 return strdup( matched_cmd.c_str() + partlen );
155 size_t first_cmd_len = first_matched_cmd.size();
156 size_t matched_len = partlen;
157 for( ; matched_len < first_cmd_len; ++matched_len )
159 char next_char = first_matched_cmd[matched_len];
161 for(
const std::string& s : matched_cmds )
163 if( s.size() <= matched_len || s[matched_len] != next_char )
173 if( matched_len == partlen )
176 std::string matched_cmd_part = first_matched_cmd.substr( partlen, matched_len - partlen );
177 return strdup( matched_cmd_part.c_str() );
186 static int cli_completion(
char *token,
char ***array)
188 auto& cmd = cli_commands();
189 int num_commands = cmd.size();
191 char **
copy = (
char **) malloc (num_commands *
sizeof(
char *));
197 int total_matches = 0;
199 const size_t partlen = strlen(token);
201 for (
const std::string& it : cmd)
203 if ( it.compare(0, partlen, token) == 0)
205 copy[total_matches] = strdup ( it.c_str() );
211 return total_matches;
219 static int cli_check_secret(
const char *source)
221 if (!cli_regex_secret().empty() && boost::regex_match(source, cli_regex_secret()))
231 static int cli_quitting =
false;
236 static int interruptible_getc(
void)
246 if( r == -1 && errno == EINTR )
249 return r == 1 && !cli_quitting ? c : EOF;
252 #endif //HAVE_EDITLINE
260 rl_set_complete_func(my_rl_complete);
261 rl_set_list_possib_func(cli_completion);
263 rl_set_getc_func(interruptible_getc);
266 _getline_thread = &getline_thread;
268 cli_quitting =
false;
273 _run_complete =
fc::async( [
this](){ run(); } );
281 if( _getline_thread )
283 _getline_thread->
signal(SIGINT);
284 _getline_thread =
nullptr;
292 _run_complete.
wait();
297 _run_complete.
wait();
311 if( isatty( fileno( stdin ) ) )
318 if( _isatty( _fileno( stdin ) ) )
321 if( _getline_thread )
323 _getline_thread->
async( [&prompt,&line](){
324 char* line_read =
nullptr;
326 line_read = readline(prompt.c_str());
327 if( line_read ==
nullptr )
331 if (cli_check_secret(line_read)) {
334 line_read = readline(
"Enter password: ");
336 if( line_read ==
nullptr )
338 line = line +
' ' + line_read;