From 2d630e38d75c0f83a819083261e2e025b4bcf29d Mon Sep 17 00:00:00 2001 From: wangqinglin <53550140+HelloByeAll@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:34:05 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90msh=E3=80=91=E6=96=B0=E5=A2=9Emsh?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8=E5=AD=90=E9=80=89=E9=A1=B9?= =?UTF-8?q?=E7=89=B9=E6=80=A7=20(#8086)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/finsh/Kconfig | 4 + components/finsh/cmd.c | 93 ++++++++++++++++++++++- components/finsh/finsh.h | 152 +++++++++++++++++++++++++------------ components/finsh/msh.c | 158 +++++++++++++++++++++++++++++++++++++++ components/finsh/msh.h | 4 + components/finsh/shell.c | 4 + 6 files changed, 365 insertions(+), 50 deletions(-) diff --git a/components/finsh/Kconfig b/components/finsh/Kconfig index 2d9d768e23..119d968163 100644 --- a/components/finsh/Kconfig +++ b/components/finsh/Kconfig @@ -76,4 +76,8 @@ if RT_USING_MSH int "The number of arguments for a shell command" default 10 + config FINSH_USING_OPTION_COMPLETION + bool "command option completion enable" + default y + endif diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c index c3b0760f6a..4dc21f404f 100644 --- a/components/finsh/cmd.c +++ b/components/finsh/cmd.c @@ -39,6 +39,7 @@ #ifdef RT_USING_FINSH #include +#define LIST_DFS_OPT_ID 0x100 #define LIST_FIND_OBJ_NR 8 static long clear(void) @@ -903,6 +904,7 @@ long list_device(void) } #endif /* RT_USING_DEVICE */ +#ifndef FINSH_USING_OPTION_COMPLETION int cmd_list(int argc, char **argv) { if(argc == 2) @@ -1013,6 +1015,95 @@ _usage: return 0; } -MSH_CMD_EXPORT_ALIAS(cmd_list, list, list objects); + +#else +CMD_OPTIONS_STATEMENT(cmd_list) +int cmd_list(int argc, char **argv) +{ + if (argc == 2) + { + switch (MSH_OPT_ID_GET(cmd_list)) + { + case RT_Object_Class_Thread: list_thread(); break; + case RT_Object_Class_Timer: list_timer(); break; +#ifdef RT_USING_SEMAPHORE + case RT_Object_Class_Semaphore: list_sem(); break; +#endif /* RT_USING_SEMAPHORE */ +#ifdef RT_USING_EVENT + case RT_Object_Class_Event: list_event(); break; +#endif /* RT_USING_EVENT */ +#ifdef RT_USING_MUTEX + case RT_Object_Class_Mutex: list_mutex(); break; +#endif /* RT_USING_MUTEX */ +#ifdef RT_USING_MAILBOX + case RT_Object_Class_MailBox: list_mailbox(); break; +#endif /* RT_USING_MAILBOX */ +#ifdef RT_USING_MESSAGEQUEUE + case RT_Object_Class_MessageQueue: list_msgqueue(); break; +#endif /* RT_USING_MESSAGEQUEUE */ +#ifdef RT_USING_MEMHEAP + case RT_Object_Class_MemHeap: list_memheap(); break; +#endif /* RT_USING_MEMHEAP */ +#ifdef RT_USING_MEMPOOL + case RT_Object_Class_MemPool: list_mempool(); break; +#endif /* RT_USING_MEMPOOL */ +#ifdef RT_USING_DEVICE + case RT_Object_Class_Device: list_device(); break; +#endif /* RT_USING_DEVICE */ +#ifdef RT_USING_DFS + case LIST_DFS_OPT_ID: + { + extern int list_fd(void); + list_fd(); + break; + } +#endif /* RT_USING_DFS */ + default: + goto _usage; + break; + }; + + return 0; + } + +_usage: + rt_kprintf("Usage: list [options]\n"); + rt_kprintf("[options]:\n"); + MSH_OPT_DUMP(cmd_list); + return 0; +} +CMD_OPTIONS_NODE_START(cmd_list) +CMD_OPTIONS_NODE(RT_Object_Class_Thread, thread, list threads) +CMD_OPTIONS_NODE(RT_Object_Class_Timer, timer, list timers) +#ifdef RT_USING_SEMAPHORE +CMD_OPTIONS_NODE(RT_Object_Class_Semaphore, sem, list semaphores) +#endif /* RT_USING_SEMAPHORE */ +#ifdef RT_USING_EVENT +CMD_OPTIONS_NODE(RT_Object_Class_Event, event, list events) +#endif /* RT_USING_EVENT */ +#ifdef RT_USING_MUTEX +CMD_OPTIONS_NODE(RT_Object_Class_Mutex, mutex, list mutexs) +#endif /* RT_USING_MUTEX */ +#ifdef RT_USING_MAILBOX +CMD_OPTIONS_NODE(RT_Object_Class_MailBox, mailbox, list mailboxs) +#endif /* RT_USING_MAILBOX */ +#ifdef RT_USING_MESSAGEQUEUE +CMD_OPTIONS_NODE(RT_Object_Class_MessageQueue, msgqueue, list message queues) +#endif /* RT_USING_MESSAGEQUEUE */ +#ifdef RT_USING_MEMHEAP +CMD_OPTIONS_NODE(RT_Object_Class_MemHeap, memheap, list memory heaps) +#endif /* RT_USING_MEMHEAP */ +#ifdef RT_USING_MEMPOOL +CMD_OPTIONS_NODE(RT_Object_Class_MemPool, mempool, list memory pools) +#endif /* RT_USING_MEMPOOL */ +#ifdef RT_USING_DEVICE +CMD_OPTIONS_NODE(RT_Object_Class_Device, device, list devices) +#endif /* RT_USING_DEVICE */ +#ifdef RT_USING_DFS +CMD_OPTIONS_NODE(LIST_DFS_OPT_ID, fd, list file descriptors) +#endif /* RT_USING_DFS */ +CMD_OPTIONS_NODE_END +#endif /* FINSH_USING_OPTION_COMPLETION */ +MSH_CMD_EXPORT_ALIAS(cmd_list, list, list objects, optenable); #endif /* RT_USING_FINSH */ diff --git a/components/finsh/finsh.h b/components/finsh/finsh.h index cf13b761d5..d6bf53abcb 100644 --- a/components/finsh/finsh.h +++ b/components/finsh/finsh.h @@ -16,21 +16,35 @@ #pragma section("FSymTab$f",read) #endif /* _MSC_VER */ +#ifdef FINSH_USING_OPTION_COMPLETION +#define FINSH_COND(opt) opt, +#else +#define FINSH_COND(opt) +#endif + +#ifdef FINSH_USING_DESCRIPTION +#define FINSH_DESC(cmd, desc) __fsym_##cmd##_desc, +#else +#define FINSH_DESC(cmd, desc) +#endif + typedef long (*syscall_func)(void); #ifdef FINSH_USING_SYMTAB + #ifdef __TI_COMPILER_VERSION__ #define __TI_FINSH_EXPORT_FUNCTION(f) PRAGMA(DATA_SECTION(f,"FSymTab")) #endif /* __TI_COMPILER_VERSION__ */ -#ifdef FINSH_USING_DESCRIPTION + #ifdef _MSC_VER -#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ +#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc, opt) \ const char __fsym_##cmd##_name[] = #cmd; \ const char __fsym_##cmd##_desc[] = #desc; \ __declspec(allocate("FSymTab$f")) \ const struct finsh_syscall __fsym_##cmd = \ { \ __fsym_##cmd##_name, \ - __fsym_##cmd##_desc, \ + FINSH_DESC(cmd, desc) \ + FINSH_COND(opt) \ (syscall_func)&name \ }; #pragma comment(linker, "/merge:FSymTab=mytext") @@ -41,63 +55,55 @@ typedef long (*syscall_func)(void); #else #define RT_NOBLOCKED #endif -#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ - __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \ - const char __fsym_##cmd##_name[] = #cmd; \ - const char __fsym_##cmd##_desc[] = #desc; \ - rt_used RT_NOBLOCKED const struct finsh_syscall __fsym_##cmd = \ +#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc, opt) \ + __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \ + const char __fsym_##cmd##_name[] = #cmd; \ + const char __fsym_##cmd##_desc[] = #desc; \ + rt_used RT_NOBLOCKED const struct finsh_syscall __fsym_##cmd = \ { \ __fsym_##cmd##_name, \ - __fsym_##cmd##_desc, \ + FINSH_DESC(cmd, desc) \ + FINSH_COND(opt) \ (syscall_func)&name \ }; + #else -#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ +#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc, opt) \ const char __fsym_##cmd##_name[] rt_section(".rodata.name") = #cmd; \ const char __fsym_##cmd##_desc[] rt_section(".rodata.name") = #desc; \ rt_used const struct finsh_syscall __fsym_##cmd rt_section("FSymTab")= \ { \ __fsym_##cmd##_name, \ - __fsym_##cmd##_desc, \ + FINSH_DESC(cmd, desc) \ + FINSH_COND(opt) \ (syscall_func)&name \ }; -#endif -#else -#ifdef _MSC_VER -#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ - const char __fsym_##cmd##_name[] = #cmd; \ - __declspec(allocate("FSymTab$f")) \ - const struct finsh_syscall __fsym_##cmd = \ - { \ - __fsym_##cmd##_name, \ - (syscall_func)&name \ - }; -#pragma comment(linker, "/merge:FSymTab=mytext") - -#elif defined(__TI_COMPILER_VERSION__) -#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ - __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \ - const char __fsym_##cmd##_name[] = #cmd; \ - const struct finsh_syscall __fsym_##cmd = \ - { \ - __fsym_##cmd##_name, \ - (syscall_func)&name \ - }; - -#else -#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ - const char __fsym_##cmd##_name[] = #cmd; \ - rt_used const struct finsh_syscall __fsym_##cmd rt_section("FSymTab")= \ - { \ - __fsym_##cmd##_name, \ - (syscall_func)&name \ - }; - -#endif -#endif /* end of FINSH_USING_DESCRIPTION */ +#endif /* _MSC_VER */ #endif /* end of FINSH_USING_SYMTAB */ + +#define __MSH_GET_MACRO(_1, _2, _3, _FUN, ...) _FUN +#define __MSH_GET_EXPORT_MACRO(_1, _2, _3, _4, _FUN, ...) _FUN + +#define _MSH_FUNCTION_CMD2(a0, a1) \ + MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, 0) + +#define _MSH_FUNCTION_CMD3_OPT(a0, a1, a2) \ + MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, a0##_msh_options) + +#define _MSH_FUNCTION_CMD3_NO_OPT(a0, a1, a2) \ + MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, 0) + +#define _MSH_FUNCTION_EXPORT_CMD3(a0, a1, a2) \ + MSH_FUNCTION_EXPORT_CMD(a0, a1, a2, 0) + +#define _MSH_FUNCTION_EXPORT_CMD4_OPT(a0, a1, a2, a3) \ + MSH_FUNCTION_EXPORT_CMD(a0, a1, a2, a0##_msh_options) + +#define _MSH_FUNCTION_EXPORT_CMD4_NO_OPT(a0, a1, a2, a3) \ + MSH_FUNCTION_EXPORT_CMD(a0, a1, a2, 0) + /** * @ingroup finsh * @@ -126,9 +132,18 @@ typedef long (*syscall_func)(void); * * @param command is the name of the command. * @param desc is the description of the command, which will show in help list. + * @param opt This is an option, enter any content to enable option completion */ -#define MSH_CMD_EXPORT(command, desc) \ - MSH_FUNCTION_EXPORT_CMD(command, command, desc) +/* MSH_CMD_EXPORT(command, desc) or MSH_CMD_EXPORT(command, desc, opt) */ +#ifdef FINSH_USING_OPTION_COMPLETION +#define MSH_CMD_EXPORT(...) \ + __MSH_GET_MACRO(__VA_ARGS__, _MSH_FUNCTION_CMD3_OPT, \ + _MSH_FUNCTION_CMD2)(__VA_ARGS__) +#else +#define MSH_CMD_EXPORT(...) \ + __MSH_GET_MACRO(__VA_ARGS__, _MSH_FUNCTION_CMD3_NO_OPT, \ + _MSH_FUNCTION_CMD2)(__VA_ARGS__) +#endif /* FINSH_USING_OPTION_COMPLETION */ /** * @ingroup msh @@ -138,9 +153,19 @@ typedef long (*syscall_func)(void); * @param command is the name of the command. * @param alias is the alias of the command. * @param desc is the description of the command, which will show in help list. + * @param opt This is an option, enter any content to enable option completion */ -#define MSH_CMD_EXPORT_ALIAS(command, alias, desc) \ - MSH_FUNCTION_EXPORT_CMD(command, alias, desc) +/* #define MSH_CMD_EXPORT_ALIAS(command, alias, desc) or + #define MSH_CMD_EXPORT_ALIAS(command, alias, desc, opt) */ +#ifdef FINSH_USING_OPTION_COMPLETION +#define MSH_CMD_EXPORT_ALIAS(...) \ + __MSH_GET_EXPORT_MACRO(__VA_ARGS__, _MSH_FUNCTION_EXPORT_CMD4_OPT, \ + _MSH_FUNCTION_EXPORT_CMD3)(__VA_ARGS__) +#else +#define MSH_CMD_EXPORT_ALIAS(...) \ + __MSH_GET_EXPORT_MACRO(__VA_ARGS__, _MSH_FUNCTION_EXPORT_CMD4_NO_OPT, \ + _MSH_FUNCTION_EXPORT_CMD3)(__VA_ARGS__) +#endif /* FINSH_USING_OPTION_COMPLETION */ /* system call table */ struct finsh_syscall @@ -149,6 +174,10 @@ struct finsh_syscall #if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) const char *desc; /* description of system call */ #endif + +#ifdef FINSH_USING_OPTION_COMPLETION + struct msh_cmd_opt *opt; +#endif syscall_func func; /* the function address of system call */ }; @@ -159,6 +188,31 @@ struct finsh_syscall_item struct finsh_syscall syscall; /* syscall */ }; +#ifdef FINSH_USING_OPTION_COMPLETION +typedef struct msh_cmd_opt +{ + rt_uint32_t id; + const char *name; + const char *des; +} msh_cmd_opt_t; + +#define CMD_OPTIONS_STATEMENT(command) static struct msh_cmd_opt command##_msh_options[]; +#define CMD_OPTIONS_NODE_START(command) static struct msh_cmd_opt command##_msh_options[] = { +#define CMD_OPTIONS_NODE(_id, _name, _des) {.id = _id, .name = #_name, .des = #_des}, +#define CMD_OPTIONS_NODE_END {0},}; + +void msh_opt_list_dump(void *options); +int msh_cmd_opt_id_get(int argc, char *argv[], void *options); +#define MSH_OPT_ID_GET(fun) msh_cmd_opt_id_get(argc, argv, (void*) fun##_msh_options) +#define MSH_OPT_DUMP(fun) msh_opt_list_dump((void*) fun##_msh_options) + +#else +#define CMD_OPTIONS_STATEMENT(command) +#define CMD_OPTIONS_NODE_START(command) +#define CMD_OPTIONS_NODE(_id, _name, _des) +#define CMD_OPTIONS_NODE_END +#endif + extern struct finsh_syscall_item *global_syscall_list; extern struct finsh_syscall *_syscall_table_begin, *_syscall_table_end; diff --git a/components/finsh/msh.c b/components/finsh/msh.c index 85fe04b8a7..9c5513f8b9 100644 --- a/components/finsh/msh.c +++ b/components/finsh/msh.c @@ -789,4 +789,162 @@ void msh_auto_complete(char *prefix) return ; } + +#ifdef FINSH_USING_OPTION_COMPLETION +static msh_cmd_opt_t *msh_get_cmd_opt(char *opt_str) +{ + struct finsh_syscall *index; + msh_cmd_opt_t *opt = RT_NULL; + char *ptr; + int len; + + if ((ptr = strchr(opt_str, ' '))) + { + len = ptr - opt_str; + } + else + { + len = strlen(opt_str); + } + + for (index = _syscall_table_begin; + index < _syscall_table_end; + FINSH_NEXT_SYSCALL(index)) + { + if (strncmp(index->name, opt_str, len) == 0 && index->name[len] == '\0') + { + opt = index->opt; + break; + } + } + + return opt; +} + +static int msh_get_argc(char *prefix, char **last_argv) +{ + int argc = 0; + char *ch = prefix; + + while (*ch) + { + if ((*ch == ' ') && *(ch + 1) && (*(ch + 1) != ' ')) + { + *last_argv = ch + 1; + argc++; + } + ch++; + } + + return argc; +} + +static void msh_opt_complete(char *opts_str, struct msh_cmd_opt *cmd_opt) +{ + struct msh_cmd_opt *opt = cmd_opt; + const char *name_ptr = RT_NULL; + int min_length = 0, length, opts_str_len; + + opts_str_len = strlen(opts_str); + + for (opt = cmd_opt; opt->id; opt++) + { + if (!strncmp(opt->name, opts_str, opts_str_len)) + { + if (min_length == 0) + { + /* set name_ptr */ + name_ptr = opt->name; + /* set initial length */ + min_length = strlen(name_ptr); + } + + length = str_common(name_ptr, opt->name); + if (length < min_length) + { + min_length = length; + } + + rt_kprintf("%s\n", opt->name); + } + } + rt_kprintf("\n"); + + if (name_ptr != NULL) + { + strncpy(opts_str, name_ptr, min_length); + } +} + +static void msh_opt_help(msh_cmd_opt_t *cmd_opt) +{ + msh_cmd_opt_t *opt = cmd_opt; + + for (; opt->id; opt++) + { + rt_kprintf("%-16s - %s\n", opt->name, opt->des); + } + rt_kprintf("\n"); +} + +void msh_opt_auto_complete(char *prefix) +{ + int argc; + char *opt_str = RT_NULL; + msh_cmd_opt_t *opt = RT_NULL; + + if ((argc = msh_get_argc(prefix, &opt_str))) + { + opt = msh_get_cmd_opt(prefix); + } + else if (!msh_get_cmd(prefix, strlen(prefix)) && (' ' == prefix[strlen(prefix) - 1])) + { + opt = msh_get_cmd_opt(prefix); + } + + if (opt && opt->id) + { + switch (argc) + { + case 0: + msh_opt_help(opt); + break; + + case 1: + msh_opt_complete(opt_str, opt); + break; + + default: + break; + } + } +} + +int msh_cmd_opt_id_get(int argc, char *argv[], void *options) +{ + msh_cmd_opt_t *opt = (msh_cmd_opt_t *) options; + int opt_id; + + for (opt_id = 0; (argc >= 2) && opt && opt->id; opt++) + { + if (!strcmp(opt->name, argv[1])) + { + opt_id = opt->id; + break; + } + } + + return opt_id; +} + +void msh_opt_list_dump(void *options) +{ + msh_cmd_opt_t *opt = (msh_cmd_opt_t *) options; + + for (; opt && opt->id; opt++) + { + rt_kprintf(" %-16s - %s\n", opt->name, opt->des); + } +} +#endif /* FINSH_USING_OPTION_COMPLETION */ #endif /* RT_USING_FINSH */ diff --git a/components/finsh/msh.h b/components/finsh/msh.h index b9b037586e..28652aef66 100644 --- a/components/finsh/msh.h +++ b/components/finsh/msh.h @@ -19,4 +19,8 @@ void msh_auto_complete(char *prefix); int msh_exec_module(const char *cmd_line, int size); int msh_exec_script(const char *cmd_line, int size); +#ifdef FINSH_USING_OPTION_COMPLETION +void msh_opt_auto_complete(char *prefix); + +#endif /* FINSH_USING_OPTION_COMPLETION */ #endif diff --git a/components/finsh/shell.c b/components/finsh/shell.c index b55eb32316..db5f286285 100644 --- a/components/finsh/shell.c +++ b/components/finsh/shell.c @@ -381,6 +381,10 @@ static void shell_auto_complete(char *prefix) rt_kprintf("\n"); msh_auto_complete(prefix); +#ifdef FINSH_USING_OPTION_COMPLETION + msh_opt_auto_complete(prefix); +#endif + rt_kprintf("%s%s", FINSH_PROMPT, prefix); }