From e33cd275aa0f3df63a6fc337db00bac0655a402d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 16 Oct 2020 01:22:39 +0000 Subject: [PATCH 1/2] add editline changes --- .gitmodules | 3 + CMakeLists.txt | 74 +++++++++++---- CMakeModules/FindReadline.cmake | 47 ---------- src/rpc/cli.cpp | 157 ++++++++++++++++++++------------ vendor/editline | 1 + 5 files changed, 158 insertions(+), 124 deletions(-) delete mode 100755 CMakeModules/FindReadline.cmake create mode 160000 vendor/editline diff --git a/.gitmodules b/.gitmodules index 0e539dc..b4e43d2 100755 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "vendor/secp256k1-zkp"] path = vendor/secp256k1-zkp url = https://github.com/bitshares/secp256k1-zkp.git +[submodule "vendor/editline"] + path = vendor/editline + url = https://github.com/troglobit/editline.git diff --git a/CMakeLists.txt b/CMakeLists.txt index bd52180..0b5ee12 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,54 @@ else ( MSVC ) endif ( MSVC ) # End configure secp256k1-zkp +# Configure editline +if ( MSVC ) + # autoconf won't work here, hard code the defines + set( EDITLINE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline" ) + + file( GLOB EDITLINE_SOURCES "${EDITLINE_DIR}/src/editline.c" ) + add_library( editline ${EDITLINE_SOURCES} ) + + target_include_directories( editline PRIVATE "${EDITLINE_DIR}" PUBLIC "${EDITLINE_DIR}/include" ) + + set_target_properties( editline PROPERTIES COMPILE_DEFINITIONS LINKER_LANGUAGE C ) +else ( MSVC ) + include(ExternalProject) + if ( MINGW ) + ExternalProject_Add( project_editline + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/vendor/editline --host=x86_64-w64-mingw32 + BUILD_COMMAND make + INSTALL_COMMAND true + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline/src/project_editline-build/.libs/libeditline.a + ) + else ( MINGW ) + ExternalProject_Add( project_editline + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline + CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/vendor/editline + BUILD_COMMAND make + INSTALL_COMMAND true + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/editline/src/project_editline-build/.libs/libeditline.a + ) + endif ( MINGW ) + ExternalProject_Add_Step(project_editline autogen + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/autogen.sh + DEPENDERS configure + ) + + ExternalProject_Get_Property(project_editline binary_dir) + + add_library(editline STATIC IMPORTED) + set_property(TARGET editline PROPERTY IMPORTED_LOCATION ${binary_dir}/src/.libs/libeditline${CMAKE_STATIC_LIBRARY_SUFFIX}) + set_property(TARGET editline PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/vendor/editline/include) + add_dependencies(editline project_editline) + install( FILES ${binary_dir}/src/.libs/libeditline${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib/cryptonomex ) +endif ( MSVC ) +# End configure editline + IF( WIN32 ) MESSAGE(STATUS "Configuring fc to build on Win32") @@ -258,27 +306,17 @@ add_subdirectory( vendor/websocketpp EXCLUDE_FROM_ALL ) setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC ) install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include ) -# begin readline stuff -find_package(Curses) -find_package(Readline) - -file(GLOB HEADERS "include/bts/cli/*.hpp") - -if (READLINE_FOUND) - target_compile_definitions (fc PRIVATE HAVE_READLINE) - set(readline_libraries ${Readline_LIBRARY}) - if (CURSES_FOUND) - list(APPEND readline_libraries ${CURSES_LIBRARY}) - endif() - set(readline_includes ${Readline_INCLUDE_DIR}) -endif() +# begin editline stuff if(WIN32) target_compile_definitions( fc PRIVATE _CRT_NONSTDC_NO_DEPRECATE ) +else(WIN32) + target_compile_definitions( fc PRIVATE HAVE_EDITLINE ) + set( editline_libraries editline ) endif(WIN32) -# end readline stuff +# end editline stuff if( NOT CPP_STANDARD ) - set( CPP_STANDARD, "-std=c++11" ) + set( CPP_STANDARD "-std=c++11" ) endif() IF(WIN32) @@ -360,7 +398,6 @@ target_include_directories(fc ${OPENSSL_INCLUDE_DIR} "vendor/diff-match-patch-cpp-stl" ${CMAKE_CURRENT_SOURCE_DIR}/vendor/websocketpp - "${readline_includes}" PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp @@ -370,7 +407,7 @@ target_include_directories(fc IF(NOT WIN32) set(LINK_USR_LOCAL_LIB -L/usr/local/lib) ENDIF() -target_link_libraries( fc PUBLIC ${LINK_USR_LOCAL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${readline_libraries} ${ECC_LIB} ) +target_link_libraries( fc PUBLIC ${LINK_USR_LOCAL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${editline_libraries} ${ECC_LIB} ) if(MSVC) set_source_files_properties( src/network/http/websocket.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) @@ -495,3 +532,4 @@ ADD_CUSTOM_COMMAND(TARGET fc POST_BUILD ${POST_BUILD_STEP_COMMANDS} ) MESSAGE(STATUS "Finished fc module configuration...") + diff --git a/CMakeModules/FindReadline.cmake b/CMakeModules/FindReadline.cmake deleted file mode 100755 index 745cfe5..0000000 --- a/CMakeModules/FindReadline.cmake +++ /dev/null @@ -1,47 +0,0 @@ -# - Try to find readline include dirs and libraries -# -# Usage of this module as follows: -# -# find_package(Readline) -# -# Variables used by this module, they can change the default behaviour and need -# to be set before calling find_package: -# -# Readline_ROOT_DIR Set this variable to the root installation of -# readline if the module has problems finding the -# proper installation path. -# -# Variables defined by this module: -# -# READLINE_FOUND System has readline, include and lib dirs found -# Readline_INCLUDE_DIR The readline include directories. -# Readline_LIBRARY The readline library. - -find_path(Readline_ROOT_DIR - NAMES include/readline/readline.h -) - -find_path(Readline_INCLUDE_DIR - NAMES readline/readline.h - HINTS ${Readline_ROOT_DIR}/include -) - -find_library(Readline_LIBRARY - NAMES readline - HINTS ${Readline_ROOT_DIR}/lib -) - -if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - set(READLINE_FOUND TRUE) -else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - FIND_LIBRARY(Readline_LIBRARY NAMES readline) - include(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY ) - MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY) -endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - -mark_as_advanced( - Readline_ROOT_DIR - Readline_INCLUDE_DIR - Readline_LIBRARY -) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index 4957fc3..c811233 100755 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -7,22 +7,8 @@ #include #endif -#ifdef HAVE_READLINE -# include -# include -// I don't know exactly what version of readline we need. I know the 4.2 version that ships on some macs is -// missing some functions we require. We're developing against 6.3, but probably anything in the 6.x -// series is fine -# if RL_VERSION_MAJOR < 6 -# ifdef _MSC_VER -# pragma message("You have an old version of readline installed that might not support some of the features we need") -# pragma message("Readline support will not be compiled in") -# else -# warning "You have an old version of readline installed that might not support some of the features we need" -# warning "Readline support will not be compiled in" -# endif -# undef HAVE_READLINE -# endif +#ifdef HAVE_EDITLINE +# include "editline.h" # ifdef WIN32 # include # endif @@ -131,61 +117,107 @@ void cli::run() } -char * dupstr (const char* s) { - char *r; - - r = (char*) malloc ((strlen (s) + 1)); - strcpy (r, s); - return (r); -} - -char* my_generator(const char* text, int state) +/**** + * @brief loop through list of commands, attempting to find a match + * @param token what the user typed + * @param match sets to 1 if only 1 match was found + * @returns the remaining letters of the name of the command or NULL if 1 match not found + */ +static char *my_rl_complete(char *token, int *match) { - static int list_index, len; - const char *name; - if (!state) { - list_index = 0; - len = strlen (text); - } + const auto& cmds = cli_commands(); + const size_t partlen = strlen (token); /* Part of token */ - auto& cmd = cli_commands(); - - while( list_index < cmd.size() ) + std::vector> matched_cmds; + for( const std::string& it : cmds ) { - name = cmd[list_index].c_str(); - list_index++; - - if (strncmp (name, text, len) == 0) - return (dupstr(name)); + if( it.compare(0, partlen, token) == 0 ) + { + matched_cmds.push_back( it ); + } } - /* If no names matched, then return NULL. */ - return ((char *)NULL); + if( matched_cmds.size() == 0 ) + return NULL; + + const std::string& first_matched_cmd = matched_cmds[0]; + if( matched_cmds.size() == 1 ) + { + *match = 1; + std::string matched_cmd = first_matched_cmd + " "; + return strdup( matched_cmd.c_str() + partlen ); + } + + size_t first_cmd_len = first_matched_cmd.size(); + size_t matched_len = partlen; + for( ; matched_len < first_cmd_len; ++matched_len ) + { + char next_char = first_matched_cmd[matched_len]; + bool end = false; + for( const std::string& s : matched_cmds ) + { + if( s.size() <= matched_len || s[matched_len] != next_char ) + { + end = true; + break; + } + } + if( end ) + break; + } + + if( matched_len == partlen ) + return NULL; + + std::string matched_cmd_part = first_matched_cmd.substr( partlen, matched_len - partlen ); + return strdup( matched_cmd_part.c_str() ); } - -static char** cli_completion( const char * text , int start, int end) +/*** + * @brief return an array of matching commands + * @param token the incoming text + * @param array the resultant array of possible matches + * @returns the number of matches + */ +static int cli_completion(char *token, char ***array) { - char **matches; - matches = (char **)NULL; + auto& cmd = cli_commands(); + int num_commands = cmd.size(); -#ifdef HAVE_READLINE - if (start == 0) - matches = rl_completion_matches ((char*)text, &my_generator); - else - rl_bind_key('\t',rl_abort); -#endif + char **copy = (char **) malloc (num_commands * sizeof(char *)); + if (copy == NULL) + { + // possible out of memory + return 0; + } + int total_matches = 0; - return (matches); + int partlen = strlen(token); + + for (const std::string& it : cmd) + { + if ( it.compare(0, partlen, token) == 0) + { + copy[total_matches] = strdup ( it.c_str() ); + ++total_matches; + } + } + *array = copy; + + return total_matches; } - +/*** + * @brief Read input from the user + * @param prompt the prompt to display + * @param line what the user typed + */ void cli::getline( const fc::string& prompt, fc::string& line) { // getting file descriptor for C++ streams is near impossible // so we just assume it's the same as the C stream... -#ifdef HAVE_READLINE +#ifdef HAVE_EDITLINE #ifndef WIN32 if( isatty( fileno( stdin ) ) ) #else @@ -197,8 +229,8 @@ void cli::getline( const fc::string& prompt, fc::string& line) if( _isatty( _fileno( stdin ) ) ) #endif { - rl_attempted_completion_function = cli_completion; - + rl_set_complete_func(my_rl_complete); + rl_set_list_possib_func(cli_completion); static fc::thread getline_thread("getline"); getline_thread.async( [&](){ char* line_read = nullptr; @@ -206,10 +238,17 @@ void cli::getline( const fc::string& prompt, fc::string& line) line_read = readline(prompt.c_str()); if( line_read == nullptr ) FC_THROW_EXCEPTION( fc::eof_exception, "" ); - rl_bind_key( '\t', rl_complete ); - if( *line_read ) - add_history(line_read); line = line_read; + try + { + if (*line_read) + add_history(line_read); + } + catch(...) + { + free(line_read); + throw; + } free(line_read); }).wait(); } diff --git a/vendor/editline b/vendor/editline new file mode 160000 index 0000000..62bba78 --- /dev/null +++ b/vendor/editline @@ -0,0 +1 @@ +Subproject commit 62bba782585c6c18d7a2b27beeb60a45db9abb43 -- 2.45.2 From ecfe8f9858f858a4ff4283a2c3f30d859ac64df5 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 16 Oct 2020 02:15:01 +0000 Subject: [PATCH 2/2] increase buffer size for history --- src/rpc/cli.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpc/cli.cpp b/src/rpc/cli.cpp index c811233..6aef4e9 100755 --- a/src/rpc/cli.cpp +++ b/src/rpc/cli.cpp @@ -229,6 +229,7 @@ void cli::getline( const fc::string& prompt, fc::string& line) if( _isatty( _fileno( stdin ) ) ) #endif { + el_hist_size = 256; rl_set_complete_func(my_rl_complete); rl_set_list_possib_func(cli_completion); static fc::thread getline_thread("getline"); -- 2.45.2