1
0
mirror of https://github.com/NevermindZZT/letter-shell.git synced 2025-01-01 09:58:41 +08:00

新增 自定义类型解析

- 可以对自定义的数据结构定义解析器,然后使用函数签名进行参数自动解析
This commit is contained in:
Letter 2023-04-22 07:50:25 +00:00
parent 99b5e6d386
commit e9375840bd
5 changed files with 171 additions and 59 deletions

View File

@ -26,6 +26,7 @@
- [命令属性字段说明](#命令属性字段说明) - [命令属性字段说明](#命令属性字段说明)
- [代理函数和代理参数解析](#代理函数和代理参数解析) - [代理函数和代理参数解析](#代理函数和代理参数解析)
- [函数签名](#函数签名) - [函数签名](#函数签名)
- [自定义类型解析](#自定义类型解析)
- [权限系统说明](#权限系统说明) - [权限系统说明](#权限系统说明)
- [锁说明](#锁说明) - [锁说明](#锁说明)
- [伴生对象](#伴生对象) - [伴生对象](#伴生对象)
@ -496,7 +497,7 @@ letter shell 3.2.x 之后,引入了函数签名的概念,以便于参数自
由此,借鉴 Java 等语言的函数签名新版也引入了函数签名的概念在声明命令时可以给定最终执行命令的函数的签名shell 根据这个签名进行参数转换,使用此功能时,需要打开宏 `SHELL_USING_FUNC_SIGNATURE` 由此,借鉴 Java 等语言的函数签名新版也引入了函数签名的概念在声明命令时可以给定最终执行命令的函数的签名shell 根据这个签名进行参数转换,使用此功能时,需要打开宏 `SHELL_USING_FUNC_SIGNATURE`
函数签名是一个字符串,通过这个字符串声明表达函数的参数类型,返回值不声明,比如一个函数`int func(int a, char *b, char c)`,它的函数签名就是 `ics` 函数签名是一个字符串,通过这个字符串声明表达函数的参数类型,返回值不声明,比如一个函数`int func(int a, char *b, char c)`,它的函数签名就是 `isc`
基本类型的参数签名定义如下: 基本类型的参数签名定义如下:
@ -507,7 +508,7 @@ letter shell 3.2.x 之后,引入了函数签名的概念,以便于参数自
| char * (字符串) | s | | char * (字符串) | s |
| pointer | p | | pointer | p |
声明命令时,在最后添加一个参数 `.data.cmd.signature = "ics"` 即可,比如: 声明命令时,在最后添加一个参数 `.data.cmd.signature = "isc"` 即可,比如:
```c ```c
void shellFuncSignatureTest(int a, char *b, char c) void shellFuncSignatureTest(int a, char *b, char c)
@ -518,6 +519,55 @@ SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
funcSignatureTest, shellFuncSignatureTest, test function signature, .data.cmd.signature = "isc"); funcSignatureTest, shellFuncSignatureTest, test function signature, .data.cmd.signature = "isc");
``` ```
### 自定义类型解析
由于函数签名的引用,我们就可以使用函数签名描述任何参数,对应的,在参数类型已知的情况下,也可以定义对应的参数解析器进行参数解析,自定义的参数类型签名需要以 `L` 开头,以 `;` 结尾,比如说定义一个 `TestStruct` 结构体类型为 `LTestStruct;`,那么接收这个结构体为参数的函数就可以通过这个类型签名定义函数签名,并导出命令
```c
typedef struct {
int a;
char *b;
} TestStruct;
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);
}
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);
```
同时,我们需要对自定义的类型定义解析器,使用 `SHELL_EXPORT_PARAM_PARSER`
```c
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;
}
int testStructClener(void *param)
{
TestStruct *data = (TestStruct *)param;
free(data->b);
free(data);
return 0;
}
SHELL_EXPORT_PARAM_PARSER(0, LTestStruct;, testStructParser, testStructClener);
```
`SHELL_EXPORT_PARAM_PARSER` 接收四个参数,第一个参数表示属性,这里一般填 0 皆可,第二个参数就是解析器对应的类型签名,第三个参数是解析器函数,第四个参数是清理函数,清理函数在参数解析失败或者命令执行完毕后会被调用,一般用于清理解析器分配的内存,如果不需要清理函数,填 `NULL` 即可
解析器函数接收两个参数,第一个参数是输入的字符串,也就是命令行输入的参数,第二个参数是解析后的参数,解析成功后,需要将解析后的参数赋值给第二个参数,解析成功返回 0解析失败返回 -1
清理函数接收一个参数,就是解析器函数解析得到的结果
## 权限系统说明 ## 权限系统说明
letter shell 3.x的权限管理同用户定义紧密相关letter shell 3.x使用8个bit位表示命令权限当用户和命令的权限按位与为真或者命令权限为0时表示该用户拥有此命令的权限可以调用该命令 letter shell 3.x的权限管理同用户定义紧密相关letter shell 3.x使用8个bit位表示命令权限当用户和命令的权限按位与为真或者命令权限为0时表示该用户拥有此命令的权限可以调用该命令

View File

@ -298,13 +298,19 @@ int testStructParser(char *string, void **param)
} }
return -1; return -1;
} }
SHELL_EXPORT_PARAM_PARSER(0, LTestStruct;, testStructParser);
int testStructClener(void *param)
{
TestStruct *data = (TestStruct *)param;
free(data->b);
free(data);
return 0;
}
SHELL_EXPORT_PARAM_PARSER(0, LTestStruct;, testStructParser, testStructClener);
void shellParamParserTest(int a, TestStruct *data, char *c) 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); 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), 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); paramParserTest, shellParamParserTest, test function signature and param parser, iLTestStruct;s);

