mirror of
https://github.com/NevermindZZT/letter-shell.git
synced 2025-01-01 09:58:41 +08:00
新增 自定义类型解析
- 可以对自定义的数据结构定义解析器,然后使用函数签名进行参数自动解析
This commit is contained in:
parent
99b5e6d386
commit
e9375840bd
54
README.md
54
README.md
@ -26,6 +26,7 @@
|
||||
- [命令属性字段说明](#命令属性字段说明)
|
||||
- [代理函数和代理参数解析](#代理函数和代理参数解析)
|
||||
- [函数签名](#函数签名)
|
||||
- [自定义类型解析](#自定义类型解析)
|
||||
- [权限系统说明](#权限系统说明)
|
||||
- [锁说明](#锁说明)
|
||||
- [伴生对象](#伴生对象)
|
||||
@ -496,7 +497,7 @@ letter shell 3.2.x 之后,引入了函数签名的概念,以便于参数自
|
||||
|
||||
由此,借鉴 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 |
|
||||
| pointer | p |
|
||||
|
||||
声明命令时,在最后添加一个参数 `.data.cmd.signature = "ics"` 即可,比如:
|
||||
声明命令时,在最后添加一个参数 `.data.cmd.signature = "isc"` 即可,比如:
|
||||
|
||||
```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");
|
||||
```
|
||||
|
||||
### 自定义类型解析
|
||||
|
||||
由于函数签名的引用,我们就可以使用函数签名描述任何参数,对应的,在参数类型已知的情况下,也可以定义对应的参数解析器进行参数解析,自定义的参数类型签名需要以 `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时,表示该用户拥有此命令的权限,可以调用该命令
|
||||
|
@ -298,13 +298,19 @@ int testStructParser(char *string, void **param)
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
@ -89,8 +89,9 @@ typedef struct shell_command_cpp_param_parser
|
||||
{
|
||||
int attr; /**< 属性 */
|
||||
const char *type; /**< 参数类型 */
|
||||
int (*function)(char *, void **);; /**< 解析函数 */
|
||||
void *unsed[2]; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */
|
||||
int (*parser)(char *, void **);; /**< 解析函数 */
|
||||
int (*cleaner)(void *); /**< 清理函数 */
|
||||
void *unsed; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */
|
||||
#if SHELL_COMMAND_FILL_BYTES != 0
|
||||
char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */
|
||||
#endif
|
||||
@ -186,21 +187,24 @@ typedef struct shell_command_cpp_param_parser
|
||||
}
|
||||
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
#undef SHELL_EXPORT_PARAM_PARSER
|
||||
/**
|
||||
* @brief shell 参数解析器定义
|
||||
*
|
||||
* @param _attr 参数解析器属性
|
||||
* @param _type 参数解析器类型
|
||||
* @param _func 参数解析器函数
|
||||
* @param _parser 参数解析器函数
|
||||
* @param _cleaner 参数清理函数
|
||||
*/
|
||||
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _func) \
|
||||
const char shellDesc##_func[] = #_type; \
|
||||
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _parser, _cleaner) \
|
||||
const char shellDesc##_parser[] = #_type; \
|
||||
extern "C" SHELL_USED const ShellCommandCppParamParser \
|
||||
shellCommand##_func SHELL_SECTION("shellCommand") = \
|
||||
shellCommand##_parser SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
_attr|SHELL_CMD_TYPE(SHELL_TYPE_PARAM_PARSER), \
|
||||
shellDesc##_func, \
|
||||
(int (*)(char *, void **))_func \
|
||||
shellDesc##_parser, \
|
||||
(int (*)(char *, void **))_parser, \
|
||||
(int (*)(void *))_cleaner \
|
||||
}
|
||||
#endif
|
||||
#endif /** SHELL_USING_CMD_EXPORT == 1 */
|
||||
|
25
src/shell.h
25
src/shell.h
@ -260,16 +260,18 @@
|
||||
*
|
||||
* @param _attr 参数解析器属性
|
||||
* @param _type 参数解析器类型
|
||||
* @param _func 参数解析器函数
|
||||
* @param _parser 参数解析器函数
|
||||
* @param _cleaner 参数清理器
|
||||
*/
|
||||
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _func) \
|
||||
const char shellDesc##_func[] = #_type; \
|
||||
#define SHELL_EXPORT_PARAM_PARSER(_attr, _type, _parser, _cleaner) \
|
||||
const char shellDesc##_parser[] = #_type; \
|
||||
SHELL_USED const ShellCommand \
|
||||
shellCommand##_func SHELL_SECTION("shellCommand") = \
|
||||
shellCommand##_parser 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 \
|
||||
.data.paramParser.type = shellDesc##_parser, \
|
||||
.data.paramParser.parser = (int (*)(char *, void **))_parser, \
|
||||
.data.paramParser.cleaner = (int (*)(void *))_cleaner \
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -344,13 +346,15 @@
|
||||
*
|
||||
* @param _attr 参数解析器属性
|
||||
* @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), \
|
||||
.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 */
|
||||
|
||||
@ -494,7 +498,8 @@ typedef struct shell_command
|
||||
struct
|
||||
{
|
||||
const char *type; /**< 参数类型 */
|
||||
int (*function)(char *, void **); /**< 解析函数 */
|
||||
int (*parser)(char *, void **); /**< 解析函数 */
|
||||
int (*cleaner)(void *); /**< 清理器 */
|
||||
} paramParser; /**< 参数解析器 */
|
||||
#endif
|
||||
} data;
|
||||
|
119
src/shell_ext.c
119
src/shell_ext.c
@ -382,7 +382,7 @@ int shellExtParsePara(Shell *shell, char *string, char *type, unsigned int *resu
|
||||
if (command != NULL)
|
||||
{
|
||||
void *param;
|
||||
if (command->data.paramParser.function(shellExtParseString(string), ¶m) == 0)
|
||||
if (command->data.paramParser.parser(shellExtParseString(string), ¶m) == 0)
|
||||
{
|
||||
*result = (unsigned int)param;
|
||||
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 执行命令
|
||||
*
|
||||
@ -426,6 +460,7 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
|
||||
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||
char type[16];
|
||||
int index = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (command->data.cmd.signature != NULL)
|
||||
{
|
||||
@ -433,7 +468,6 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
|
||||
if (except != argc - 1)
|
||||
{
|
||||
shellWriteString(shell, "Parameters number incorrect\r\n");
|
||||
shellPrint(shell, "except: %d, actual: %d\r\n", except, argc - 1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -461,124 +495,124 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
|
||||
{
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 1
|
||||
case 0:
|
||||
return command->data.cmd.function();
|
||||
// break;
|
||||
ret = command->data.cmd.function();
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 1 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 2
|
||||
case 1:
|
||||
return command->data.cmd.function(params[0]);
|
||||
// break;
|
||||
ret = command->data.cmd.function(params[0]);
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 2 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 3
|
||||
case 2:
|
||||
return command->data.cmd.function(params[0], params[1]);
|
||||
// break;
|
||||
ret = command->data.cmd.function(params[0], params[1]);
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 3 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 4
|
||||
case 3:
|
||||
return command->data.cmd.function(params[0], params[1],
|
||||
ret = command->data.cmd.function(params[0], params[1],
|
||||
params[2]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 4 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 5
|
||||
case 4:
|
||||
return command->data.cmd.function(params[0], params[1],
|
||||
ret = command->data.cmd.function(params[0], params[1],
|
||||
params[2], params[3]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 5 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 6
|
||||
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[4]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 6 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 7
|
||||
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[4], params[5]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 7 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 8
|
||||
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[4], params[5],
|
||||
params[6]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 8 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 9
|
||||
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[4], params[5],
|
||||
params[6], params[7]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 9 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 10
|
||||
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[4], params[5],
|
||||
params[6], params[7],
|
||||
params[8]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 10 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 11
|
||||
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[4], params[5],
|
||||
params[6], params[7],
|
||||
params[8], params[9]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 11 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 12
|
||||
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[4], params[5],
|
||||
params[6], params[7],
|
||||
params[8], params[9],
|
||||
params[10]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 12 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 13
|
||||
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[4], params[5],
|
||||
params[6], params[7],
|
||||
params[8], params[9],
|
||||
params[10], params[11]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 13 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 14
|
||||
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[4], params[5],
|
||||
params[6], params[7],
|
||||
params[8], params[9],
|
||||
params[10], params[11],
|
||||
params[12]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 14 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 15
|
||||
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[4], params[5],
|
||||
params[6], params[7],
|
||||
params[8], params[9],
|
||||
params[10], params[11],
|
||||
params[12], params[13]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 15 */
|
||||
#if SHELL_PARAMETER_MAX_NUMBER >= 16
|
||||
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[4], params[5],
|
||||
params[6], params[7],
|
||||
@ -586,11 +620,24 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
|
||||
params[10], params[11],
|
||||
params[12], params[13],
|
||||
params[14]);
|
||||
// break;
|
||||
break;
|
||||
#endif /** SHELL_PARAMETER_MAX_NUMBER >= 16 */
|
||||
default:
|
||||
return -1;
|
||||
// break;
|
||||
ret = -1;
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user