diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cfc2d76f..41880a244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Fix - move des functions to libcrypto (@merlokk) + - Added `CLIGetOptionList` to cliparser that makes it easier to implement text options in the cli (@merlokk) - Added experimental support for macOS users utilizing MacPorts instead of Homebrew (@linuxgemini) - Added `pm3_online_check.py` - a script to verify and initialize a Proxmark3 RDV4 device (@iceman1001) diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index ec9f50e20..ad89856cd 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -298,6 +298,64 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int return 0; } +int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, int *value) { + char data[200] = {0}; + int datalen = 0; + int res = CLIParamStrToBuf(argstr, (uint8_t *)data, sizeof(data), &datalen); + if (res) + return res; + + // no data to check - we do not touch *value, just return + if (datalen == 0) + return 0; + + str_lower(data); + + int val = -1; + int cntr = 0; + for (int i = 0; i < CLI_MAX_OPTLIST_LEN; i++) { + // end of array + if (option_array[i].text == NULL) + break; + // exact match + if (strcmp(option_array[i].text, data) == 0) { + *value = option_array[i].code; + return 0; + } + // partial match + if (strncmp(option_array[i].text, data, datalen) == 0) { + val = option_array[i].code; + cntr++; + } + } + + // check partial match + if (cntr == 0) { + PrintAndLogEx(ERR, "Parameter error: No similar option to `%s`. Valid options: %s\n", argstr->sval[0], argstr->hdr.datatype); + return 20; + } + if (cntr > 1) { + PrintAndLogEx(ERR, "Parameter error: Several options fit to `%s`. Valid options: %s\n", argstr->sval[0], argstr->hdr.datatype); + return 21; + } + + *value = val; + return 0; +} + +const char *CLIGetOptionListStr(const CLIParserOption *option_array, int value) { + static const char *errmsg = "n/a"; + + for (int i = 0; i < CLI_MAX_OPTLIST_LEN; i++) { + if (option_array[i].text == NULL) + break; + if (option_array[i].code == value) + return option_array[i].text; + } + return errmsg; +} + + // hexstr -> u64, w optional len input and default value fallback. // 0 = failed // 1 = OK diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index 39a5792f8..f50fec2ee 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -51,6 +51,8 @@ #define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), (*datalen), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} +#define CLIGetOptionListWithReturn(ctx, paramnum, option_array, option_array_len, value) if (CLIGetOptionList(arg_get_str((ctx), (paramnum)), (option_array), (option_array_len), (value))) {CLIParserFree((ctx)); return PM3_ESOFT;} + typedef struct { void **argtable; size_t argtableLen; @@ -59,6 +61,14 @@ typedef struct { const char *programHelp; char buf[1024 + 60]; } CLIParserContext; + +#define CLI_MAX_OPTLIST_LEN 50 +// option list needs to have NULL at the last record int the field `text` +typedef struct { + int code; + const char *text; +} CLIParserOption; + int CLIParserInit(CLIParserContext **ctx, const char *vprogramName, const char *vprogramHint, const char *vprogramHelp); void CLIParserPrintHelp(CLIParserContext *ctx); int CLIParserParseString(CLIParserContext *ctx, const char *str, void *vargtable[], size_t vargtableLen, bool allowEmptyExec); @@ -69,6 +79,10 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); int CLIParamBinToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); +// names in the CLIParserOption array must be in the lowercase format +int CLIGetOptionList(struct arg_str *argstr, const CLIParserOption *option_array, int *value); +const char *CLIGetOptionListStr(const CLIParserOption *option_array, int value); + uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def); int arg_get_u64_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint64_t def, uint64_t *out, uint8_t nlen, bool optional); int arg_get_u32_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out);