View File

@ -89,8 +89,9 @@ typedef struct shell_command_cpp_param_parser
{ {
int attr; /**< 属性 */ int attr; /**< 属性 */
const char *type; /**< 参数类型 */ const char *type; /**< 参数类型 */
int (*function)(char *, void **);; /**< 解析函数 */ int (*parser)(char *, void **);; /**< 解析函数 */
void *unsed[2]; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */ int (*cleaner)(void *); /**< 清理函数 */
void *unsed; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */
#if SHELL_COMMAND_FILL_BYTES != 0 #if SHELL_COMMAND_FILL_BYTES != 0
char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */ char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */
#endif #endif
@ -186,21 +187,24 @@ typedef struct shell_command_cpp_param_parser
} }
#if SHELL_USING_FUNC_SIGNATURE == 1 #if SHELL_USING_FUNC_SIGNATURE == 1
#undef SHELL_EXPORT_PARAM_PARSER
/** /**
* @brief shell * @brief shell
* *
* @param _attr * @param _attr
* @param _type * @param _type
* @param _func * @param _parser
* @param _cleaner
*/ */
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _func) \ #define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _parser, _cleaner) \
const char shellDesc##_func[] = #_type; \ const char shellDesc##_parser[] = #_type; \
extern "C" SHELL_USED const ShellCommandCppParamParser \ extern "C" SHELL_USED const ShellCommandCppParamParser \
shellCommand##_func SHELL_SECTION("shellCommand") = \ shellCommand##_parser SHELL_SECTION("shellCommand") = \
{ \ { \
_attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \ _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \
shellDesc##_func, \ shellDesc##_parser, \
(int (*)(char *, void **))_func \ (int (*)(char *, void **))_parser, \
(int (*)(void *))_cleaner \
} }
#endif #endif
#endif /** SHELL_USING_CMD_EXPORT == 1 */ #endif /** SHELL_USING_CMD_EXPORT == 1 */

View File

