Add linenoise-ng as alternative to readline

This commit is contained in:
Philippe Teuwen 2022-01-10 23:53:01 +01:00
commit 3ada10be72
11 changed files with 220 additions and 2 deletions

View file

@ -140,6 +140,12 @@ if (NOT SKIPREADLINE EQUAL 1)
if (READLINE_INCLUDE_DIRS AND READLINE_LIBRARIES)
set(READLINE_FOUND ON)
endif (READLINE_INCLUDE_DIRS AND READLINE_LIBRARIES)
else (NOT SKIPREADLINE EQUAL 1)
if (NOT SKIPLINENOISE EQUAL 1)
if (EXISTS ${PM3_ROOT}/client/deps/linenoise/)
set(LINENOISE_LOCAL_FOUND ON)
endif (EXISTS ${PM3_ROOT}/client/deps/linenoise/)
endif (NOT SKIPLINENOISE EQUAL 1)
endif (NOT SKIPREADLINE EQUAL 1)
if (NOT SKIPJANSSONSYSTEM EQUAL 1)
@ -500,6 +506,18 @@ else (SKIPREADLINE EQUAL 1)
endif (READLINE_FOUND)
endif(SKIPREADLINE EQUAL 1)
if (NOT READLINE_FOUND)
if (SKIPLINENOISE EQUAL 1)
message(STATUS "Linenoise library: skipped")
else (SKIPLINENOISE EQUAL 1)
if (LINENOISE_LOCAL_FOUND)
message(STATUS "Linenoise library: enabled")
else (LINENOISE_LOCAL_FOUND)
message(STATUS "Linenoise library: Linenoise not found, disabled")
endif (LINENOISE_LOCAL_FOUND)
endif (SKIPLINENOISE EQUAL 1)
endif (NOT READLINE_FOUND)
if (SKIPWHEREAMISYSTEM EQUAL 1)
message(STATUS "Whereami library: local library forced")
else (SKIPWHEREAMISYSTEM EQUAL 1)
@ -578,6 +596,13 @@ if (NOT JANSSON_FOUND)
set(ADDITIONAL_LNK pm3rrg_rdv4_jansson ${ADDITIONAL_LNK})
endif (NOT JANSSON_FOUND)
if (NOT READLINE_FOUND)
if (LINENOISE_LOCAL_FOUND)
add_definitions("-DHAVE_LINENOISE")
set(ADDITIONAL_LNK pm3rrg_rdv4_linenoise ${ADDITIONAL_LNK})
endif (LINENOISE_LOCAL_FOUND)
endif (NOT READLINE_FOUND)
if (NOT WHEREAMI_FOUND)
set(ADDITIONAL_LNK pm3rrg_rdv4_whereami ${ADDITIONAL_LNK})
endif (NOT WHEREAMI_FOUND)

View file

@ -78,6 +78,14 @@ JANSSONLIBINC = -I$(JANSSONLIBPATH)
JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a
JANSSONLIBLD =
## Linenoise
# Can be used if Readline is unavailable or explicitely disabled
# Requires to be unpacked, see deps/get_linenoise.sh
LINENOISELIBPATH = ./deps/linenoise
LINENOISELIBINC = -I$(LINENOISELIBPATH)
LINENOISELIB = $(LINENOISELIBPATH)/liblinenoise.a
LINENOISELIBLD =
## Lua
LUALIBPATH = ./deps/liblua
LUALIBINC = -I$(LUALIBPATH)
@ -146,6 +154,9 @@ STATICLIBS += $(HARDNESTEDLIB)
LDLIBS +=$(HARDNESTEDLIBLD)
PM3INCLUDES += $(HARDNESTEDLIBINC)
## Linenoise
# wait to see if Readline is available
## Lua
ifneq ($(SKIPLUASYSTEM),1)
ifdef MACPORTS_PREFIX
@ -325,6 +336,16 @@ ifneq ($(SKIPREADLINE),1)
LDLIBS += -lreadline
READLINE_FOUND = 1
else
## Linenoise
ifneq ($(SKIPLINENOISE),1)
ifneq (,$(wildcard $(LINENOISELIBPATH)))
STATICLIBS += $(LINENOISELIB)
LDLIBS += $(LINENOISELIBLD)
PM3INCLUDES += $(LINENOISELIBINC)
LINENOISE_LOCAL_FOUND = 1
endif
endif
endif
########
@ -362,6 +383,10 @@ ifeq ($(READLINE_FOUND),1)
PM3CFLAGS += -DHAVE_READLINE
endif
ifeq ($(LINENOISE_LOCAL_FOUND),1)
PM3CFLAGS += -DHAVE_LINENOISE
endif
ifeq ($(BT_FOUND),1)
PM3CFLAGS += -DHAVE_BLUEZ
endif
@ -466,6 +491,18 @@ else
endif
endif
ifneq ($(READLINE_FOUND),1)
ifeq ($(SKIPLINENOISE),1)
$(info Linenoise library: skipped)
else
ifeq ($(LINENOISE_LOCAL_FOUND),1)
$(info Linenoise library: enabled)
else
$(info Linenoise library: Linenoise not found, disabled)
endif
endif
endif
ifeq ($(SKIPWHEREAMISYSTEM),1)
$(info Whereami library: local library forced)
else
@ -737,6 +774,9 @@ clean:
$(Q)$(MAKE) --no-print-directory -C $(CLIPARSERLIBPATH) clean
$(Q)$(MAKE) --no-print-directory -C $(HARDNESTEDLIBPATH) clean
$(Q)$(MAKE) --no-print-directory -C $(JANSSONLIBPATH) clean
ifeq ($(LINENOISE_LOCAL_FOUND), 1)
$(Q)$(MAKE) --no-print-directory -C $(LINENOISELIBPATH) clean
endif
$(Q)$(MAKE) --no-print-directory -C $(LUALIBPATH) clean
$(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) clean
$(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) clean
@ -792,6 +832,12 @@ ifneq ($(JANSSON_FOUND),1)
$(Q)$(MAKE) --no-print-directory -C $(JANSSONLIBPATH) all
endif
$(LINENOISELIB): .FORCE
ifeq ($(LINENOISE_LOCAL_FOUND), 1)
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C $(LINENOISELIBPATH) all
endif
$(LUALIB): .FORCE
ifneq ($(LUA_FOUND),1)
$(info [*] MAKE $@ for $(LUAPLATFORM))

