更新模板到最新状态
This commit is contained in:
@@ -27,11 +27,11 @@
|
||||
* - @b PSET_CP 根据一个已定义的 const sh_vset_param_t* 执行自动补选项
|
||||
*
|
||||
* 实例1: 以下这些函数可被 SH_SETUP_CMD 中定义的 FUNC 执行,或者作为 sh_vset_param_t::set_func 的成员
|
||||
* static int _value_set_u8(const char *argv[]) { SET_VAR(&var_u8, 1, 200); }
|
||||
* static int _value_set_s16(const char *argv[]) { SET_VAR(&var_s16, -1000, 1000); }
|
||||
* static int _value_set_float(const char *argv[]) { SET_VAR(&var_float, -1000, var_u8); }
|
||||
* static int _value_set_str(const char *argv[]) { SET_VAR(&var_str, 0, 0); }
|
||||
* static int _value_set_enum(const char *argv[]) { SET_ENUM(&var_s32, "enable=1,disable=0"); }
|
||||
* static int _value_set_u8(const char *argv[]) { return SET_VAR(&var_u8, 1, 200); }
|
||||
* static int _value_set_s16(const char *argv[]) { return SET_VAR(&var_s16, -1000, 1000); }
|
||||
* static int _value_set_float(const char *argv[]) { return SET_VAR(&var_float, -1000, var_u8); }
|
||||
* static int _value_set_str(const char *argv[]) { return SET_VAR(&var_str, 0, 0); }
|
||||
* static int _value_set_enum(const char *argv[]) { return SET_ENUM(&var_s32, "enable=1,disable=0"); }
|
||||
*
|
||||
* 实例2: 实现选项+参数的格式
|
||||
* static sh_vset_param_t const s_param_template[] = {
|
||||
@@ -77,14 +77,6 @@ typedef enum
|
||||
*/
|
||||
typedef void (*vset_cb)(sh_t *sh_hdl, void *new_value);
|
||||
|
||||
/* 待设置变量数据结构 */
|
||||
typedef struct
|
||||
{
|
||||
void *dest;
|
||||
__type_attr_t attr;
|
||||
vset_cb cb;
|
||||
} __vset_param_t;
|
||||
|
||||
#define __GENERIC_ATTR(VAR) (__builtin_types_compatible_p(__typeof(VAR), char) ? __TYPE_ATTR_CHR \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile char) ? __TYPE_ATTR_CHR \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), bool) ? __TYPE_ATTR_BOOL \
|
||||
@@ -122,71 +114,41 @@ typedef struct // 用于长选项设置的描述结构
|
||||
const char *enum_str; // 仅在类型为 vset_enum_fn 时有效,为对应的选项提供可选的补全参数选项,值为 NULL 或 "" 时默认候选参数为 '?'
|
||||
} sh_vset_param_t;
|
||||
|
||||
int vset_unsigned(const __vset_param_t *param, const char *argv[], unsigned int low, unsigned int high);
|
||||
int vset_integer(const __vset_param_t *param, const char *argv[], signed int low, signed int high);
|
||||
int vset_float(const __vset_param_t *param, const char *argv[], float low, float high);
|
||||
int vset_str(const __vset_param_t *param, const char *argv[], unsigned bufsize);
|
||||
int vset_enum(const __vset_param_t *param, const char *argv[], const char *enum_str);
|
||||
int vset_unsigned(void *dest, __type_attr_t attr, vset_cb cb, const char *argv[], unsigned int low, unsigned int high);
|
||||
int vset_integer(void *dest, __type_attr_t attr, vset_cb cb, const char *argv[], signed int low, signed int high);
|
||||
int vset_float(void *dest, __type_attr_t attr, vset_cb cb, const char *argv[], float low, float high);
|
||||
int vset_str(void *dest, __type_attr_t attr, vset_cb cb, const char *argv[], unsigned bufsize);
|
||||
int vset_enum(void *dest, __type_attr_t attr, vset_cb cb, const char *argv[], const char *enum_str);
|
||||
void vset_cp_enum(int argc, bool flag, const char *enum_str);
|
||||
|
||||
int vset_option_set(sh_t *sh_hdl, int *argc, const char *argv[], const sh_vset_param_t *p, unsigned size);
|
||||
bool vset_option_cp(sh_t *sh_hdl, int argc, const char *argv[], bool flag, const sh_vset_param_t *p, unsigned size);
|
||||
|
||||
/* 自动分析并设置变量的值,带设置回调 */
|
||||
#define SET_VAR_CB(NAME, LOW, HIGH, CB) \
|
||||
do \
|
||||
{ \
|
||||
static __vset_param_t const param = { \
|
||||
.dest = NAME, \
|
||||
.attr = __GENERIC_ATTR(*(NAME)), \
|
||||
.cb = CB, \
|
||||
}; \
|
||||
if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U8 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U16 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U32 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U64) \
|
||||
{ \
|
||||
return vset_unsigned(¶m, argv, LOW, HIGH); \
|
||||
} \
|
||||
else if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_CHR || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_BOOL || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S8 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S16 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S32 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S64) \
|
||||
{ \
|
||||
return vset_integer(¶m, argv, LOW, HIGH); \
|
||||
} \
|
||||
else if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_FLOAT || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_DOUBLE) \
|
||||
{ \
|
||||
return vset_float(¶m, argv, LOW, HIGH); \
|
||||
} \
|
||||
else if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_STR) \
|
||||
{ \
|
||||
return vset_str(¶m, argv, sizeof(*(NAME))); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
#define SET_VAR_CB(NAME, LOW, HIGH, CB) \
|
||||
((__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U8 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U16 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U32 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U64) \
|
||||
? vset_unsigned(NAME, __GENERIC_ATTR(*(NAME)), CB, argv, LOW, HIGH) \
|
||||
: ((__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_CHR || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_BOOL || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S8 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S16 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S32 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S64) \
|
||||
? vset_integer(NAME, __GENERIC_ATTR(*(NAME)), CB, argv, LOW, HIGH) \
|
||||
: ((__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_FLOAT || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_DOUBLE) \
|
||||
? vset_float(NAME, __GENERIC_ATTR(*(NAME)), CB, argv, LOW, HIGH) \
|
||||
: ((__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_STR) \
|
||||
? vset_str(NAME, __GENERIC_ATTR(*(NAME)), CB, argv, sizeof(*(NAME))) \
|
||||
: -1))))
|
||||
|
||||
/* 设置数据类型为 枚举型 的变量,带设置回调 */
|
||||
#define SET_ENUM_CB(NAME, ENUM_STR, CB) \
|
||||
do \
|
||||
{ \
|
||||
static __vset_param_t const param = { \
|
||||
.dest = NAME, \
|
||||
.attr = __GENERIC_ATTR(*(NAME)), \
|
||||
.cb = CB, \
|
||||
}; \
|
||||
return vset_enum(¶m, argv, ENUM_STR); \
|
||||
} while (0)
|
||||
(vset_enum(NAME, __GENERIC_ATTR(*(NAME)), CB, \
|
||||
argv, ENUM_STR))
|
||||
|
||||
/* 自动分析并设置变量的值 */
|
||||
#define SET_VAR(NAME, LOW, HIGH) SET_VAR_CB(NAME, LOW, HIGH, NULL)
|
||||
@@ -194,16 +156,6 @@ bool vset_option_cp(sh_t *sh_hdl, int argc, const char *argv[], bool flag, const
|
||||
/* 设置数据类型为 枚举型 的变量 */
|
||||
#define SET_ENUM(NAME, ENUM_STR) SET_ENUM_CB(NAME, ENUM_STR, NULL)
|
||||
|
||||
/* 对应 SET_VAR 所设置的变量的可用自动补全函数 */
|
||||
#define SET_CP_VAR() \
|
||||
do \
|
||||
{ \
|
||||
if (argc + flag == 1) \
|
||||
{ \
|
||||
sh_completion_resource(sh_hdl, NULL, "? ", NULL); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* 对应 SET_ENUM 所设置的变量的可用自动补全函数 */
|
||||
#define SET_CP_ENUM(ENUM_STR) \
|
||||
do \
|
||||
@@ -216,8 +168,67 @@ bool vset_option_cp(sh_t *sh_hdl, int argc, const char *argv[], bool flag, const
|
||||
|
||||
typedef void (*vset_global_cb)(sh_t *sh_hdl);
|
||||
|
||||
void vset_init(sh_t *sh_hdl, vset_global_cb cb);
|
||||
void vset_init(sh_t *sh_hdl, vset_global_cb global_cb);
|
||||
|
||||
void vset_force_cb(void);
|
||||
|
||||
/**
|
||||
* @note 对本函数的进一步说明。
|
||||
*
|
||||
* 在 sh 模块设计完成后,发现除了用于执行某些定义好的的操作外,更多情况下是用于设置变量。
|
||||
* 为了更好的支持这种需求,本模块应运而生。
|
||||
* 本模块的设计目标是通过命令行的形式设置变量,同时支持对变量的取值范围限制。
|
||||
* 本模块的设计思路是通过宏定义,将变量的类型和取值范围传递给 SET_VAR() 或 SET_ENUM() 进行具体的设置。
|
||||
* 本模块主要使用到的宏定义有:
|
||||
* - @b SET_VAR()
|
||||
* - @b SET_ENUM()
|
||||
* - @b SET_CP_ENUM()
|
||||
* - @b PSET_FN()
|
||||
* - @b PSET_CP()
|
||||
*
|
||||
* 这些都是根据实际的使用场景定义的。
|
||||
* 根据 sh 模块的主体功能,分为两个部分(可在使用 SH_SETUP_CMD() 定义命令时的第三和第四个参数来体现):
|
||||
* - 一个是用于执行某些操作的函数。
|
||||
* - 另一个是用于像 bash 一样,按 Tab 键自动补全的函数。
|
||||
* 对于前者,可在实际执行函数中直接使用 SET_VAR() 或 SET_ENUM() 来设置变量。
|
||||
* 对于后者,可在实际补全函数中直接使用 SET_CP_ENUM() 来提示可选项和可选值。
|
||||
*
|
||||
* 为什么设置宏要分两种?
|
||||
* SET_VAR() 和 SET_ENUM() 的本质区别是, SET_VAR() 用于设置无符号整形、带符号整型、单精度的浮点数和字符串的变量,它们的取值范围是连续的。
|
||||
* 值得注意的是: SET_VAR() 也支持字符串的设置,但是字符串的取值范围是无法限制的。
|
||||
* 而 SET_ENUM() 用于设置枚举型的变量,它的取值范围是允许离散的,并且可用一些字符串来表示具体的取值。
|
||||
*
|
||||
* 为什么补全函数只有 SET_CP_ENUM() ?
|
||||
* 因为 SET_ENUM() 的取值范围是离散的,所以需要一个额外的函数来提供可选的补全参数选项。对于连续的取值范围,不需要这个函数。
|
||||
*
|
||||
* 设置宏较为独立,虽然它是为了配合本模块而设计的,但是它的功能是独立的,在传输的参数中的 sh_hdl 主要是为了回显一些错误信息。
|
||||
* 补全宏则是为了配合 sh 模块的补全功能而设计的,它的功能是为了提供可选的补全参数选项。
|
||||
*
|
||||
* 小结:
|
||||
* - SET_VAR() 和 SET_ENUM() 用于设置变量的值。
|
||||
* - SET_CP_ENUM() 用于提供可选的补全参数选项。
|
||||
* - 它们可能在命令执行函数和补全函数中直接使用。
|
||||
*
|
||||
* 接着新问题来了,使用 SET_VAR() 或 SET_ENUM() 时,只能设置一个变量,如果这个命令要包含多种设置,该怎么办?
|
||||
* 为了解决这个问题,本模块引入了 sh_vset_param_t 结构体,它是一个数组,用于描述支待的待设置变量的具体类型。
|
||||
* 它统一描述了该命令的所有选项,包括选项的名称、选项的描述、选项的设置函数和选项的可选值。
|
||||
* 在命令执行函数和补全函数中,通过调用 PSET_FN() 和 PSET_CP() 来执行具体的设置。
|
||||
* 这两个宏的参数就是 sh_vset_param_t 结构体的数组。
|
||||
* 这个结构体的定义是固定的,它的成员包括:
|
||||
* - 选项,如 "--value"
|
||||
* - 对该选项的描述
|
||||
* - 与 option 对应的,使用宏 SET_VAR() 或 SET_ENUM() 设置变量的函数。如果值为 NULL 表示该选项无参数,同时对应的输入参数被保留
|
||||
* - 仅在类型为 vset_enum_fn 时有效,为对应的选项提供可选的补全参数选项,值为 NULL 或 "" 时默认候选参数为 '?'
|
||||
* 通过设置这个结构,便可得到一个完整的命令格式: <命令> [选项 <参数>] [选项 <参数>] ...
|
||||
*
|
||||
* 其他一些细节:
|
||||
* - 这些宏都是以最简约的形式定义的,以便在有大量数据的情况下降低阅读难度。在一些特殊情况下,可根据这些提及到的宏的定义展开理解再灵活使用。
|
||||
*
|
||||
* 总结:
|
||||
* SET_VAR(), SET_ENUM() 和 SET_CP_ENUM() 是用于单个变量的设置和补全,它们可以直接在命令执行函数和补全函数中使用,也可以在 sh_vset_param_t 结构体中对应的函数使用。
|
||||
* PSET_FN() 和 PSET_CP() 是用于多个变量的设置和补全,它们可以直接在命令执行函数和补全函数中被调用。
|
||||
* sh_vset_param_t 结构体是用于描述支待的待设置变量的具体类型,它可以直接在命令执行函数和补全函数中被调用。
|
||||
*
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user