@ -260,16 +260,18 @@
* *
* @param _attr * @param _attr
* @param _type * @param _type
* @param _func * @param _parser
* @param _cleaner
*/ */
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _func) \ #define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _parser, _cleaner) \
const char shellDesc##_func[] = #_type; \ const char shellDesc##_parser[] = #_type; \
SHELL_USED const ShellCommand \ SHELL_USED const ShellCommand \
shellCommand##_func SHELL_SECTION("shellCommand") = \ shellCommand##_parser SHELL_SECTION("shellCommand") = \
{ \ { \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \ .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \
.data.paramParser.type = shellDesc##_func, \ .data.paramParser.type = shellDesc##_parser, \
.data.paramParser.function = (int (*)(char *, void **))_func \ .data.paramParser.parser = (int (*)(char *, void **))_parser, \
.data.paramParser.cleaner = (int (*)(void *))_cleaner \
} }
#endif #endif
@ -344,13 +346,15 @@
* *
* @param _attr * @param _attr
* @param _type * @param _type
* @param _func * @param _parser
* @param _cleaner
*/ */
#define SHELL_PARAM_PARSER_ITEM(_attr, _type, _func) \ #define SHELL_PARAM_PARSER_ITEM(_attr, _type, _parser, _cleaner) \
{ \ { \
.attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \ .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \
.data.paramParser.type = #_type, \ .data.paramParser.type = #_type, \
.data.paramParser.function = (int (*)(char *, void **))_func \ .data.paramParser.parser = (int (*)(char *, void **))_parser, \
.data.paramParser.cleaner = (int (*)(void *))_cleaner \
} }
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */ #endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
@ -494,7 +498,8 @@ typedef struct shell_command
struct struct
{ {
const char *type; /**< 参数类型 */ const char *type; /**< 参数类型 */
int (*function)(char *, void **); /**< 解析函数 */ int (*parser)(char *, void **); /**< 解析函数 */
int (*cleaner)(void *); /**< 清理器 */
} paramParser; /**< 参数解析器 */ } paramParser; /**< 参数解析器 */
#endif #endif
} data; } data;

View File