2
client/deps/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
linenoise/
linenoise.cmake

View file

@ -10,6 +10,9 @@ endif()
if (NOT TARGET pm3rrg_rdv4_jansson)
include(jansson.cmake)
endif()
if ((NOT TARGET pm3rrg_rdv4_linenoise) AND (EXISTS ${PM3_ROOT}/client/deps/linenoise/))
include(linenoise.cmake)
endif()
if (NOT TARGET pm3rrg_rdv4_lua)
include(lua.cmake)
endif()

58
client/deps/get_linenoise.sh Executable file
View file

@ -0,0 +1,58 @@
#!/bin/bash
# Can be used if Readline is unavailable or explicitely disabled
# Note that ConvertUTF.cpp is under redis-only license therefore
# if you are maintainer, think twice before including it
version=1.0.1
mkdir -p linenoise
ZP=linenoise-ng-$version
if [ ! -f "${ZP}.zip" ]; then
wget -O "${ZP}.zip" https://github.com/arangodb/linenoise-ng/archive/v$version.zip
fi
unzip -o -j "${ZP}.zip" $ZP/src/ConvertUTF.cpp $ZP/src/ConvertUTF.h $ZP/LICENSE $ZP/src/linenoise.cpp $ZP/include/linenoise.h $ZP/README.md $ZP/src/wcwidth.cpp -d linenoise
#echo "Please do make style"
echo "Generating linenoise.cmake..."
cat > linenoise.cmake << EOF
add_library(pm3rrg_rdv4_linenoise STATIC
linenoise/ConvertUTF.cpp
linenoise/linenoise.cpp
linenoise/wcwidth.cpp
)
target_compile_definitions(pm3rrg_rdv4_linenoise PRIVATE NDEBUG)
target_include_directories(pm3rrg_rdv4_linenoise INTERFACE linenoise)
target_compile_options(pm3rrg_rdv4_linenoise PRIVATE -Wall -Werror -O3)
set_property(TARGET pm3rrg_rdv4_linenoise PROPERTY POSITION_INDEPENDENT_CODE ON)
EOF
cd linenoise
echo "Generating linenoise/Makefile..."
cat > Makefile << EOF
MYSRCPATHS =
MYINCLUDES =
MYCXXFLAGS = -DNDEBUG -std=c++11 -fomit-frame-pointer
MYDEFS =
MYCXXSRCS = ConvertUTF.cpp linenoise.cpp wcwidth.cpp
LIB_A = liblinenoise.a
include ../../../Makefile.host
EOF
# Patch to get proper autocompletion of subcommands
patch << EOF
diff -Naur linenoise.cpp linenoise.cpp
+++ linenoise.cpp 2017-03-06 17:01:33.000000000 +0100
--- linenoise.cpp 2022-01-29 10:37:19.656202922 +0100
@@ -1956,7 +1956,7 @@
// character and
// extract a copy to parse. we also handle the case where tab is hit while
// not at end-of-line.
- int startIndex = pos;
+ int startIndex = 0;
while (--startIndex >= 0) {
if (strchr(breakChars, buf32[startIndex])) {
break;
EOF

Binary file not shown.

View file

@ -141,6 +141,12 @@ if (NOT SKIPREADLINE EQUAL 1)
if (READLINE_INCLUDE_DIRS AND READLINE_LIBRARIES)
set(READLINE_FOUND ON)
endif (READLINE_INCLUDE_DIRS AND READLINE_LIBRARIES)
else (NOT SKIPREADLINE EQUAL 1)
if (NOT SKIPLINENOISE EQUAL 1)
if (EXISTS ${PM3_ROOT}/client/deps/linenoise/)
set(LINENOISE_LOCAL_FOUND ON)
endif (EXISTS ${PM3_ROOT}/client/deps/linenoise/)
endif (NOT SKIPLINENOISE EQUAL 1)
endif (NOT SKIPREADLINE EQUAL 1)
if (NOT SKIPJANSSONSYSTEM EQUAL 1)
@ -501,6 +507,18 @@ else (SKIPREADLINE EQUAL 1)
endif (READLINE_FOUND)
endif(SKIPREADLINE EQUAL 1)
if (NOT READLINE_FOUND)
if (SKIPLINENOISE EQUAL 1)
message(STATUS "Linenoise library: skipped")
else (SKIPLINENOISE EQUAL 1)
if (LINENOISE_LOCAL_FOUND)
message(STATUS "Linenoise library: enabled")
else (LINENOISE_LOCAL_FOUND)
message(STATUS "Linenoise library: Linenoise not found, disabled")
endif (LINENOISE_LOCAL_FOUND)
endif (SKIPLINENOISE EQUAL 1)
endif (NOT READLINE_FOUND)
if (SKIPWHEREAMISYSTEM EQUAL 1)
message(STATUS "Whereami library: local library forced")
else (SKIPWHEREAMISYSTEM EQUAL 1)
@ -581,6 +599,13 @@ if (NOT JANSSON_FOUND)
set(ADDITIONAL_LNK pm3rrg_rdv4_jansson ${ADDITIONAL_LNK})
endif (NOT JANSSON_FOUND)
if (NOT READLINE_FOUND)
if (LINENOISE_LOCAL_FOUND)
add_definitions("-DHAVE_LINENOISE")
set(ADDITIONAL_LNK pm3rrg_rdv4_linenoise ${ADDITIONAL_LNK})
endif (LINENOISE_LOCAL_FOUND)
endif (NOT READLINE_FOUND)
if (NOT WHEREAMI_FOUND)
set(ADDITIONAL_LNK pm3rrg_rdv4_whereami ${ADDITIONAL_LNK})
endif (NOT WHEREAMI_FOUND)

View file

@ -995,8 +995,10 @@ void pm3_version(bool verbose, bool oneliner) {
PrintAndLogEx(NORMAL, " platform.................. " PM3HOSTOS " / " PM3HOSTARCH);
#if defined(HAVE_READLINE)
PrintAndLogEx(NORMAL, " Readline support.......... " _GREEN_("present"));
#elif defined(HAVE_LINENOISE)
PrintAndLogEx(NORMAL, " Linenoise support......... " _GREEN_("present"));
#else
PrintAndLogEx(NORMAL, " Readline support.......... " _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " Readline/Linenoise support." _YELLOW_("absent"));
#endif
#ifdef HAVE_GUI
PrintAndLogEx(NORMAL, " QT GUI support............ " _GREEN_("present"));

View file

@ -24,6 +24,8 @@
#if defined(HAVE_READLINE)
#include <readline/readline.h>
#include <readline/history.h>
#elif defined(HAVE_LINENOISE)
#include "linenoise.h"
#endif
#include "pm3line_vocabulory.h"
#include "pm3_cmd.h"
@ -73,6 +75,39 @@ static char **rl_command_completion(const char *text, int start, int end) {
return rl_completion_matches(text, rl_command_generator);
}
#elif defined(HAVE_LINENOISE)
static void ln_command_completion(const char *text, linenoiseCompletions *lc) {
int index = 0;
const char *prev_match = "";
size_t prev_match_len = 0;
size_t len = strlen(text);
const char *command;
while ((command = vocabulory[index].name)) {
// When no pm3 device present
// and the command is not available offline,
// we skip it.
if ((g_session.pm3_present == false) && (vocabulory[index].offline == false )) {
index++;
continue;
}
index++;
if (strncmp (command, text, len) == 0) {
const char *space = strstr(command + len, " ");
if (space != NULL) {
if ((prev_match_len == 0) || (strncmp (prev_match, command, prev_match_len < space - command ? prev_match_len : space - command) != 0)) {
linenoiseAddCompletion(lc, str_ndup(command, space - command + 1));
prev_match = command;
prev_match_len = space - command + 1;
}
} else {
linenoiseAddCompletion(lc, command);
}
}
}
}
#endif // HAVE_READLINE
# if defined(_WIN32)
@ -119,12 +154,17 @@ void pm3line_init(void) {
#ifdef RL_STATE_READCMD
rl_extend_line_buffer(1024);
#endif // RL_STATE_READCMD
#elif defined(HAVE_LINENOISE)
linenoiseInstallWindowChangeHandler();
linenoiseSetCompletionCallback(ln_command_completion);
#endif // HAVE_READLINE
}
char *pm3line_read(const char *s) {
#if defined(HAVE_READLINE)
return readline(s);
#elif defined(HAVE_LINENOISE)
return linenoise(s);
#else
printf("%s", s);
char *answer = NULL;
@ -160,6 +200,12 @@ int pm3line_load_history(const char *path) {
} else {
return PM3_ESOFT;
}
#elif defined(HAVE_LINENOISE)
if (linenoiseHistoryLoad(path) == 0) {
return PM3_SUCCESS;
} else {
return PM3_ESOFT;
}
#else
(void) path;
return PM3_ENOTIMPL;
@ -173,6 +219,9 @@ void pm3line_add_history(const char *line) {
if ((!entry) || (strcmp(entry->line, line) != 0)) {
add_history(line);
}
#elif defined(HAVE_LINENOISE)
// linenoiseHistoryAdd takes already care of duplicate entries
linenoiseHistoryAdd(line);
#else
(void) line;
#endif
@ -182,6 +231,8 @@ void pm3line_flush_history(void) {
if (g_session.history_path) {
#if defined(HAVE_READLINE)
write_history(g_session.history_path);
#elif defined(HAVE_LINENOISE)
linenoiseHistorySave(g_session.history_path);
#endif // HAVE_READLINE
free(g_session.history_path);
g_session.history_path = NULL;

View file

@ -66,6 +66,11 @@ It's also possible to skip parts even if libraries are present in the compilatio
* `make client SKIPJANSSONSYSTEM=1` to skip system Jansson lib even if libjansson is present, use embedded Jansson lib instead
* `make client SKIPWHEREAMISYSTEM=1` to skip system Whereami lib even if libwhereami is present, use embedded whereami lib instead
By default, the client is using Readline, but this can be disabled:
* `make client SKIPREADLINE=1` to skip system Readline lib even if libreadline is present
When Readline is disabled, it is possible to use Linenoise instead. Note that Linenoise-ng contains `ConvertUTF.cpp` which is under a redistribution-only license, therefore think twice before including it in a release. To get Linenoise-ng, see `client/deps/get_linenoise.sh`.
If you're cross-compiling, these ones might be useful:
* `make client SKIPREVENGTEST=1` to skip compilation and execution of a consistency test for reveng, which can be problematic in case of cross-compilation

View file

@ -62,7 +62,7 @@ At the moment both are maintained because they don't perfectly overlap yet.
| dep libm | sys | sys | |
| libm detection | **none** | **none** (1) | (1) cf https://cmake.org/pipermail/cmake/2019-March/069168.html ? |
| dep mbedtls | in_common | in_common | no sys lib: missing support for CMAC in def conf (btw no .pc available) |
| dep python3 | opt, sys, <3.8 & 3.8 | opt, sys, <3.8 & 3.8 | |
| dep python3 | opt, sys, < 3.8 & 3.8 | opt, sys, < 3.8 & 3.8 | |
| python3 detection | pc | pkg_search_module | |
| `SKIPPYTHON` | yes | yes | |
| dep pthread | sys | sys | |
@ -74,6 +74,7 @@ At the moment both are maintained because they don't perfectly overlap yet.
| dep readline | sys | sys | |
| readline detection | **none** (1) | find*(2), Cross:getzip | (1) OSX: hardcoded path (2) additional paths for OSX |
| `SKIPREADLINE` | yes | yes | CLI not fully functional without Readline |
| `SKIPLINENOISE` | yes | yes | replacement of Readline, not as complete |
| dep reveng | in_deps | in_deps | |
| `SKIPREVENGTEST` | yes(1) | **no**(2) | (1) e.g. if cross-compilation (2) tests aren't compiled/ran with cmake |
| dep tinycbor | in_deps | in_deps | |