pm3line API to hide readline, linenoise as alternative

This commit is contained in:
Philippe Teuwen
2020-06-19 00:39:20 +02:00
parent f1ae469cd7
commit f315d89f87
6 changed files with 165 additions and 68 deletions

View File

@@ -279,6 +279,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/preferences.c ${PM3_ROOT}/client/src/preferences.c
${PM3_ROOT}/client/src/pm3_binlib.c ${PM3_ROOT}/client/src/pm3_binlib.c
${PM3_ROOT}/client/src/pm3_bitlib.c ${PM3_ROOT}/client/src/pm3_bitlib.c
${PM3_ROOT}/client/src/pm3line.c
${PM3_ROOT}/client/src/prng.c ${PM3_ROOT}/client/src/prng.c
${PM3_ROOT}/client/src/scandir.c ${PM3_ROOT}/client/src/scandir.c
${PM3_ROOT}/client/src/scripting.c ${PM3_ROOT}/client/src/scripting.c

View File

@@ -516,6 +516,7 @@ SRCS = aidsearch.c \
pm3_bitlib.c \ pm3_bitlib.c \
preferences.c \ preferences.c \
prng.c \ prng.c \
pm3line.c \
proxmark3.c \ proxmark3.c \
scandir.c \ scandir.c \
uart/uart_posix.c \ uart/uart_posix.c \

View File

@@ -9,13 +9,8 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdhflegic.h" #include "cmdhflegic.h"
#include <stdio.h> // for Mingw readline
#include <ctype.h> // tolower #include <ctype.h> // tolower
#include "pm3line.h" // pm3line_read, pm3line_free
#ifdef HAVE_READLINE
#include <readline/readline.h>
#endif
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" // clearCommandBuffer #include "comms.h" // clearCommandBuffer
#include "cmdtrace.h" #include "cmdtrace.h"
@@ -705,18 +700,11 @@ static int CmdLegicWrbl(const char *Cmd) {
PrintAndLogEx(NORMAL, "#####################################"); PrintAndLogEx(NORMAL, "#####################################");
const char *confirm = "Do you really want to continue? y(es)/n(o) : "; const char *confirm = "Do you really want to continue? y(es)/n(o) : ";
bool overwrite = false; bool overwrite = false;
#ifdef HAVE_READLINE
char *answer = readline(confirm); char *answer = pm3line_read(confirm);
overwrite = (answer[0] == 'y' || answer[0] == 'Y'); overwrite = (answer[0] == 'y' || answer[0] == 'Y');
#else pm3line_free(answer);
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);
if (!overwrite) { if (!overwrite) {
PrintAndLogEx(NORMAL, "command cancelled"); PrintAndLogEx(NORMAL, "command cancelled");
return PM3_EOPABORTED; return PM3_EOPABORTED;

124
client/src/pm3line.c Normal file
View File

@@ -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 <stdlib.h>
#include <stdio.h> // for Mingw readline and for getline
#ifdef HAVE_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#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
}

20
client/src/pm3line.h Normal file
View File

@@ -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__

View File

@@ -10,16 +10,12 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "proxmark3.h" #include "proxmark3.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> // for Mingw readline #include <stdio.h>
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#ifdef HAVE_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#include <ctype.h> #include <ctype.h>
#include "pm3line.h"
#include "usart_defs.h" #include "usart_defs.h"
#include "util_posix.h" #include "util_posix.h"
#include "proxgui.h" #include "proxgui.h"
@@ -122,14 +118,11 @@ static int check_comm(void) {
if (IsCommunicationThreadDead() && session.pm3_present) { if (IsCommunicationThreadDead() && session.pm3_present) {
PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") " mode. Use "_YELLOW_("\"hw connect\"") " to reconnect\n"); PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") " mode. Use "_YELLOW_("\"hw connect\"") " to reconnect\n");
prompt_dev = PROXPROMPT_DEV_OFFLINE; prompt_dev = PROXPROMPT_DEV_OFFLINE;
#ifdef HAVE_READLINE
char prompt[PROXPROMPT_MAX_SIZE] = {0}; char prompt[PROXPROMPT_MAX_SIZE] = {0};
prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev); prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev);
char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0};
memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors); memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors);
rl_set_prompt(prompt_filtered); pm3line_update_prompt(prompt_filtered);
rl_forced_update_display();
#endif
CloseProxmark(); CloseProxmark();
} }
return 0; 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; char *my_history_path = NULL;
if (searchHomeFilePath(&my_history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) { if (searchHomeFilePath(&my_history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "No history will be recorded");
my_history_path = NULL; my_history_path = NULL;
} else { } 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... // loops every time enter is pressed...
while (1) { while (1) {
bool printprompt = false; bool printprompt = false;
@@ -293,30 +288,13 @@ check_script:
printprompt = true; printprompt = true;
} else { } else {
#ifdef HAVE_READLINE pm3line_check(check_comm);
rl_event_hook = check_comm;
#else
check_comm();
#endif
prompt_ctx = PROXPROMPT_CTX_INTERACTIVE; prompt_ctx = PROXPROMPT_CTX_INTERACTIVE;
char prompt[PROXPROMPT_MAX_SIZE] = {0}; char prompt[PROXPROMPT_MAX_SIZE] = {0};
prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev); prompt_compose(prompt, sizeof(prompt), prompt_ctx, prompt_dev);
char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0}; char prompt_filtered[PROXPROMPT_MAX_SIZE] = {0};
memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors); memcpy_filter_ansi(prompt_filtered, prompt, sizeof(prompt_filtered), !session.supports_colors);
#ifdef HAVE_READLINE cmd = pm3line_read(prompt_filtered);
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
fflush(NULL); fflush(NULL);
} }
} }
@@ -354,16 +332,10 @@ check_script:
PrintAndLogEx(NORMAL, "%s%s", prompt_filtered, cmd); PrintAndLogEx(NORMAL, "%s%s", prompt_filtered, cmd);
g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG;
#ifdef HAVE_READLINE
// add to history if not from a script // add to history if not from a script
if (!current_cmdscriptfile()) { if (!current_cmdscriptfile()) {
HIST_ENTRY *entry = history_get(history_length); pm3line_add_history(cmd);
// add if not identical to latest recorded cmd
if ((!entry) || (strcmp(entry->line, cmd) != 0)) {
add_history(cmd);
} }
}
#endif
// process cmd // process cmd
int ret = CommandReceived(cmd); int ret = CommandReceived(cmd);
// exit or quit // exit or quit
@@ -390,12 +362,10 @@ check_script:
while (current_cmdscriptfile()) while (current_cmdscriptfile())
pop_cmdscriptfile(); pop_cmdscriptfile();
#ifdef HAVE_READLINE
if (my_history_path) { if (my_history_path) {
write_history(my_history_path); pm3line_save_history(my_history_path);;
free(my_history_path); free(my_history_path);
} }
#endif
if (cmd) { if (cmd) {
free(cmd); free(cmd);
cmd = NULL; cmd = NULL;
@@ -700,14 +670,7 @@ int main(int argc, char *argv[]) {
char *port = NULL; char *port = NULL;
uint32_t speed = 0; uint32_t speed = 0;
#ifdef HAVE_READLINE pm3line_init();
/* initialize history */
using_history();
#ifdef RL_STATE_READCMD
rl_extend_line_buffer(1024);
#endif // RL_STATE_READCMD
#endif // HAVE_READLINE
char *exec_name = argv[0]; char *exec_name = argv[0];
#if defined(_WIN32) #if defined(_WIN32)