@ -382,7 +382,7 @@ int shellExtParsePara(Shell *shell, char *string, char *type, unsigned int *resu
if (command != NULL) if (command != NULL)
{ {
void *param; void *param;
if (command->data.paramParser.function(shellExtParseString(string), &param) == 0) if (command->data.paramParser.parser(shellExtParseString(string), &param) == 0)
{ {
*result = (unsigned int)param; *result = (unsigned int)param;
return 0; return 0;
@ -409,6 +409,40 @@ int shellExtParsePara(Shell *shell, char *string, char *type, unsigned int *resu
} }
#if SHELL_USING_FUNC_SIGNATURE == 1
int shellExtCleanerPara(Shell *shell, char *type, unsigned int param)
{
if (type == NULL)
{
return 0;
}
else
{
if (strcmp("c", type) == 0
|| strcmp("i", type) == 0
|| strcmp("f", type) == 0
|| strcmp("p", type) == 0
|| strcmp("s", type) == 0)
{
return 0;
}
else
{
ShellCommand *command = shellSeekCommand(shell,
type,
shell->commandList.base,
0);
if (command != NULL && command->data.paramParser.cleaner != NULL)
{
return command->data.paramParser.cleaner((void *)param);
}
}
}
return -1;
}
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
/** /**
* @brief * @brief
* *
@ -426,6 +460,7 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
#if SHELL_USING_FUNC_SIGNATURE == 1 #if SHELL_USING_FUNC_SIGNATURE == 1
char type[16]; char type[16];
int index = 0; int index = 0;
int ret = 0;
if (command->data.cmd.signature != NULL) if (command->data.cmd.signature != NULL)
{ {
@ -433,7 +468,6 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
if (except != argc - 1) if (except != argc - 1)
{ {
shellWriteString(shell, "Parameters number incorrect\r\n"); shellWriteString(shell, "Parameters number incorrect\r\n");
shellPrint(shell, "except: %d, actual: %d\r\n", except, argc - 1);
return -1; return -1;
} }
} }
@ -461,124 +495,124 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
{ {
#if SHELL_PARAMETER_MAX_NUMBER >= 1 #if SHELL_PARAMETER_MAX_NUMBER >= 1
case 0: case 0:
return command->data.cmd.function(); ret = command->data.cmd.function();
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 1 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 1 */
#if SHELL_PARAMETER_MAX_NUMBER >= 2 #if SHELL_PARAMETER_MAX_NUMBER >= 2
case 1: case 1:
return command->data.cmd.function(params[0]); ret = command->data.cmd.function(params[0]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 2 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 2 */
#if SHELL_PARAMETER_MAX_NUMBER >= 3 #if SHELL_PARAMETER_MAX_NUMBER >= 3
case 2: case 2:
return command->data.cmd.function(params[0], params[1]); ret = command->data.cmd.function(params[0], params[1]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 3 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 3 */
#if SHELL_PARAMETER_MAX_NUMBER >= 4 #if SHELL_PARAMETER_MAX_NUMBER >= 4
case 3: case 3:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2]); params[2]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 4 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 4 */
#if SHELL_PARAMETER_MAX_NUMBER >= 5 #if SHELL_PARAMETER_MAX_NUMBER >= 5
case 4: case 4:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3]); params[2], params[3]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 5 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 5 */
#if SHELL_PARAMETER_MAX_NUMBER >= 6 #if SHELL_PARAMETER_MAX_NUMBER >= 6
case 5: case 5:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4]); params[4]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 6 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 6 */
#if SHELL_PARAMETER_MAX_NUMBER >= 7 #if SHELL_PARAMETER_MAX_NUMBER >= 7
case 6: case 6:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5]); params[4], params[5]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 7 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 7 */
#if SHELL_PARAMETER_MAX_NUMBER >= 8 #if SHELL_PARAMETER_MAX_NUMBER >= 8
case 7: case 7:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6]); params[6]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 8 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 8 */
#if SHELL_PARAMETER_MAX_NUMBER >= 9 #if SHELL_PARAMETER_MAX_NUMBER >= 9
case 8: case 8:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7]); params[6], params[7]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 9 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 9 */
#if SHELL_PARAMETER_MAX_NUMBER >= 10 #if SHELL_PARAMETER_MAX_NUMBER >= 10
case 9: case 9:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7], params[6], params[7],
params[8]); params[8]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 10 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 10 */
#if SHELL_PARAMETER_MAX_NUMBER >= 11 #if SHELL_PARAMETER_MAX_NUMBER >= 11
case 10: case 10:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7], params[6], params[7],
params[8], params[9]); params[8], params[9]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 11 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 11 */
#if SHELL_PARAMETER_MAX_NUMBER >= 12 #if SHELL_PARAMETER_MAX_NUMBER >= 12
case 11: case 11:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7], params[6], params[7],
params[8], params[9], params[8], params[9],
params[10]); params[10]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 12 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 12 */
#if SHELL_PARAMETER_MAX_NUMBER >= 13 #if SHELL_PARAMETER_MAX_NUMBER >= 13
case 12: case 12:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7], params[6], params[7],
params[8], params[9], params[8], params[9],
params[10], params[11]); params[10], params[11]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 13 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 13 */
#if SHELL_PARAMETER_MAX_NUMBER >= 14 #if SHELL_PARAMETER_MAX_NUMBER >= 14
case 13: case 13:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7], params[6], params[7],
params[8], params[9], params[8], params[9],
params[10], params[11], params[10], params[11],
params[12]); params[12]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 14 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 14 */
#if SHELL_PARAMETER_MAX_NUMBER >= 15 #if SHELL_PARAMETER_MAX_NUMBER >= 15
case 14: case 14:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7], params[6], params[7],
params[8], params[9], params[8], params[9],
params[10], params[11], params[10], params[11],
params[12], params[13]); params[12], params[13]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 15 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 15 */
#if SHELL_PARAMETER_MAX_NUMBER >= 16 #if SHELL_PARAMETER_MAX_NUMBER >= 16
case 15: case 15:
return command->data.cmd.function(params[0], params[1], ret = command->data.cmd.function(params[0], params[1],
params[2], params[3], params[2], params[3],
params[4], params[5], params[4], params[5],
params[6], params[7], params[6], params[7],
@ -586,11 +620,24 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
params[10], params[11], params[10], params[11],
params[12], params[13], params[12], params[13],
params[14]); params[14]);
// break; break;
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 16 */ #endif /** SHELL_PARAMETER_MAX_NUMBER >= 16 */
default: default:
return -1; ret = -1;
// break; break;
} }
#if SHELL_USING_FUNC_SIGNATURE == 1
if (command->data.cmd.signature != NULL) {
index = 0;
for (int i = 0; i < argc - 1; i++)
{
index = shellGetNextParamType(command->data.cmd.signature, index, type);
shellExtCleanerPara(shell, type, params[i]);
}
}
#endif /** SHELL_USING_FUNC_SIGNATURE == 1 */
return ret;
} }