diff --git a/.gitignore b/.gitignore index 17b2ab5..4d9cd93 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,8 @@ cmake_install.cmake CMakeCache.txt demo/x86-gcc/Makefile demo/x86-gcc/LetterShell +demo/x86-gcc/LetterShell.map +demo/x86-gcc/compile_commands.json +demo/x86-gcc/.cache/ .vscode build \ No newline at end of file diff --git a/demo/x86-gcc/shell_port.c b/demo/x86-gcc/shell_port.c index 449ef81..2f65957 100644 --- a/demo/x86-gcc/shell_port.c +++ b/demo/x86-gcc/shell_port.c @@ -274,10 +274,39 @@ void systemPassthrough(char *data, unsigned short len) SHELL_EXPORT_PASSTROUGH(SHELL_CMD_PERMISSION(0), system, system>>\x20, systemPassthrough, passthrough for system command); #if SHELL_USING_FUNC_SIGNATURE == 1 + void shellFuncSignatureTest(int a, char *b, char c) { printf("a = %d, b = %s, c = %c\r\n", a, b, c); } -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), -funcSignatureTest, shellFuncSignatureTest, test function signature, .data.cmd.signature = "isc"); -#endif +SHELL_EXPORT_CMD_SIGN(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), +funcSignatureTest, shellFuncSignatureTest, test function signature, isc); + +typedef struct { + int a; + char *b; +} TestStruct; + +int testStructParser(char *string, void **param) +{ + TestStruct *data = malloc(sizeof(TestStruct)); + data->b = malloc(16); + if (sscanf(string, "%d %s", &(data->a), data->b) == 2) + { + *param = (void *)data; + return 0; + } + return -1; +} +SHELL_EXPORT_PARAM_PARSER(0, LTestStruct;, testStructParser); + +void shellParamParserTest(int a, TestStruct *data, char *c) +{ + printf("a = %d, data->a = %d, data->b = %s, c = %s\r\n", a, data->a, data->b, c); + free(data->b); + free(data); +} +SHELL_EXPORT_CMD_SIGN(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), +paramParserTest, shellParamParserTest, test function signature and param parser, iLTestStruct;s); + +#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */ diff --git a/extensions/cpp_support/shell_cpp.h b/extensions/cpp_support/shell_cpp.h index 50e3ea0..88ae02f 100644 --- a/extensions/cpp_support/shell_cpp.h +++ b/extensions/cpp_support/shell_cpp.h @@ -84,6 +84,19 @@ typedef struct shell_command_cpp_key #endif } ShellCommandCppKey; +#if SHELL_USING_FUNC_SIGNATURE == 1 +typedef struct shell_command_cpp_param_parser +{ + int attr; /**< 属性 */ + const char *type; /**< 参数类型 */ + int (*function)(char *, void **);; /**< 解析函数 */ + void *unsed[2]; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */ +#if SHELL_COMMAND_FILL_BYTES != 0 + char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */ +#endif +} ShellCommandCppParamParser; +#endif + #if SHELL_USING_CMD_EXPORT == 1 #undef SHELL_EXPORT_CMD @@ -171,11 +184,28 @@ typedef struct shell_command_cpp_key (void (*)(Shell *))_func, \ shellDesc##_value \ } + +#if SHELL_USING_FUNC_SIGNATURE == 1 + /** + * @brief shell 参数解析器定义 + * + * @param _attr 参数解析器属性 + * @param _type 参数解析器类型 + * @param _func 参数解析器函数 + */ + #define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _func) \ + const char shellDesc##_func[] = #_type; \ + extern "C" SHELL_USED const ShellCommandCppParamParser \ + shellCommand##_func SHELL_SECTION("shellCommand") = \ + { \ + _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \ + shellDesc##_func, \ + (int (*)(char *, void **))_func \ + } +#endif #endif /** SHELL_USING_CMD_EXPORT == 1 */ } #endif /**< defined __cplusplus */ #endif /**< __SHELL_CPP_H__ */ - - diff --git a/src/shell.c b/src/shell.c index 09b9d2b..ddb10bb 100644 --- a/src/shell.c +++ b/src/shell.c @@ -573,6 +573,12 @@ static const char* shellGetCommandName(ShellCommand *command) { return command->data.user.name; } +#if SHELL_USING_FUNC_SIGNATURE == 1 + else if (command->attr.attrs.type == SHELL_TYPE_PARAM_PARSER) + { + return command->data.paramParser.type; + } +#endif else { shellToHex(command->data.key.value, buffer); @@ -1957,7 +1963,13 @@ int shellExecute(int argc, char *argv[]) Shell *shell = shellGetCurrent(); if (shell && argc >= 2) { - int (*func)() = (int (*)())shellExtParsePara(shell, argv[1], NULL); + unsigned result; + if (shellExtParsePara(shell, argv[1], NULL, &result) != 0) + { + shellWriteString(shell, shellText[SHELL_TEXT_PARAM_ERROR]); + return -1; + } + int (*func)() = (int (*)())result; ShellCommand command = { .attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) |SHELL_CMD_DISABLE_RETURN, diff --git a/src/shell.h b/src/shell.h index ca2aed6..1512c94 100644 --- a/src/shell.h +++ b/src/shell.h @@ -143,6 +143,31 @@ ##__VA_ARGS__ \ } +#if SHELL_USING_FUNC_SIGNATURE == 1 + /** + * @brief shell 命令定义 + * + * @param _attr 命令属性 + * @param _name 命令名 + * @param _func 命令函数 + * @param _desc 命令描述 + * @param _sign 命令签名 + */ + #define SHELL_EXPORT_CMD_SIGN(_attr, _name, _func, _desc, _sign) \ + const char shellCmd##_name[] = #_name; \ + const char shellDesc##_name[] = #_desc; \ + const char shellSign##_name[] = #_sign; \ + SHELL_USED const ShellCommand \ + shellCommand##_name SHELL_SECTION("shellCommand") = \ + { \ + .attr.value = _attr, \ + .data.cmd.name = shellCmd##_name, \ + .data.cmd.function = (int (*)())_func, \ + .data.cmd.desc = shellDesc##_name, \ + .data.cmd.signature = shellSign##_name \ + } +#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */ + /** * @brief shell 代理命令定义 * @@ -228,6 +253,26 @@ #define SHELL_EXPORT_KEY_AGENCY(_attr, _value, _func, _desc, ...) \ SHELL_AGENCY_FUNC(_func, ##__VA_ARGS__) \ SHELL_EXPORT_KEY(_attr, _value, SHELL_AGENCY_FUNC_NAME(_func), _desc) + +#if SHELL_USING_FUNC_SIGNATURE == 1 + /** + * @brief shell 参数解析器定义 + * + * @param _attr 参数解析器属性 + * @param _type 参数解析器类型 + * @param _func 参数解析器函数 + */ + #define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _func) \ + const char shellDesc##_func[] = #_type; \ + SHELL_USED const ShellCommand \ + shellCommand##_func SHELL_SECTION("shellCommand") = \ + { \ + .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \ + .data.paramParser.type = shellDesc##_func, \ + .data.paramParser.function = (int (*)(char *, void **))_func \ + } +#endif + #else /** * @brief shell 命令item定义 @@ -293,12 +338,31 @@ .data.key.desc = #_desc \ } +#if SHELL_USING_FUNC_SIGNATURE == 1 + /** + * @brief shell 参数解析器item定义 + * + * @param _attr 参数解析器属性 + * @param _type 参数解析器类型 + * @param _func 参数解析器函数 + */ + #define SHELL_PARAM_PARSER_ITEM(_attr, _type, _func) \ + { \ + .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \ + .data.paramParser.type = #_type, \ + .data.paramParser.function = (int (*)(char *, void **))_func \ + } +#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */ + #define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) #define SHELL_EXPORT_CMD_AGENCY(_attr, _name, _func, _desc, ...) #define SHELL_EXPORT_VAR(_attr, _name, _value, _desc) #define SHELL_EXPORT_USER(_attr, _name, _password, _desc) #define SHELL_EXPORT_KEY(_attr, _value, _func, _desc) #define SHELL_EXPORT_KEY_AGENCY(_attr, _name, _func, _desc, ...) +#if SHELL_USING_FUNC_SIGNATURE == 1 + #define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _func) +#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */ #endif /** SHELL_USING_CMD_EXPORT == 1 */ /** @@ -316,6 +380,9 @@ typedef enum SHELL_TYPE_VAR_NODE, /**< 节点变量 */ SHELL_TYPE_USER, /**< 用户 */ SHELL_TYPE_KEY, /**< 按键 */ +#if SHELL_USING_FUNC_SIGNATURE == 1 + SHELL_TYPE_PARAM_PARSER, /**< 参数解析器 */ +#endif } ShellCommandType; @@ -410,28 +477,26 @@ typedef struct shell_command const char *name; /**< 变量名 */ void *value; /**< 变量值 */ const char *desc; /**< 变量描述 */ - #if SHELL_USING_FUNC_SIGNATURE == 1 - const char *unsued; /**< 未使用成员 */ - #endif } var; /**< 变量定义 */ struct { const char *name; /**< 用户名 */ const char *password; /**< 用户密码 */ const char *desc; /**< 用户描述 */ - #if SHELL_USING_FUNC_SIGNATURE == 1 - const char *unsued; /**< 未使用成员 */ - #endif } user; /**< 用户定义 */ struct { int value; /**< 按键键值 */ void (*function)(Shell *); /**< 按键执行函数 */ const char *desc; /**< 按键描述 */ - #if SHELL_USING_FUNC_SIGNATURE == 1 - const char *unsued; /**< 未使用成员 */ - #endif } key; /**< 按键定义 */ +#if SHELL_USING_FUNC_SIGNATURE == 1 + struct + { + const char *type; /**< 参数类型 */ + int (*function)(char *, void **); /**< 解析函数 */ + } paramParser; /**< 参数解析器 */ +#endif } data; #if SHELL_COMMAND_FILL_BYTES != 0 char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */ @@ -485,5 +550,3 @@ void *shellCompanionGet(Shell *shell, int id); #endif #endif - - diff --git a/src/shell_ext.c b/src/shell_ext.c index 5e5dc3f..8876532 100644 --- a/src/shell_ext.c +++ b/src/shell_ext.c @@ -30,9 +30,9 @@ extern int shellGetVarValue(Shell *shell, ShellCommand *command); * * @return int 下一个参数在签名中的索引 */ -static int shellGetNextArgType(const char *signature, int index, char *type) +static int shellGetNextParamType(const char *signature, int index, char *type) { - char *p = signature + index; + const char *p = signature + index; if (*p == 'L') { while (*p != ';' && *p != 0) @@ -40,8 +40,10 @@ static int shellGetNextArgType(const char *signature, int index, char *type) *type++ = *p++; index++; } + *type++ = *p++; + index++; } - else + else if (*p != 0) { *type++ = *p; index++; @@ -49,6 +51,31 @@ static int shellGetNextArgType(const char *signature, int index, char *type) *type = '\0'; return index; } + + +static int shellGetParamNumExcept(const char *signature) +{ + int num = 0; + const char *p = signature; + + while (*p) + { + if (*p == 'L') + { + while (*p != ';' && *p != 0) + { + p++; + } + p++; + } + else + { + p++; + } + num++; + } + return num; +} #endif /** @@ -297,47 +324,88 @@ static unsigned int shellExtParseVar(Shell *shell, char *var) * * @param shell shell对象 * @param string 参数 - * @return unsigned int 解析结果 + * @param result 解析结果 + * + * @return int 0 解析成功 --1 解析失败 */ -unsigned int shellExtParsePara(Shell *shell, char *string, char *type) +int shellExtParsePara(Shell *shell, char *string, char *type, unsigned int *result) { if (type == NULL || (*string == '$' && *(string + 1))) { if (*string == '\'' && *(string + 1)) { - return (unsigned int)shellExtParseChar(string); + *result = (unsigned int)shellExtParseChar(string); + return 0; } else if (*string == '-' || (*string >= '0' && *string <= '9')) { - return (unsigned int)shellExtParseNumber(string); + *result = (unsigned int)shellExtParseNumber(string); + return 0; } else if (*string == '$' && *(string + 1)) { - return shellExtParseVar(shell, string); + *result = shellExtParseVar(shell, string); + return 0; } else if (*string) { - return (unsigned int)shellExtParseString(string); + *result = (unsigned int)shellExtParseString(string); + return 0; } } +#if SHELL_USING_FUNC_SIGNATURE == 1 else { if (strcmp("c", type) == 0) { - return (unsigned int)shellExtParseChar(string); + *result = (unsigned int)shellExtParseChar(string); + return 0; } else if (strcmp("i", type) == 0 || strcmp("f", type) == 0 || strcmp("p", type) == 0) { - return (unsigned int)shellExtParseNumber(string); + *result = (unsigned int)shellExtParseNumber(string); + return 0; } else if (strcmp("s", type) == 0) { - return (unsigned int)shellExtParseString(string); + *result = (unsigned int)shellExtParseString(string); + return 0; + } + else + { + ShellCommand *command = shellSeekCommand(shell, + type, + shell->commandList.base, + 0); + if (command != NULL) + { + void *param; + if (command->data.paramParser.function(shellExtParseString(string), ¶m) == 0) + { + *result = (unsigned int)param; + return 0; + } + else + { + shellWriteString(shell, "Parse param for type: "); + shellWriteString(shell, type); + shellWriteString(shell, " failed\r\n"); + return -1; + } + } + else + { + shellWriteString(shell, "Can't find the param parser for type: "); + shellWriteString(shell, type); + shellWriteString(shell, "\r\n"); + return -1; + } } } - return 0; +#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */ + return -1; } @@ -356,23 +424,38 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[]) int paramNum = command->attr.attrs.paramNum > (argc - 1) ? command->attr.attrs.paramNum : (argc - 1); #if SHELL_USING_FUNC_SIGNATURE == 1 - char type[8]; + char type[16]; int index = 0; + + if (command->data.cmd.signature != NULL) + { + int except = shellGetParamNumExcept(command->data.cmd.signature); + if (except != argc - 1) + { + shellWriteString(shell, "Parameters number incorrect\r\n"); + shellPrint(shell, "except: %d, actual: %d\r\n", except, argc - 1); + return -1; + } + } #endif for (int i = 0; i < argc - 1; i++) { #if SHELL_USING_FUNC_SIGNATURE == 1 if (command->data.cmd.signature != NULL) { - index = shellGetNextArgType(command->data.cmd.signature, index, type); - params[i] = shellExtParsePara(shell, argv[i + 1], type); + index = shellGetNextParamType(command->data.cmd.signature, index, type); + if (shellExtParsePara(shell, argv[i + 1], type, ¶ms[i]) != 0) + { + return -1; + } } else + #endif /** SHELL_USING_FUNC_SIGNATURE == 1 */ { - params[i] = shellExtParsePara(shell, argv[i + 1], NULL); + if (shellExtParsePara(shell, argv[i + 1], NULL, ¶ms[i]) != 0) + { + return -1; + } } - #else - params[i] = shellExtParsePara(shell, argv[i + 1], NULL); - #endif } switch (paramNum) { diff --git a/src/shell_ext.h b/src/shell_ext.h index 200078e..dadf56d 100644 --- a/src/shell_ext.h +++ b/src/shell_ext.h @@ -27,7 +27,7 @@ typedef enum NUM_TYPE_FLOAT /**< 浮点型 */ } ShellNumType; -unsigned int shellExtParsePara(Shell *shell, char *string, char *type); +int shellExtParsePara(Shell *shell, char *string, char *type, unsigned int *result); int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[]); #endif