From f315d89f87a2194b2bf458c3fa41fd1b766beaec Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Fri, 19 Jun 2020 00:39:20 +0200 Subject: [PATCH] pm3line API to hide readline, linenoise as alternative --- client/CMakeLists.txt | 1 + client/Makefile | 1 + client/src/cmdhflegic.c | 22 ++----- client/src/pm3line.c | 124 ++++++++++++++++++++++++++++++++++++++++ client/src/pm3line.h | 20 +++++++ client/src/proxmark3.c | 65 +++++---------------- 6 files changed, 165 insertions(+), 68 deletions(-) create mode 100644 client/src/pm3line.c create mode 100644 client/src/pm3line.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 3529754a5..44128ce90 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -279,6 +279,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/preferences.c ${PM3_ROOT}/client/src/pm3_binlib.c ${PM3_ROOT}/client/src/pm3_bitlib.c + ${PM3_ROOT}/client/src/pm3line.c ${PM3_ROOT}/client/src/prng.c ${PM3_ROOT}/client/src/scandir.c ${PM3_ROOT}/client/src/scripting.c diff --git a/client/Makefile b/client/Makefile index 3bd059318..be65d4fee 100644 --- a/client/Makefile +++ b/client/Makefile @@ -516,6 +516,7 @@ SRCS = aidsearch.c \ pm3_bitlib.c \ preferences.c \ prng.c \ + pm3line.c \ proxmark3.c \ scandir.c \ uart/uart_posix.c \ diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index a91c1a418..eb30c41b2 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -9,13 +9,8 @@ //----------------------------------------------------------------------------- #include "cmdhflegic.h" -#include // for Mingw readline #include // tolower - -#ifdef HAVE_READLINE -#include -#endif - +#include "pm3line.h" // pm3line_read, pm3line_free #include "cmdparser.h" // command_t #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" @@ -705,18 +700,11 @@ static int CmdLegicWrbl(const char *Cmd) { PrintAndLogEx(NORMAL, "#####################################"); const char *confirm = "Do you really want to continue? y(es)/n(o) : "; bool overwrite = false; -#ifdef HAVE_READLINE - char *answer = readline(confirm); + + char *answer = pm3line_read(confirm); overwrite = (answer[0] == 'y' || answer[0] == 'Y'); -#else - printf("%s", confirm); - char *answer = NULL; - size_t anslen = 0; - if (getline(&answer, &anslen, stdin) > 0) { - overwrite = (answer[0] == 'y' || answer[0] == 'Y'); - } -#endif - free(answer); + pm3line_free(answer); + if (!overwrite) { PrintAndLogEx(NORMAL, "command cancelled"); return PM3_EOPABORTED; diff --git a/client/src/pm3line.c b/client/src/pm3line.c new file mode 100644 index 000000000..b6f5dc82c --- /dev/null +++ b/client/src/pm3line.c @@ -0,0 +1,124 @@ +// Copyright (C) 2020 Doegox +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- + +#include "pm3line.h" +#include +#include // for Mingw readline and for getline +#ifdef HAVE_READLINE +#include +#include +#elif HAVE_LINENOISE +#include "linenoise.h" +#endif +#include "pm3_cmd.h" + +void pm3line_init(void) { +#ifdef HAVE_READLINE + /* initialize history */ + using_history(); + +#ifdef RL_STATE_READCMD + rl_extend_line_buffer(1024); +#endif // RL_STATE_READCMD +#elif HAVE_LINENOISE + linenoiseInstallWindowChangeHandler(); +#endif // HAVE_READLINE +} + +char *pm3line_read(const char *s) { +#ifdef HAVE_READLINE + return readline(s); +#elif HAVE_LINENOISE + return linenoise(s); +#else + printf("%s", s); + char *answer = NULL; + size_t anslen = 0; + int ret; + if ((ret = getline(&answer, &anslen, stdin)) < 0) { + // TODO this happens also when kbd_enter_pressed() is used, with a key pressed or not + printf("DEBUG: getline returned %i", ret); + free(answer); + answer = NULL; + } + return answer; +#endif +} + +void pm3line_free(void *ref) { + free(ref); +} + +void pm3line_update_prompt(const char *prompt) { +#ifdef HAVE_READLINE + rl_set_prompt(prompt); + rl_forced_update_display(); +#else + (void) prompt; +#endif +} + +int pm3line_load_history(const char *path) { +#ifdef HAVE_READLINE + if (read_history(path) == 0) { + return PM3_SUCCESS; + } else { + return PM3_ESOFT; + } +#elif HAVE_LINENOISE + if (linenoiseHistoryLoad(path) == 0) { + return PM3_SUCCESS; + } else { + return PM3_ESOFT; + } +#else + (void) path; + return PM3_ENOTIMPL; +#endif +} + +void pm3line_add_history(const char *line) { +#ifdef HAVE_READLINE + HIST_ENTRY *entry = history_get(history_length); + // add if not identical to latest recorded line + if ((!entry) || (strcmp(entry->line, line) != 0)) { + add_history(line); + } +#elif HAVE_LINENOISE + // linenoiseHistoryAdd takes already care of duplicate entries + linenoiseHistoryAdd(line); +#else + (void) line; +#endif +} + +int pm3line_save_history(const char *path) { +#ifdef HAVE_READLINE + if (write_history(path) == 0) { + return PM3_SUCCESS; + } else { + return PM3_ESOFT; + } +#elif HAVE_LINENOISE + if (linenoiseHistorySave(path) == 0) { + return PM3_SUCCESS; + } else { + return PM3_ESOFT; + } +#else + (void) path; + return PM3_ENOTIMPL; +#endif +} + +void pm3line_check(int (check)(void)) { +#ifdef HAVE_READLINE + rl_event_hook = check; +#else + check(); +#endif +} diff --git a/client/src/pm3line.h b/client/src/pm3line.h new file mode 100644 index 000000000..ea2fb3bbe --- /dev/null +++ b/client/src/pm3line.h @@ -0,0 +1,20 @@ +// Copyright (C) 2020 Doegox +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- + +#ifndef PM3LINE_H__ +#define PM3LINE_H__ + +void pm3line_init(void); +char *pm3line_read(const char* s); +void pm3line_free(void *ref); +void pm3line_update_prompt(const char *prompt); +int pm3line_load_history(const char *path); +void pm3line_add_history(const char *line); +int pm3line_save_history(const char *path); +void pm3line_check(int (check)(void)); + +#endif // PM3LINE_H__ diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index d820e297d..f6cb77485 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -10,16 +10,12 @@ //----------------------------------------------------------------------------- #include "proxmark3.h" - #include -#include // for Mingw readline +#include #include #include -#ifdef HAVE_READLINE -#include -#include -#endif #include +#include "pm3line.h" #include "usart_defs.h" #include "util_posix.h" #include "proxgui.h" @@ -122,14 +118,11 @@ static int check_comm(void) { if (IsCommunicationThreadDead() && session.pm3_present) { PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") " mode. Use "_YELLOW_("\"hw connect\"") " to reconnect\n"); prompt_dev = PROXPROMPT_DEV_OFFLINE; -#ifdef HAVE_READLINE char prompt[PROXPROMPT_MAX_SIZE] = {0}; prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev); char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors); - rl_set_prompt(prompt_filtered); - rl_forced_update_display(); -#endif + pm3line_update_prompt(prompt_filtered); CloseProxmark(); } return 0; @@ -210,15 +203,17 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { } } -#ifdef HAVE_READLINE + bool loaded_history = false; char *my_history_path = NULL; if (searchHomeFilePath(&my_history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) { - PrintAndLogEx(ERR, "No history will be recorded"); my_history_path = NULL; } else { - read_history(my_history_path); + loaded_history = (pm3line_load_history(my_history_path) == PM3_SUCCESS); } -#endif + if (! loaded_history) { + PrintAndLogEx(ERR, "No history will be recorded"); + } + // loops every time enter is pressed... while (1) { bool printprompt = false; @@ -293,30 +288,13 @@ check_script: printprompt = true; } else { -#ifdef HAVE_READLINE - rl_event_hook = check_comm; -#else - check_comm(); -#endif + pm3line_check(check_comm); prompt_ctx = PROXPROMPT_CTX_INTERACTIVE; char prompt[PROXPROMPT_MAX_SIZE] = {0}; prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev); char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors); -#ifdef HAVE_READLINE - cmd = readline(prompt_filtered); -#else - printf("%s", prompt_filtered); - cmd = NULL; - size_t len = 0; - int ret; - if ((ret = getline(&cmd, &len, stdin)) < 0) { - // TODO this happens also when kbd_enter_pressed() is used, with a key pressed or not - printf("GETLINE ERR %i", ret); - free(cmd); - cmd = NULL; - } -#endif + cmd = pm3line_read(prompt_filtered); fflush(NULL); } } @@ -354,16 +332,10 @@ check_script: PrintAndLogEx(NORMAL, "%s%s", prompt_filtered, cmd); g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; -#ifdef HAVE_READLINE // add to history if not from a script if (!current_cmdscriptfile()) { - HIST_ENTRY *entry = history_get(history_length); - // add if not identical to latest recorded cmd - if ((!entry) || (strcmp(entry->line, cmd) != 0)) { - add_history(cmd); - } + pm3line_add_history(cmd); } -#endif // process cmd int ret = CommandReceived(cmd); // exit or quit @@ -390,12 +362,10 @@ check_script: while (current_cmdscriptfile()) pop_cmdscriptfile(); -#ifdef HAVE_READLINE if (my_history_path) { - write_history(my_history_path); + pm3line_save_history(my_history_path);; free(my_history_path); } -#endif if (cmd) { free(cmd); cmd = NULL; @@ -700,14 +670,7 @@ int main(int argc, char *argv[]) { char *port = NULL; uint32_t speed = 0; -#ifdef HAVE_READLINE - /* initialize history */ - using_history(); - -#ifdef RL_STATE_READCMD - rl_extend_line_buffer(1024); -#endif // RL_STATE_READCMD -#endif // HAVE_READLINE + pm3line_init(); char *exec_name = argv[0]; #if defined(_WIN32)