2018-10-11 16:48:46 +08:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Copyright (C) 2017 Merlok
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Command line parser core commands
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "cliparser.h"
|
|
|
|
#include <string.h>
|
2020-06-01 23:30:33 +08:00
|
|
|
#include <stdlib.h>
|
2018-10-11 16:48:46 +08:00
|
|
|
|
2020-06-01 23:30:33 +08:00
|
|
|
int CLIParserInit(CLIParserContext **ctx, const char *vprogramName, const char *vprogramHint, const char *vprogramHelp) {
|
|
|
|
*ctx = malloc(sizeof(CLIParserContext));
|
|
|
|
if (!*ctx) {
|
|
|
|
printf("ERROR: Insufficient memory\n");
|
|
|
|
fflush(stdout);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
(*ctx)->argtable = NULL;
|
|
|
|
(*ctx)->argtableLen = 0;
|
|
|
|
(*ctx)->programName = vprogramName;
|
|
|
|
(*ctx)->programHint = vprogramHint;
|
|
|
|
(*ctx)->programHelp = vprogramHelp;
|
|
|
|
memset((*ctx)->buf, 0x00, sizeof((*ctx)->buf));
|
2019-03-10 06:35:06 +08:00
|
|
|
return 0;
|
2018-10-11 16:48:46 +08:00
|
|
|
}
|
|
|
|
|
2020-06-01 23:30:33 +08:00
|
|
|
int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargtable[], size_t vargtableLen, bool allowEmptyExec) {
|
2019-03-10 06:35:06 +08:00
|
|
|
int nerrors;
|
|
|
|
|
2020-06-01 23:30:33 +08:00
|
|
|
ctx->argtable = vargtable;
|
|
|
|
ctx->argtableLen = vargtableLen;
|
2019-03-10 06:35:06 +08:00
|
|
|
|
|
|
|
/* verify the argtable[] entries were allocated sucessfully */
|
2020-06-01 23:30:33 +08:00
|
|
|
if (arg_nullcheck(ctx->argtable) != 0) {
|
2019-03-10 06:35:06 +08:00
|
|
|
/* NULL entries were detected, some allocations must have failed */
|
|
|
|
printf("ERROR: Insufficient memory\n");
|
2020-04-12 02:41:05 +08:00
|
|
|
fflush(stdout);
|
2019-03-10 06:35:06 +08:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
/* Parse the command line as defined by argtable[] */
|
2020-06-01 23:30:33 +08:00
|
|
|
nerrors = arg_parse(argc, argv, ctx->argtable);
|
2019-03-10 06:35:06 +08:00
|
|
|
|
|
|
|
/* special case: '--help' takes precedence over error reporting */
|
2020-06-01 23:30:33 +08:00
|
|
|
if ((argc < 2 && !allowEmptyExec) || ((struct arg_lit *)(ctx->argtable)[0])->count > 0) { // help must be the first record
|
|
|
|
printf("Usage: %s", ctx->programName);
|
|
|
|
arg_print_syntaxv(stdout, ctx->argtable, "\n");
|
|
|
|
if (ctx->programHint)
|
|
|
|
printf("%s\n\n", ctx->programHint);
|
|
|
|
arg_print_glossary(stdout, ctx->argtable, " %-20s %s\n");
|
2019-03-10 06:35:06 +08:00
|
|
|
printf("\n");
|
2020-06-01 23:30:33 +08:00
|
|
|
if (ctx->programHelp)
|
|
|
|
printf("%s \n", ctx->programHelp);
|
2019-03-10 06:35:06 +08:00
|
|
|
|
2020-04-12 02:41:05 +08:00
|
|
|
fflush(stdout);
|
2019-03-10 06:35:06 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the parser returned any errors then display them and exit */
|
|
|
|
if (nerrors > 0) {
|
|
|
|
/* Display the error details contained in the arg_end struct.*/
|
2020-06-01 23:30:33 +08:00
|
|
|
arg_print_errors(stdout, ((struct arg_end *)(ctx->argtable)[vargtableLen - 1]), ctx->programName);
|
|
|
|
printf("Try '%s --help' for more information.\n", ctx->programName);
|
2020-04-12 02:41:05 +08:00
|
|
|
fflush(stdout);
|
2019-03-10 06:35:06 +08:00
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2018-10-11 16:48:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
enum ParserState {
|
2019-03-10 06:35:06 +08:00
|
|
|
PS_FIRST,
|
|
|
|
PS_ARGUMENT,
|
|
|
|
PS_OPTION,
|
2018-10-11 16:48:46 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define isSpace(c)(c == ' ' || c == '\t')
|
|
|
|
|
2020-06-01 23:30:33 +08:00
|
|
|
int CLIParserParseString(CLIParserContext *ctx, const char *str, void *vargtable[], size_t vargtableLen, bool allowEmptyExec) {
|
|
|
|
return CLIParserParseStringEx(ctx, str, vargtable, vargtableLen, allowEmptyExec, false);
|
2018-10-11 16:48:46 +08:00
|
|
|
}
|
|
|
|
|
2020-06-01 23:30:33 +08:00
|
|
|
int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtable[], size_t vargtableLen, bool allowEmptyExec, bool clueData) {
|
2019-03-10 06:35:06 +08:00
|
|
|
int argc = 0;
|
|
|
|
char *argv[200] = {NULL};
|
|
|
|
|
|
|
|
int len = strlen(str);
|
2020-06-01 23:30:33 +08:00
|
|
|
char buf[500] = {0};
|
|
|
|
memset(ctx->buf, 0x00, 500);
|
2019-03-10 06:35:06 +08:00
|
|
|
char *bufptr = buf;
|
|
|
|
char *spaceptr = NULL;
|
|
|
|
enum ParserState state = PS_FIRST;
|
|
|
|
|
|
|
|
argv[argc++] = bufptr;
|
|
|
|
// param0 = program name
|
2020-06-01 23:30:33 +08:00
|
|
|
memcpy(buf, ctx->programName, strlen(ctx->programName) + 1); // with 0x00
|
|
|
|
bufptr += strlen(ctx->programName) + 1;
|
2019-03-10 06:35:06 +08:00
|
|
|
if (len)
|
|
|
|
argv[argc++] = bufptr;
|
|
|
|
|
|
|
|
// parse params
|
|
|
|
for (int i = 0; i < len; i++) {
|
2019-03-10 07:00:59 +08:00
|
|
|
switch (state) {
|
2019-03-10 06:35:06 +08:00
|
|
|
case PS_FIRST: // first char
|
2019-03-10 07:00:59 +08:00
|
|
|
if (!clueData || str[i] == '-') { // first char before space is '-' - next element - option OR not "clueData" for not-option fields
|
2019-03-10 06:35:06 +08:00
|
|
|
state = PS_OPTION;
|
|
|
|
|
|
|
|
if (spaceptr) {
|
|
|
|
bufptr = spaceptr;
|
|
|
|
*bufptr = 0x00;
|
|
|
|
bufptr++;
|
|
|
|
argv[argc++] = bufptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spaceptr = NULL;
|
|
|
|
case PS_ARGUMENT:
|
|
|
|
if (state == PS_FIRST)
|
|
|
|
state = PS_ARGUMENT;
|
|
|
|
if (isSpace(str[i])) {
|
|
|
|
spaceptr = bufptr;
|
|
|
|
state = PS_FIRST;
|
|
|
|
}
|
|
|
|
*bufptr = str[i];
|
|
|
|
bufptr++;
|
|
|
|
break;
|
|
|
|
case PS_OPTION:
|
2019-03-10 07:00:59 +08:00
|
|
|
if (isSpace(str[i])) {
|
2019-03-10 06:35:06 +08:00
|
|
|
state = PS_FIRST;
|
|
|
|
|
|
|
|
*bufptr = 0x00;
|
|
|
|
bufptr++;
|
|
|
|
argv[argc++] = bufptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*bufptr = str[i];
|
|
|
|
bufptr++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-01 23:30:33 +08:00
|
|
|
return CLIParserParseArg(ctx, argc, argv, vargtable, vargtableLen, allowEmptyExec);
|
2018-10-11 16:48:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// convertors
|
2019-03-10 18:20:22 +08:00
|
|
|
int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
|
2019-03-10 06:35:06 +08:00
|
|
|
*datalen = 0;
|
|
|
|
|
|
|
|
int ibuf = 0;
|
2019-04-07 18:30:25 +08:00
|
|
|
uint8_t tmp_buf[256] = {0};
|
|
|
|
int res = CLIParamStrToBuf(argstr, tmp_buf, maxdatalen * 2, &ibuf); // *2 because here HEX
|
2020-04-13 03:23:52 +08:00
|
|
|
if (res) {
|
2020-04-12 02:41:05 +08:00
|
|
|
printf("Parameter error: buffer overflow.\n");
|
|
|
|
fflush(stdout);
|
2019-03-10 06:35:06 +08:00
|
|
|
return res;
|
2020-04-12 02:41:05 +08:00
|
|
|
}
|
2020-04-13 03:23:52 +08:00
|
|
|
if (ibuf == 0) {
|
|
|
|
return res;
|
|
|
|
}
|
2020-04-16 15:01:14 +08:00
|
|
|
|
2019-04-07 18:30:25 +08:00
|
|
|
switch (param_gethex_to_eol((char *)tmp_buf, 0, data, maxdatalen, datalen)) {
|
2019-03-10 07:00:59 +08:00
|
|
|
case 1:
|
|
|
|
printf("Parameter error: Invalid HEX value.\n");
|
2020-04-12 02:41:05 +08:00
|
|
|
fflush(stdout);
|
2019-03-10 07:00:59 +08:00
|
|
|
return 1;
|
|
|
|
case 2:
|
|
|
|
printf("Parameter error: parameter too large.\n");
|
2020-04-12 02:41:05 +08:00
|
|
|
fflush(stdout);
|
2019-03-10 07:00:59 +08:00
|
|
|
return 2;
|
|
|
|
case 3:
|
|
|
|
printf("Parameter error: Hex string must have even number of digits.\n");
|
2020-04-12 02:41:05 +08:00
|
|
|
fflush(stdout);
|
2019-03-10 07:00:59 +08:00
|
|
|
return 3;
|
2019-03-10 06:35:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2018-10-24 23:18:05 +08:00
|
|
|
}
|
|
|
|
|
2019-03-10 18:20:22 +08:00
|
|
|
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
|
2019-03-10 06:35:06 +08:00
|
|
|
*datalen = 0;
|
|
|
|
if (!argstr->count)
|
|
|
|
return 0;
|
2019-03-09 15:59:13 +08:00
|
|
|
|
2019-04-07 18:30:25 +08:00
|
|
|
uint8_t tmp_buf[256] = {0};
|
2019-03-10 06:35:06 +08:00
|
|
|
int ibuf = 0;
|
2019-03-09 15:59:13 +08:00
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
for (int i = 0; i < argstr->count; i++) {
|
|
|
|
int len = strlen(argstr->sval[i]);
|
2019-04-07 18:30:25 +08:00
|
|
|
memcpy(&tmp_buf[ibuf], argstr->sval[i], len);
|
2019-03-10 06:35:06 +08:00
|
|
|
ibuf += len;
|
|
|
|
}
|
2019-04-07 18:30:25 +08:00
|
|
|
tmp_buf[ibuf] = 0;
|
2019-03-09 15:59:13 +08:00
|
|
|
|
2019-03-10 06:35:06 +08:00
|
|
|
if (!ibuf)
|
|
|
|
return 0;
|
2018-10-24 23:18:05 +08:00
|
|
|
|
2020-04-13 03:23:52 +08:00
|
|
|
if (ibuf > maxdatalen) {
|
|
|
|
fflush(stdout);
|
2019-03-10 06:35:06 +08:00
|
|
|
return 2;
|
2020-04-13 03:23:52 +08:00
|
|
|
}
|
2019-03-09 15:59:13 +08:00
|
|
|
|
2019-04-07 18:30:25 +08:00
|
|
|
memcpy(data, tmp_buf, ibuf);
|
2019-03-10 06:35:06 +08:00
|
|
|
*datalen = ibuf;
|
|
|
|
return 0;
|
2018-10-11 16:48:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|