mirror of
https://github.com/NevermindZZT/letter-shell.git
synced 2025-01-21 10:02:54 +08:00
新增 函数签名
## 函数签名 之前的版本里,如果声明的命令是 `SHELL_TYPE_CMD_FUNC`,shell 会自动进行参数的转换,但是参数转换后的类型是猜出来的,无法保证转换后的数据类型是正确的,一旦猜错了,就容易导致程序挂掉 由此,借鉴 Java 等语言的函数签名,新版也引入了函数签名的概念,在声明命令时,可以给定最终执行命令的函数的签名,shell 根据这个签名进行参数转换,使用此功能时,需要打开宏 `SHELL_USING_FUNC_SIGNATURE` 函数签名是一个字符串,通过这个字符串声明表达函数的参数类型,返回值不声明,比如一个函数`int func(int a, char *b, char c)`,它的函数签名就是 `ics` 基本类型的参数签名定义如下: | 类型 | 签名 | | -------------------- | ---- | | char(字符) | c | | int/short/char(数字) | i | | char * (字符串) | s | | pointer | p | 声明命令时,在最后添加一个参数 `.data.cmd.signature = "ics"` 即可,比如: ```c 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"); ```
This commit is contained in:
parent
c4dad4c43a
commit
acd9dceb4e
38
README.md
38
README.md
@ -1,8 +1,8 @@
|
|||||||
# letter shell 3.x
|
# letter shell 3.x
|
||||||
|
|
||||||
![version](https://img.shields.io/badge/version-3.1.2-brightgreen.svg)
|
![version](https://img.shields.io/badge/version-3.2.0-brightgreen.svg)
|
||||||
![standard](https://img.shields.io/badge/standard-c99-brightgreen.svg)
|
![standard](https://img.shields.io/badge/standard-c99-brightgreen.svg)
|
||||||
![build](https://img.shields.io/badge/build-2021.10.17-brightgreen.svg)
|
![build](https://img.shields.io/badge/build-2023.04.15-brightgreen.svg)
|
||||||
![license](https://img.shields.io/badge/license-MIT-brightgreen.svg)
|
![license](https://img.shields.io/badge/license-MIT-brightgreen.svg)
|
||||||
|
|
||||||
一个功能强大的嵌入式shell
|
一个功能强大的嵌入式shell
|
||||||
@ -25,6 +25,7 @@
|
|||||||
- [定义宏说明](#定义宏说明)
|
- [定义宏说明](#定义宏说明)
|
||||||
- [命令属性字段说明](#命令属性字段说明)
|
- [命令属性字段说明](#命令属性字段说明)
|
||||||
- [代理函数和代理参数解析](#代理函数和代理参数解析)
|
- [代理函数和代理参数解析](#代理函数和代理参数解析)
|
||||||
|
- [函数签名](#函数签名)
|
||||||
- [权限系统说明](#权限系统说明)
|
- [权限系统说明](#权限系统说明)
|
||||||
- [锁说明](#锁说明)
|
- [锁说明](#锁说明)
|
||||||
- [伴生对象](#伴生对象)
|
- [伴生对象](#伴生对象)
|
||||||
@ -178,6 +179,8 @@
|
|||||||
| SHELL_DEFAULT_USER | shell默认用户 |
|
| SHELL_DEFAULT_USER | shell默认用户 |
|
||||||
| SHELL_DEFAULT_USER_PASSWORD | 默认用户密码 |
|
| SHELL_DEFAULT_USER_PASSWORD | 默认用户密码 |
|
||||||
| SHELL_LOCK_TIMEOUT | shell自动锁定超时 |
|
| SHELL_LOCK_TIMEOUT | shell自动锁定超时 |
|
||||||
|
| SHELL_USING_FUNC_SIGNATURE | 使用函数签名 |
|
||||||
|
| SHELL_COMMAND_FILL_BYTES | 命令结构体填充字节数 |
|
||||||
|
|
||||||
## 使用方式
|
## 使用方式
|
||||||
|
|
||||||
@ -485,6 +488,36 @@ p1, SHELL_PARAM_FLOAT(p2), p3, SHELL_PARAM_FLOAT(p4));
|
|||||||
|
|
||||||
相比常规的命令导出,代理函数命令导出前4个参数和常规形式的命令导出一致,之后的参数即传递至目标函数的参数,letter shell默认实现的代理函数定义支持最多7个参数,p1~p7,对于不需要代理参数解析的参数,只需要对应写入`px(x为1~7)`即可,比如上方示例的`p1`和`p3`,而需要代理参数解析的参数,则需要使用对应的参数解析器,比如上方示例的`p2`和`p4`
|
相比常规的命令导出,代理函数命令导出前4个参数和常规形式的命令导出一致,之后的参数即传递至目标函数的参数,letter shell默认实现的代理函数定义支持最多7个参数,p1~p7,对于不需要代理参数解析的参数,只需要对应写入`px(x为1~7)`即可,比如上方示例的`p1`和`p3`,而需要代理参数解析的参数,则需要使用对应的参数解析器,比如上方示例的`p2`和`p4`
|
||||||
|
|
||||||
|
## 函数签名
|
||||||
|
|
||||||
|
letter shell 3.2.x 之后,引入了函数签名的概念,以便于参数自动解析
|
||||||
|
|
||||||
|
之前的版本里,如果声明的命令是 `SHELL_TYPE_CMD_FUNC`,shell 会自动进行参数的转换,但是参数转换后的类型是猜出来的,无法保证转换后的数据类型是正确的,一旦猜错了,就容易导致程序挂掉
|
||||||
|
|
||||||
|
由此,借鉴 Java 等语言的函数签名,新版也引入了函数签名的概念,在声明命令时,可以给定最终执行命令的函数的签名,shell 根据这个签名进行参数转换,使用此功能时,需要打开宏 `SHELL_USING_FUNC_SIGNATURE`
|
||||||
|
|
||||||
|
函数签名是一个字符串,通过这个字符串声明表达函数的参数类型,返回值不声明,比如一个函数`int func(int a, char *b, char c)`,它的函数签名就是 `ics`
|
||||||
|
|
||||||
|
基本类型的参数签名定义如下:
|
||||||
|
|
||||||
|
| 类型 | 签名 |
|
||||||
|
| -------------------- | ---- |
|
||||||
|
| char(字符) | c |
|
||||||
|
| int/short/char(数字) | i |
|
||||||
|
| char * (字符串) | s |
|
||||||
|
| pointer | p |
|
||||||
|
|
||||||
|
声明命令时,在最后添加一个参数 `.data.cmd.signature = "ics"` 即可,比如:
|
||||||
|
|
||||||
|
```c
|
||||||
|
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");
|
||||||
|
```
|
||||||
|
|
||||||
## 权限系统说明
|
## 权限系统说明
|
||||||
|
|
||||||
letter shell 3.x的权限管理同用户定义紧密相关,letter shell 3.x使用8个bit位表示命令权限,当用户和命令的权限按位与为真,或者命令权限为0时,表示该用户拥有此命令的权限,可以调用该命令
|
letter shell 3.x的权限管理同用户定义紧密相关,letter shell 3.x使用8个bit位表示命令权限,当用户和命令的权限按位与为真,或者命令权限为0时,表示该用户拥有此命令的权限,可以调用该命令
|
||||||
@ -566,7 +599,6 @@ python shellTools.py project
|
|||||||
letter shell 3.x提供了一个x86的demo,可以直接编译运行,其中包含了一条按键键值测试命令,可以测试按键键值,用于快捷键的定义,编译运行方法如下:
|
letter shell 3.x提供了一个x86的demo,可以直接编译运行,其中包含了一条按键键值测试命令,可以测试按键键值,用于快捷键的定义,编译运行方法如下:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
mv src/shell_cfg.h src/shell_cfg.h.bak
|
|
||||||
cd demo/x86-gcc/
|
cd demo/x86-gcc/
|
||||||
cmake .
|
cmake .
|
||||||
make
|
make
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
add_definitions(-DSHELL_CFG_USER="shell_cfg_user.h")
|
|
||||||
|
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS "src/shell.c"
|
SRCS "src/shell.c"
|
||||||
"src/shell_ext.c"
|
"src/shell_ext.c"
|
||||||
"shell_port.c"
|
"shell_port.c"
|
||||||
|
|
||||||
INCLUDE_DIRS "./"
|
INCLUDE_DIRS "./"
|
||||||
"./src"
|
"./src"
|
||||||
|
|
||||||
|
REQUIRES
|
||||||
|
driver
|
||||||
|
|
||||||
LDFRAGMENTS "shell.lf"
|
LDFRAGMENTS "shell.lf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_compile_options(${COMPONENT_LIB} PRIVATE -DSHELL_CFG_USER="shell_cfg_user.h")
|
||||||
|
@ -11,3 +11,5 @@
|
|||||||
- `esp-idf` 编译系统会忽略 `__attribute__((used))` 声明,所以仅仅作为命令定义的函数不会被包含在编译出来的固件里面,只有被代码引用的函数会被编译进去
|
- `esp-idf` 编译系统会忽略 `__attribute__((used))` 声明,所以仅仅作为命令定义的函数不会被包含在编译出来的固件里面,只有被代码引用的函数会被编译进去
|
||||||
|
|
||||||
- 此 demo 包含链接使用的 `.lf` 文件,在使用这个文件的情况下不需要修改 `esp-idf` 中的 `ld` 文件
|
- 此 demo 包含链接使用的 `.lf` 文件,在使用这个文件的情况下不需要修改 `esp-idf` 中的 `ld` 文件
|
||||||
|
|
||||||
|
- 如果使用 overlay 的方式配置 shell,建议在主 CMakeList.txt 后面添加 `idf_build_set_property(COMPILE_OPTIONS "-DSHELL_CFG_USER=\"shell_cfg_user.h\"" APPEND)`
|
||||||
|
@ -34,5 +34,7 @@ target_include_directories(LetterShell PUBLIC
|
|||||||
|
|
||||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T shell.lds")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} \
|
||||||
|
-T \"${CMAKE_CURRENT_SOURCE_DIR}/shell.lds\" \
|
||||||
|
-Wl,-Map=LetterShell.map")
|
||||||
set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -std=c++11 -pthread")
|
set(CMAKE_CXX_FLAGS "${CAMKE_CXX_FLAGS} -std=c++11 -pthread")
|
||||||
|
@ -77,6 +77,13 @@ SECTIONS
|
|||||||
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
.rodata1 : { *(.rodata1) }
|
.rodata1 : { *(.rodata1) }
|
||||||
|
. = ALIGN(32);
|
||||||
|
.shell_command ALIGN(4) :
|
||||||
|
{
|
||||||
|
_shell_command_start = .;
|
||||||
|
KEEP (*(shellCommand))
|
||||||
|
_shell_command_end = .;
|
||||||
|
}
|
||||||
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
@ -183,12 +190,7 @@ SECTIONS
|
|||||||
. = ALIGN(64 / 8);
|
. = ALIGN(64 / 8);
|
||||||
. = SEGMENT_START("ldata-segment", .);
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
{
|
{ *(.lrodata .lrodata.* .gnu.linkonce.lr.*) }
|
||||||
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
|
||||||
_shell_command_start = .;
|
|
||||||
KEEP (*(shellCommand))
|
|
||||||
_shell_command_end = .;
|
|
||||||
}
|
|
||||||
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
{
|
{
|
||||||
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
@ -66,4 +66,21 @@ unsigned int userGetTick();
|
|||||||
*/
|
*/
|
||||||
#define SHELL_FREE(obj) free(obj)
|
#define SHELL_FREE(obj) free(obj)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 使用函数签名
|
||||||
|
* 使能后,可以在声明命令时,指定函数的签名,shell 会根据函数签名进行参数转换,
|
||||||
|
* 而不是自动判断参数的类型,如果参数和函数签名不匹配,会停止执行命令
|
||||||
|
*/
|
||||||
|
#define SHELL_USING_FUNC_SIGNATURE 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令填充字节数
|
||||||
|
* 这个选项控制对声明的命令结构体进行填充,填充的字节数为`SHELL_COMMAND_FILL_BYTES`,
|
||||||
|
* 填充的数据位于命令结构体的末尾
|
||||||
|
* 部分编译器会在结构体数据后面进行填充,使变量的地址对齐,这会导致 shell 中
|
||||||
|
* 通过 sizeof 获取结构体大小,然后通过偏移进行遍历的时候,无法正确地找到命令
|
||||||
|
* 通过填充,我们主动将结构体对齐,从而使得 shell 可以正确地遍历命令
|
||||||
|
*/
|
||||||
|
#define SHELL_COMMAND_FILL_BYTES 24
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -272,3 +272,12 @@ void systemPassthrough(char *data, unsigned short len)
|
|||||||
system(data);
|
system(data);
|
||||||
}
|
}
|
||||||
SHELL_EXPORT_PASSTROUGH(SHELL_CMD_PERMISSION(0), system, system>>\x20, systemPassthrough, passthrough for system command);
|
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
|
||||||
|
@ -25,6 +25,12 @@ typedef struct shell_command_cpp_cmd
|
|||||||
const char *name; /**< 命令名 */
|
const char *name; /**< 命令名 */
|
||||||
int (*function)(); /**< 命令执行函数 */
|
int (*function)(); /**< 命令执行函数 */
|
||||||
const char *desc; /**< 命令描述 */
|
const char *desc; /**< 命令描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
const char *signature; /**< 函数签名 */
|
||||||
|
#endif
|
||||||
|
#if SHELL_COMMAND_FILL_BYTES != 0
|
||||||
|
char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */
|
||||||
|
#endif
|
||||||
} ShellCommandCppCmd;
|
} ShellCommandCppCmd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,6 +42,12 @@ typedef struct shell_command_cpp_var
|
|||||||
const char *name; /**< 变量名 */
|
const char *name; /**< 变量名 */
|
||||||
void *value; /**< 变量值 */
|
void *value; /**< 变量值 */
|
||||||
const char *desc; /**< 变量描述 */
|
const char *desc; /**< 变量描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
void *unused; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */
|
||||||
|
#endif
|
||||||
|
#if SHELL_COMMAND_FILL_BYTES != 0
|
||||||
|
char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */
|
||||||
|
#endif
|
||||||
} ShellCommandCppVar;
|
} ShellCommandCppVar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,6 +59,12 @@ typedef struct shell_command_cpp_user
|
|||||||
const char *name; /**< 用户名 */
|
const char *name; /**< 用户名 */
|
||||||
const char *password; /**< 用户密码 */
|
const char *password; /**< 用户密码 */
|
||||||
const char *desc; /**< 用户描述 */
|
const char *desc; /**< 用户描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
void *unused; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */
|
||||||
|
#endif
|
||||||
|
#if SHELL_COMMAND_FILL_BYTES != 0
|
||||||
|
char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */
|
||||||
|
#endif
|
||||||
} ShellCommandCppUser;
|
} ShellCommandCppUser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,6 +76,12 @@ typedef struct shell_command_cpp_key
|
|||||||
int value; /**< 按键键值 */
|
int value; /**< 按键键值 */
|
||||||
void (*function)(Shell *); /**< 按键执行函数 */
|
void (*function)(Shell *); /**< 按键执行函数 */
|
||||||
const char *desc; /**< 按键描述 */
|
const char *desc; /**< 按键描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
void *unused; /**< 未使用成员,需要保持和 ShellCommandCppCmd 大小一致 */
|
||||||
|
#endif
|
||||||
|
#if SHELL_COMMAND_FILL_BYTES != 0
|
||||||
|
char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */
|
||||||
|
#endif
|
||||||
} ShellCommandCppKey;
|
} ShellCommandCppKey;
|
||||||
|
|
||||||
#if SHELL_USING_CMD_EXPORT == 1
|
#if SHELL_USING_CMD_EXPORT == 1
|
||||||
@ -70,8 +94,9 @@ typedef struct shell_command_cpp_key
|
|||||||
* @param _name 命令名
|
* @param _name 命令名
|
||||||
* @param _func 命令函数
|
* @param _func 命令函数
|
||||||
* @param _desc 命令描述
|
* @param _desc 命令描述
|
||||||
|
* @param ... 其他参数
|
||||||
*/
|
*/
|
||||||
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) \
|
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc, ...) \
|
||||||
const char shellCmd##_name[] = #_name; \
|
const char shellCmd##_name[] = #_name; \
|
||||||
const char shellDesc##_name[] = #_desc; \
|
const char shellDesc##_name[] = #_desc; \
|
||||||
extern "C" SHELL_USED const ShellCommandCppCmd \
|
extern "C" SHELL_USED const ShellCommandCppCmd \
|
||||||
@ -80,7 +105,8 @@ typedef struct shell_command_cpp_key
|
|||||||
_attr, \
|
_attr, \
|
||||||
shellCmd##_name, \
|
shellCmd##_name, \
|
||||||
(int (*)())_func, \
|
(int (*)())_func, \
|
||||||
shellDesc##_name \
|
shellDesc##_name, \
|
||||||
|
##__VA_ARGS__ \
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef SHELL_EXPORT_VAR
|
#undef SHELL_EXPORT_VAR
|
||||||
|
@ -1957,7 +1957,7 @@ int shellExecute(int argc, char *argv[])
|
|||||||
Shell *shell = shellGetCurrent();
|
Shell *shell = shellGetCurrent();
|
||||||
if (shell && argc >= 2)
|
if (shell && argc >= 2)
|
||||||
{
|
{
|
||||||
int (*func)() = (int (*)())shellExtParsePara(shell, argv[1]);
|
int (*func)() = (int (*)())shellExtParsePara(shell, argv[1], NULL);
|
||||||
ShellCommand command = {
|
ShellCommand command = {
|
||||||
.attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)
|
.attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)
|
||||||
|SHELL_CMD_DISABLE_RETURN,
|
|SHELL_CMD_DISABLE_RETURN,
|
||||||
|
27
src/shell.h
27
src/shell.h
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include "shell_cfg.h"
|
#include "shell_cfg.h"
|
||||||
|
|
||||||
#define SHELL_VERSION "3.1.2" /**< 版本号 */
|
#define SHELL_VERSION "3.2.0" /**< 版本号 */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,8 +128,9 @@
|
|||||||
* @param _name 命令名
|
* @param _name 命令名
|
||||||
* @param _func 命令函数
|
* @param _func 命令函数
|
||||||
* @param _desc 命令描述
|
* @param _desc 命令描述
|
||||||
|
* @param ... 其他参数
|
||||||
*/
|
*/
|
||||||
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) \
|
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc, ...) \
|
||||||
const char shellCmd##_name[] = #_name; \
|
const char shellCmd##_name[] = #_name; \
|
||||||
const char shellDesc##_name[] = #_desc; \
|
const char shellDesc##_name[] = #_desc; \
|
||||||
SHELL_USED const ShellCommand \
|
SHELL_USED const ShellCommand \
|
||||||
@ -138,7 +139,8 @@
|
|||||||
.attr.value = _attr, \
|
.attr.value = _attr, \
|
||||||
.data.cmd.name = shellCmd##_name, \
|
.data.cmd.name = shellCmd##_name, \
|
||||||
.data.cmd.function = (int (*)())_func, \
|
.data.cmd.function = (int (*)())_func, \
|
||||||
.data.cmd.desc = shellDesc##_name \
|
.data.cmd.desc = shellDesc##_name, \
|
||||||
|
##__VA_ARGS__ \
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -386,7 +388,7 @@ typedef struct shell_command
|
|||||||
ShellCommandType type : 4; /**< command类型 */
|
ShellCommandType type : 4; /**< command类型 */
|
||||||
unsigned char enableUnchecked : 1; /**< 在未校验密码的情况下可用 */
|
unsigned char enableUnchecked : 1; /**< 在未校验密码的情况下可用 */
|
||||||
unsigned char disableReturn : 1; /**< 禁用返回值输出 */
|
unsigned char disableReturn : 1; /**< 禁用返回值输出 */
|
||||||
unsigned char readOnly : 1; /**< 只读 */
|
unsigned char readOnly : 1; /**< 只读 */
|
||||||
unsigned char reserve : 1; /**< 保留 */
|
unsigned char reserve : 1; /**< 保留 */
|
||||||
unsigned char paramNum : 4; /**< 参数数量 */
|
unsigned char paramNum : 4; /**< 参数数量 */
|
||||||
} attrs;
|
} attrs;
|
||||||
@ -399,26 +401,41 @@ typedef struct shell_command
|
|||||||
const char *name; /**< 命令名 */
|
const char *name; /**< 命令名 */
|
||||||
int (*function)(); /**< 命令执行函数 */
|
int (*function)(); /**< 命令执行函数 */
|
||||||
const char *desc; /**< 命令描述 */
|
const char *desc; /**< 命令描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
const char *signature; /**< 函数签名 */
|
||||||
|
#endif
|
||||||
} cmd; /**< 命令定义 */
|
} cmd; /**< 命令定义 */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
const char *name; /**< 变量名 */
|
const char *name; /**< 变量名 */
|
||||||
void *value; /**< 变量值 */
|
void *value; /**< 变量值 */
|
||||||
const char *desc; /**< 变量描述 */
|
const char *desc; /**< 变量描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
const char *unsued; /**< 未使用成员 */
|
||||||
|
#endif
|
||||||
} var; /**< 变量定义 */
|
} var; /**< 变量定义 */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
const char *name; /**< 用户名 */
|
const char *name; /**< 用户名 */
|
||||||
const char *password; /**< 用户密码 */
|
const char *password; /**< 用户密码 */
|
||||||
const char *desc; /**< 用户描述 */
|
const char *desc; /**< 用户描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
const char *unsued; /**< 未使用成员 */
|
||||||
|
#endif
|
||||||
} user; /**< 用户定义 */
|
} user; /**< 用户定义 */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int value; /**< 按键键值 */
|
int value; /**< 按键键值 */
|
||||||
void (*function)(Shell *); /**< 按键执行函数 */
|
void (*function)(Shell *); /**< 按键执行函数 */
|
||||||
const char *desc; /**< 按键描述 */
|
const char *desc; /**< 按键描述 */
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
const char *unsued; /**< 未使用成员 */
|
||||||
|
#endif
|
||||||
} key; /**< 按键定义 */
|
} key; /**< 按键定义 */
|
||||||
} data;
|
} data;
|
||||||
|
#if SHELL_COMMAND_FILL_BYTES != 0
|
||||||
|
char fill[SHELL_COMMAND_FILL_BYTES]; /**< 填充字节 */
|
||||||
|
#endif
|
||||||
} ShellCommand;
|
} ShellCommand;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,4 +246,25 @@
|
|||||||
#define SHELL_LOCK_TIMEOUT 0 * 60 * 1000
|
#define SHELL_LOCK_TIMEOUT 0 * 60 * 1000
|
||||||
#endif /** SHELL_LOCK_TIMEOUT */
|
#endif /** SHELL_LOCK_TIMEOUT */
|
||||||
|
|
||||||
|
#ifndef SHELL_USING_FUNC_SIGNATURE
|
||||||
|
/**
|
||||||
|
* @brief 使用函数签名
|
||||||
|
* 使能后,可以在声明命令时,指定函数的签名,shell 会根据函数签名进行参数转换,
|
||||||
|
* 而不是自动判断参数的类型,如果参数和函数签名不匹配,会停止执行命令
|
||||||
|
*/
|
||||||
|
#define SHELL_USING_FUNC_SIGNATURE 0
|
||||||
|
#endif /** SHELL_USING_FUNC_SIGNATURE */
|
||||||
|
|
||||||
|
#ifndef SHELL_COMMAND_FILL_BYTES
|
||||||
|
/**
|
||||||
|
* @brief 命令填充字节数
|
||||||
|
* 这个选项控制对声明的命令结构体进行填充,填充的字节数为`SHELL_COMMAND_FILL_BYTES`,
|
||||||
|
* 填充的数据位于命令结构体的末尾
|
||||||
|
* 部分编译器会在结构体数据后面进行填充,使变量的地址对齐,这会导致 shell 中
|
||||||
|
* 通过 sizeof 获取结构体大小,然后通过偏移进行遍历的时候,无法正确地找到命令
|
||||||
|
* 通过填充,我们主动将结构体对齐,从而使得 shell 可以正确地遍历命令
|
||||||
|
*/
|
||||||
|
#define SHELL_COMMAND_FILL_BYTES 0
|
||||||
|
#endif /** SHELL_COMMAND_FILL_BYTES */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "shell_cfg.h"
|
#include "shell_cfg.h"
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
#include "shell_ext.h"
|
#include "shell_ext.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
extern ShellCommand* shellSeekCommand(Shell *shell,
|
extern ShellCommand* shellSeekCommand(Shell *shell,
|
||||||
const char *cmd,
|
const char *cmd,
|
||||||
@ -20,6 +20,37 @@ extern ShellCommand* shellSeekCommand(Shell *shell,
|
|||||||
unsigned short compareLength);
|
unsigned short compareLength);
|
||||||
extern int shellGetVarValue(Shell *shell, ShellCommand *command);
|
extern int shellGetVarValue(Shell *shell, ShellCommand *command);
|
||||||
|
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
/**
|
||||||
|
* @brief 获取下一个参数类型
|
||||||
|
*
|
||||||
|
* @param signature 函数签名
|
||||||
|
* @param index 参数遍历在签名中的起始索引
|
||||||
|
* @param type 获取到的参数类型
|
||||||
|
*
|
||||||
|
* @return int 下一个参数在签名中的索引
|
||||||
|
*/
|
||||||
|
static int shellGetNextArgType(const char *signature, int index, char *type)
|
||||||
|
{
|
||||||
|
char *p = signature + index;
|
||||||
|
if (*p == 'L')
|
||||||
|
{
|
||||||
|
while (*p != ';' && *p != 0)
|
||||||
|
{
|
||||||
|
*type++ = *p++;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*type++ = *p;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
*type = '\0';
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 判断数字进制
|
* @brief 判断数字进制
|
||||||
*
|
*
|
||||||
@ -92,7 +123,7 @@ static char shellExtToNum(char code)
|
|||||||
*/
|
*/
|
||||||
static char shellExtParseChar(char *string)
|
static char shellExtParseChar(char *string)
|
||||||
{
|
{
|
||||||
char *p = string + 1;
|
char *p = (*string == '\'') ? (string + 1) : string;
|
||||||
char value = 0;
|
char value = 0;
|
||||||
|
|
||||||
if (*p == '\\')
|
if (*p == '\\')
|
||||||
@ -268,23 +299,43 @@ static unsigned int shellExtParseVar(Shell *shell, char *var)
|
|||||||
* @param string 参数
|
* @param string 参数
|
||||||
* @return unsigned int 解析结果
|
* @return unsigned int 解析结果
|
||||||
*/
|
*/
|
||||||
unsigned int shellExtParsePara(Shell *shell, char *string)
|
unsigned int shellExtParsePara(Shell *shell, char *string, char *type)
|
||||||
{
|
{
|
||||||
if (*string == '\'' && *(string + 1))
|
if (type == NULL || (*string == '$' && *(string + 1)))
|
||||||
{
|
{
|
||||||
return (unsigned int)shellExtParseChar(string);
|
if (*string == '\'' && *(string + 1))
|
||||||
|
{
|
||||||
|
return (unsigned int)shellExtParseChar(string);
|
||||||
|
}
|
||||||
|
else if (*string == '-' || (*string >= '0' && *string <= '9'))
|
||||||
|
{
|
||||||
|
return (unsigned int)shellExtParseNumber(string);
|
||||||
|
}
|
||||||
|
else if (*string == '$' && *(string + 1))
|
||||||
|
{
|
||||||
|
return shellExtParseVar(shell, string);
|
||||||
|
}
|
||||||
|
else if (*string)
|
||||||
|
{
|
||||||
|
return (unsigned int)shellExtParseString(string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (*string == '-' || (*string >= '0' && *string <= '9'))
|
else
|
||||||
{
|
{
|
||||||
return (unsigned int)shellExtParseNumber(string);
|
if (strcmp("c", type) == 0)
|
||||||
}
|
{
|
||||||
else if (*string == '$' && *(string + 1))
|
return (unsigned int)shellExtParseChar(string);
|
||||||
{
|
}
|
||||||
return shellExtParseVar(shell, string);
|
else if (strcmp("i", type) == 0
|
||||||
}
|
|| strcmp("f", type) == 0
|
||||||
else if (*string)
|
|| strcmp("p", type) == 0)
|
||||||
{
|
{
|
||||||
return (unsigned int)shellExtParseString(string);
|
return (unsigned int)shellExtParseNumber(string);
|
||||||
|
}
|
||||||
|
else if (strcmp("s", type) == 0)
|
||||||
|
{
|
||||||
|
return (unsigned int)shellExtParseString(string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -304,9 +355,24 @@ int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
|
|||||||
unsigned int params[SHELL_PARAMETER_MAX_NUMBER] = {0};
|
unsigned int params[SHELL_PARAMETER_MAX_NUMBER] = {0};
|
||||||
int paramNum = command->attr.attrs.paramNum > (argc - 1) ?
|
int paramNum = command->attr.attrs.paramNum > (argc - 1) ?
|
||||||
command->attr.attrs.paramNum : (argc - 1);
|
command->attr.attrs.paramNum : (argc - 1);
|
||||||
|
#if SHELL_USING_FUNC_SIGNATURE == 1
|
||||||
|
char type[8];
|
||||||
|
int index = 0;
|
||||||
|
#endif
|
||||||
for (int i = 0; i < argc - 1; i++)
|
for (int i = 0; i < argc - 1; i++)
|
||||||
{
|
{
|
||||||
params[i] = shellExtParsePara(shell, argv[i + 1]);
|
#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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
params[i] = shellExtParsePara(shell, argv[i + 1], NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
params[i] = shellExtParsePara(shell, argv[i + 1], NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
switch (paramNum)
|
switch (paramNum)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@ typedef enum
|
|||||||
NUM_TYPE_FLOAT /**< 浮点型 */
|
NUM_TYPE_FLOAT /**< 浮点型 */
|
||||||
} ShellNumType;
|
} ShellNumType;
|
||||||
|
|
||||||
unsigned int shellExtParsePara(Shell *shell, char *string);
|
unsigned int shellExtParsePara(Shell *shell, char *string, char *type);
|
||||||
int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[]);
|
int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user