From 3ada10be721a92845cbad1f2f78db2343b1fda50 Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Mon, 10 Jan 2022 23:53:01 +0100 Subject: [PATCH] Add linenoise-ng as alternative to readline --- client/CMakeLists.txt | 25 ++++++++++ client/Makefile | 46 +++++++++++++++++++ client/deps/.gitignore | 2 + client/deps/CMakeLists.txt | 3 ++ client/deps/get_linenoise.sh | 58 ++++++++++++++++++++++++ client/deps/linenoise-ng-1.0.1.zip | Bin 0 -> 47590 bytes client/experimental_lib/CMakeLists.txt | 25 ++++++++++ client/src/cmdhw.c | 4 +- client/src/pm3line.c | 51 +++++++++++++++++++++ doc/md/Development/Maintainers.md | 5 ++ doc/md/Development/Makefile-vs-CMake.md | 3 +- 11 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 client/deps/.gitignore create mode 100755 client/deps/get_linenoise.sh create mode 100644 client/deps/linenoise-ng-1.0.1.zip diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index e377616f8..f6a0c9e9f 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -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) diff --git a/client/Makefile b/client/Makefile index 905609b36..4debb130f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -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)) diff --git a/client/deps/.gitignore b/client/deps/.gitignore new file mode 100644 index 000000000..c3eede102 --- /dev/null +++ b/client/deps/.gitignore @@ -0,0 +1,2 @@ +linenoise/ +linenoise.cmake diff --git a/client/deps/CMakeLists.txt b/client/deps/CMakeLists.txt index f7b96a7ea..87613c0fe 100644 --- a/client/deps/CMakeLists.txt +++ b/client/deps/CMakeLists.txt @@ -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() diff --git a/client/deps/get_linenoise.sh b/client/deps/get_linenoise.sh new file mode 100755 index 000000000..4bb6dbc81 --- /dev/null +++ b/client/deps/get_linenoise.sh @@ -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 diff --git a/client/deps/linenoise-ng-1.0.1.zip b/client/deps/linenoise-ng-1.0.1.zip new file mode 100644 index 0000000000000000000000000000000000000000..8093590c01eb391698ea2d65aab8c350c9579094 GIT binary patch literal 47590 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

4EfN2dPE& zsCj-Cr1=uegrN!tmd>_|+#KMz*g21S{oqnO-2e`Fb@;>19uE7?*5TeR{@pv+`T_sq z9gGL~<){5UA{wA7VG^#QiC3KBtU~(^IVN;My7f%oYcEKo0}H)RhdU@S=y;D)LY6N@BXQf3SaatT0tR#tK#R5L+dMot@|` zYIF$1?;E1Fb+oGL6lU=?i}sBDRztja>sP0HhI16nt*+-71hlF zQe@GRx9uWw??X8dVbEngkD$;+fzs|mH5=-(SgH+w9bW2mPJev2vv;QEk9m5$^R9iS zHM3<23rIpp(A`zkBjhM$Rzt-T8G|MWYd5q8X|Cd_nVG41ymhp>eYm-^2eTAv)?s03 z73G9cKp90Xh-Rn=os#24Sx^AP%rWP$m8F`?b|Nr)X_eeRX-%0dt#!_Oy~eccCy8>C zR$`MtdLa z!lhZA&Y-Mi8k5c2K3=v~!Er{}dWpj0?`=U+e(t3$a)kOBog(%YyVvOYu=rDHDZ7qh zItseZtQs}C=M7`Hj(7IA-T>N1e+RhNW+nMvthU4&)LOjG&Y_kb85Lca@y(KW!W5=- z6L%*{JEH+web8V`H-=){U9=Qkj4m(nu;ltG>RgEq*~+BU?2S^ofI7;u5j|5Uht!BX zIi&AvfKxFlSP#!3Y)uMd1Dk|@-`HT|IK9OJjZc>H_G$4|lIO_)#H91|I2leDISFr? zkz0ALM=r&jf>eG#ZvXvM4Wn)&@CEtgD5%=&KLMZ7jc=T%#)>s!N{APsuiE)c~zP){x#=GUvO2 zWW~Hu*7uv1m2nu;b!iAGt!1Ee%vuPpFt=OE?e8}j317?$Mv*2=~1pj5b~tMbk*FL0SdxdODs z2mjy^r+&yv*o7$O1GG;d))HS6>^x9lHJZ1DN6bfFWMa;Qbil!2 z!9^l3t+rZ9MwGm%kn5+M+rvrZ#8+u|xm#hknC63W>Xg$jVaug-QFxZFyD9_iwMPh! zlT(pyg0US#${BGafe+a~qvY~YmGGmX{8X4d`7BN5LLrhVoaE86%!p8m>c45n-TfZ7 z+7P$aFVdhM78jtNPYeyHZk=Y12IR&F-Z)s^v-c(kgF^vwc~B_Ok8%C4#=DX#W2jJ- z>_v_^Co8ql90SYhK;2Ip*iuJma4FJAU1-ik;qWd%1-hrd|7l2qeBZE<97hpds$M$s z;cOj>5Hh$)CCRWRi@MI;PAy{R^!Qv&+ppX4R!5^xNG|@Q_NU&rA23mqnSX^Cy`}l4 zd1+#A=9ku;jj{`~ybu>#C1m+LtfLZTy^i{Q367K9YnP`@7vP+jo0Q#4qihF=EtDUt zv>ub-`TC$Tmb-GN5Rv8)N8aKJ5fw?zeAcy=RU?DZh6(^=?h(C8d+NB7%gs(=iHgE< zKT}|GXR1FQOPaaJYGjKuz~O-z?D}|XRLQWG(1N|9D{nrFE&2X=#79qfQsc7l*VAvF zpJ@+DHBa6ppGe6OVh^K@py5^)ZEpZmBQ=;%!m2y|m zcUI}X>Tb?9%J};9OokwH#fQJvON_z#`$GjFYhW{zQC@ySfBvSCpU2lNMeTBSR1hmU(Aud4a2$%5Rk72$<3F8}vg6O_#{P}xOd4$PerIW1ak##^h`cRI$xnvICMGAByNO~g(11EV`gp?C#F@}oeSea zNDCKqAV(Vl{8^FnhH|9_u}pZ2?VByJTI�p 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 literal 0 HcmV?d00001 diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index a31a3110d..618b5af28 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -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) diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 991815e46..5e462ea8d 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -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")); diff --git a/client/src/pm3line.c b/client/src/pm3line.c index f070d3813..91e7df6c2 100644 --- a/client/src/pm3line.c +++ b/client/src/pm3line.c @@ -24,6 +24,8 @@ #if defined(HAVE_READLINE) #include #include +#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; diff --git a/doc/md/Development/Maintainers.md b/doc/md/Development/Maintainers.md index 2055e5bd2..2a72e500f 100644 --- a/doc/md/Development/Maintainers.md +++ b/doc/md/Development/Maintainers.md @@ -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 diff --git a/doc/md/Development/Makefile-vs-CMake.md b/doc/md/Development/Makefile-vs-CMake.md index 79ac43e2c..c54e911ff 100644 --- a/doc/md/Development/Makefile-vs-CMake.md +++ b/doc/md/Development/Makefile-vs-CMake.md @@ -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 | |