瀏覽代碼

【msh】新增msh自动补全子选项特性 (#8086)

wangqinglin 1 年之前
父節點
當前提交
2d630e38d7
共有 6 個文件被更改,包括 363 次插入48 次删除
  1. 4 0
      components/finsh/Kconfig
  2. 92 1
      components/finsh/cmd.c
  3. 101 47
      components/finsh/finsh.h
  4. 158 0
      components/finsh/msh.c
  5. 4 0
      components/finsh/msh.h
  6. 4 0
      components/finsh/shell.c

+ 4 - 0
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

+ 92 - 1
components/finsh/cmd.c

@@ -39,6 +39,7 @@
 #ifdef RT_USING_FINSH
 #include <finsh.h>
 
+#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 */

+ 101 - 47
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,62 +55,54 @@ 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")
+#endif  /* _MSC_VER */
+#endif /* end of FINSH_USING_SYMTAB */
 
-#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                                             \
-                };
+#define __MSH_GET_MACRO(_1, _2, _3, _FUN, ...)  _FUN
+#define __MSH_GET_EXPORT_MACRO(_1, _2, _3, _4, _FUN, ...) _FUN
 
-#endif
-#endif /* end of FINSH_USING_DESCRIPTION */
-#endif /* end of FINSH_USING_SYMTAB */
+#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;
 

+ 158 - 0
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 */

+ 4 - 0
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

+ 4 - 0
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);
 }