RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
msh.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2013-03-30 Bernard the first verion for finsh
9 * 2014-01-03 Bernard msh can execute module.
10 * 2017-07-19 Aubr.Cool limit argc to RT_FINSH_ARG_MAX
11 */
12#include <rtthread.h>
13#include <string.h>
14#include <errno.h>
15
16#ifdef RT_USING_FINSH
17
18#ifndef FINSH_ARG_MAX
19#define FINSH_ARG_MAX 8
20#endif /* FINSH_ARG_MAX */
21
22#include "msh.h"
23#include "shell.h"
24#ifdef DFS_USING_POSIX
25#include <dfs_file.h>
26#include <unistd.h>
27#include <fcntl.h>
28#endif /* DFS_USING_POSIX */
29#ifdef RT_USING_MODULE
30#include <dlmodule.h>
31#endif /* RT_USING_MODULE */
32
33typedef int (*cmd_function_t)(int argc, char **argv);
34
35static int msh_help(int argc, char **argv)
36{
37 rt_kprintf("RT-Thread shell commands:\n");
38 {
39 struct finsh_syscall *index;
40
41 for (index = _syscall_table_begin;
42 index < _syscall_table_end;
43 FINSH_NEXT_SYSCALL(index))
44 {
45#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
46 rt_kprintf("%-16s - %s\n", index->name, index->desc);
47#else
48 rt_kprintf("%s ", index->name);
49#endif
50 }
51 }
52 rt_kprintf("\n");
53
54 return 0;
55}
56MSH_CMD_EXPORT_ALIAS(msh_help, help, RT-Thread shell help);
57
58#ifdef MSH_USING_BUILT_IN_COMMANDS
59static int cmd_ps(int argc, char **argv)
60{
61 extern long list_thread(void);
62 extern int list_module(void);
63
64#ifdef RT_USING_MODULE
65 if ((argc == 2) && (strcmp(argv[1], "-m") == 0))
66 list_module();
67 else
68#endif
70 return 0;
71}
72MSH_CMD_EXPORT_ALIAS(cmd_ps, ps, List threads in the system);
73
74#ifdef RT_USING_HEAP
75static int cmd_free(int argc, char **argv)
76{
77#ifdef RT_USING_MEMHEAP_AS_HEAP
78 extern void list_memheap(void);
79 list_memheap();
80#else
81 rt_size_t total = 0, used = 0, max_used = 0;
82
83 rt_memory_info(&total, &used, &max_used);
84 rt_kprintf("total : %d\n", total);
85 rt_kprintf("used : %d\n", used);
86 rt_kprintf("maximum : %d\n", max_used);
87 rt_kprintf("available: %d\n", total - used);
88#endif
89 return 0;
90}
91MSH_CMD_EXPORT_ALIAS(cmd_free, free, Show the memory usage in the system);
92#endif /* RT_USING_HEAP */
93
94#if RT_CPUS_NR > 1
95static int cmd_bind(int argc, char **argv)
96{
97 rt_err_t result;
98 rt_ubase_t thread_id;
99 rt_ubase_t core_id;
100 rt_thread_t thread;
101 char *endptr;
102
103 if (argc != 3)
104 {
105 rt_kprintf("Usage: bind <thread_id> <core_id>\n");
106 return 0;
107 }
108
109 /* Parse thread_id */
110 thread_id = (rt_ubase_t)strtoul(argv[1], &endptr, 0);
111 if (*endptr != '\0')
112 {
113 rt_kprintf("Error: Invalid thread ID '%s'\n", argv[1]);
114 return 0;
115 }
116
117 /* Parse core_id */
118 core_id = (rt_uint8_t)strtoul(argv[2], &endptr, 0);
119 if (*endptr != '\0')
120 {
121 rt_kprintf("Error: Invalid core ID '%s'\n", argv[2]);
122 return 0;
123 }
124
125 thread = (rt_thread_t)thread_id;
126
128 {
129 rt_kprintf("Error: Invalid thread ID %#lx\n", thread_id);
130 return 0;
131 }
132
133 result = rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void *)core_id);
134 if (result == RT_EOK)
135 {
136 rt_kprintf("Thread 0x%lx bound to core %d successfully\n",
137 thread_id, core_id);
138 }
139 else
140 {
141 rt_kprintf("Failed to bind thread 0x%lx to core %d\n",
142 thread_id, core_id);
143 }
144 return 0;
145}
146MSH_CMD_EXPORT_ALIAS(cmd_bind, bind, Binding thread to core);
147#endif /* RT_CPUS_NR > 1 */
148
149#endif /* MSH_USING_BUILT_IN_COMMANDS */
150
151static int msh_split(char *cmd, rt_size_t length, char *argv[FINSH_ARG_MAX])
152{
153 char *ptr;
154 rt_size_t position;
155 rt_size_t argc;
156 rt_size_t i;
157
158 ptr = cmd;
159 position = 0;
160 argc = 0;
161
162 while (position < length)
163 {
164 /* strip bank and tab */
165 while ((*ptr == ' ' || *ptr == '\t') && position < length)
166 {
167 *ptr = '\0';
168 ptr ++;
169 position ++;
170 }
171
172 if (argc >= FINSH_ARG_MAX)
173 {
174 rt_kprintf("Too many args ! We only Use:\n");
175 for (i = 0; i < argc; i++)
176 {
177 rt_kprintf("%s ", argv[i]);
178 }
179 rt_kprintf("\n");
180 break;
181 }
182
183 if (position >= length) break;
184
185 /* handle string */
186 if (*ptr == '"')
187 {
188 ptr ++;
189 position ++;
190 argv[argc] = ptr;
191 argc ++;
192
193 /* skip this string */
194 while (*ptr != '"' && position < length)
195 {
196 if (*ptr == '\\')
197 {
198 if (*(ptr + 1) == '"')
199 {
200 ptr ++;
201 position ++;
202 }
203 }
204 ptr ++;
205 position ++;
206 }
207 if (position >= length) break;
208
209 /* skip '"' */
210 *ptr = '\0';
211 ptr ++;
212 position ++;
213 }
214 else
215 {
216 argv[argc] = ptr;
217 argc ++;
218 while ((*ptr != ' ' && *ptr != '\t') && position < length)
219 {
220 ptr ++;
221 position ++;
222 }
223 if (position >= length) break;
224 }
225 }
226
227 return argc;
228}
229
230static cmd_function_t msh_get_cmd(char *cmd, int size)
231{
232 struct finsh_syscall *index;
233 cmd_function_t cmd_func = RT_NULL;
234
235 for (index = _syscall_table_begin;
236 index < _syscall_table_end;
237 FINSH_NEXT_SYSCALL(index))
238 {
239 if (strncmp(index->name, cmd, size) == 0 &&
240 index->name[size] == '\0')
241 {
242 cmd_func = (cmd_function_t)index->func;
243 break;
244 }
245 }
246
247 return cmd_func;
248}
249
250#if defined(RT_USING_MODULE) && defined(DFS_USING_POSIX)
251/* Return 0 on module executed. Other value indicate error.
252 */
253int msh_exec_module(const char *cmd_line, int size)
254{
255 int ret;
256 int fd = -1;
257 char *pg_name;
258 int length, cmd_length = 0;
259
260 if (size == 0)
261 return -RT_ERROR;
262 /* get the length of command0 */
263 while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size)
264 cmd_length ++;
265
266 /* get name length */
267 length = cmd_length + 32;
268
269 /* allocate program name memory */
270 pg_name = (char *) rt_malloc(length + 3);
271 if (pg_name == RT_NULL)
272 return -RT_ENOMEM;
273
274 /* copy command0 */
275 rt_memcpy(pg_name, cmd_line, cmd_length);
276 pg_name[cmd_length] = '\0';
277
278 if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL)
279 {
280 /* try to open program */
281 fd = open(pg_name, O_RDONLY, 0);
282
283 /* search in /bin path */
284 if (fd < 0)
285 {
286 rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line);
287 fd = open(pg_name, O_RDONLY, 0);
288 }
289 }
290 else
291 {
292 /* add .mo and open program */
293
294 /* try to open program */
295 strcat(pg_name, ".mo");
296 fd = open(pg_name, O_RDONLY, 0);
297
298 /* search in /bin path */
299 if (fd < 0)
300 {
301 rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line);
302 fd = open(pg_name, O_RDONLY, 0);
303 }
304 }
305
306 if (fd >= 0)
307 {
308 /* found program */
309 close(fd);
310 dlmodule_exec(pg_name, cmd_line, size);
311 ret = 0;
312 }
313 else
314 {
315 ret = -1;
316 }
317
318 rt_free(pg_name);
319 return ret;
320}
321#endif
322
323static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp)
324{
325 int argc;
326 rt_size_t cmd0_size = 0;
327 cmd_function_t cmd_func;
328 char *argv[FINSH_ARG_MAX];
329
330 RT_ASSERT(cmd);
331 RT_ASSERT(retp);
332
333 /* find the size of first command */
334 while (cmd0_size < length && (cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t'))
335 cmd0_size ++;
336 if (cmd0_size == 0)
337 return -RT_ERROR;
338
339 cmd_func = msh_get_cmd(cmd, cmd0_size);
340 if (cmd_func == RT_NULL)
341 return -RT_ERROR;
342
343 /* split arguments */
344 rt_memset(argv, 0x00, sizeof(argv));
345 argc = msh_split(cmd, length, argv);
346 if (argc == 0)
347 return -RT_ERROR;
348
349 /* exec this command */
350 *retp = cmd_func(argc, argv);
351 return 0;
352}
353
354#if defined(RT_USING_SMART) && defined(DFS_USING_POSIX)
355#include <lwp.h>
356/* check whether a file of the given path exits */
357static rt_bool_t _msh_lwp_cmd_exists(const char *path)
358{
359 int fd = -1;
360 fd = open(path, O_RDONLY, 0);
361 if (fd < 0)
362 {
363 return RT_FALSE;
364 }
365 close(fd);
366 return RT_TRUE;
367}
368
369/*
370 * search for the file named "pg_name" or "pg_name.elf" at the given directory,
371 * and return its path. return NULL when not found.
372 */
373static char *_msh_exec_search_path(const char *path, const char *pg_name)
374{
375 char *path_buffer = RT_NULL;
376 ssize_t pg_len = strlen(pg_name);
377 ssize_t base_len = 0;
378
379 if (path)
380 {
381 base_len = strlen(path);
382 }
383
384 path_buffer = rt_malloc(base_len + pg_len + 6);
385 if (path_buffer == RT_NULL)
386 {
387 return RT_NULL; /* no mem */
388 }
389
390 if (base_len > 0)
391 {
392 memcpy(path_buffer, path, base_len);
393 path_buffer[base_len] = '/';
394 path_buffer[base_len + 1] = '\0';
395 }
396 else
397 {
398 *path_buffer = '\0';
399 }
400 strcat(path_buffer, pg_name);
401
402 if (_msh_lwp_cmd_exists(path_buffer))
403 {
404 return path_buffer;
405 }
406
407 if (strstr(path_buffer, ".elf") != NULL)
408 {
409 goto not_found;
410 }
411
412 strcat(path_buffer, ".elf");
413 if (_msh_lwp_cmd_exists(path_buffer))
414 {
415 return path_buffer;
416 }
417
418not_found:
419 rt_free(path_buffer);
420 return RT_NULL;
421}
422
423/*
424 * search for the file named "pg_name" or "pg_name.elf" at each env path,
425 * and return its path. return NULL when not found.
426 */
427static char *_msh_exec_search_env(const char *pg_name)
428{
429 char *result = RT_NULL;
430 char *exec_path = RT_NULL;
431 char *search_path = RT_NULL;
432 char *pos = RT_NULL;
433 char tmp_ch = '\0';
434
435 if (!(exec_path = getenv("PATH")))
436 {
437 return RT_NULL;
438 }
439
440 /* exec path may need to be modified */
441 if (!(exec_path = strdup(exec_path)))
442 {
443 return RT_NULL;
444 }
445
446 pos = exec_path;
447 search_path = exec_path;
448
449 /* walk through the entire exec_path until finding the program wanted
450 or hitting its end */
451 while (1)
452 {
453 /* env paths are seperated by ':' */
454 if (*pos == ':' || *pos == '\0')
455 {
456 tmp_ch = *pos;
457 *pos = '\0';
458
459 result = _msh_exec_search_path(search_path, pg_name);
460 if (result || tmp_ch == '\0')
461 {
462 goto ret;
463 }
464
465 pos++;
466 search_path = pos;
467 continue;
468 }
469
470 pos++;
471 }
472
473 /* release the duplicated exec_path and return */
474ret:
475 rt_free(exec_path);
476 return result;
477}
478
479int _msh_exec_lwp(int debug, char *cmd, rt_size_t length)
480{
481 int argc;
482 int cmd0_size = 0;
483 char *argv[FINSH_ARG_MAX];
484 char *pg_name;
485 int ret;
486
487 /* find the size of first command */
488 while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
489 cmd0_size ++;
490 if (cmd0_size == 0)
491 return -1;
492
493 /* split arguments */
494 rt_memset(argv, 0x00, sizeof(argv));
495 argc = msh_split(cmd, length, argv);
496 if (argc == 0)
497 return -1;
498
499 /* try to find program in working directory */
500 pg_name = _msh_exec_search_path("", argv[0]);
501 if (pg_name)
502 {
503 goto found_program;
504 }
505
506 /* only check these paths when the first argument doesn't contain path
507 seperator */
508 if (strstr(argv[0], "/"))
509 {
510 return -1;
511 }
512
513 /* try to find program in /bin */
514 pg_name = _msh_exec_search_path("/bin", argv[0]);
515 if (pg_name)
516 {
517 goto found_program;
518 }
519
520 /* try to find program in dirs registered to env path */
521 pg_name = _msh_exec_search_env(argv[0]);
522 if (pg_name)
523 {
524 goto found_program;
525 }
526
527 /* not found in anywhere */
528 return -1;
529
530 /* found program */
531found_program:
532 ret = exec(pg_name, debug, argc, argv);
533 rt_free(pg_name);
534
535 return ret;
536}
537#endif
538
539
540int msh_exec(char *cmd, rt_size_t length)
541{
542 int cmd_ret = 0;
543
544 /* strim the beginning of command */
545 while ((length > 0) && (*cmd == ' ' || *cmd == '\t'))
546 {
547 cmd++;
548 length--;
549 }
550
551 if (length == 0)
552 return 0;
553
554 /* Exec sequence:
555 * 1. built-in command
556 * 2. module(if enabled)
557 */
558 if (_msh_exec_cmd(cmd, length, &cmd_ret) == 0)
559 {
560 if(cmd_ret < 0)
561 {
562 rt_kprintf("%s: command failed %d.\n", cmd, cmd_ret);
563 }
564 return cmd_ret;
565 }
566#ifdef DFS_USING_POSIX
567#ifdef DFS_USING_WORKDIR
568 if (msh_exec_script(cmd, length) == 0)
569 {
570 return 0;
571 }
572#endif
573
574#ifdef RT_USING_MODULE
575 if (msh_exec_module(cmd, length) == 0)
576 {
577 return 0;
578 }
579#endif /* RT_USING_MODULE */
580
581#ifdef RT_USING_SMART
582 /* exec from msh_exec , debug = 0*/
583 /* _msh_exec_lwp return is pid , <= 0 means failed */
584 cmd_ret = _msh_exec_lwp(0, cmd, length);
585 if (cmd_ret > 0)
586 {
587 return 0;
588 }
589#endif /* RT_USING_SMART */
590#endif /* DFS_USING_POSIX */
591
592 /* truncate the cmd at the first space. */
593 {
594 char *tcmd;
595 tcmd = cmd;
596 while (*tcmd != ' ' && *tcmd != '\0')
597 {
598 tcmd++;
599 }
600 *tcmd = '\0';
601 }
602#ifdef RT_USING_SMART
603 if (cmd_ret == -EACCES)
604 {
605 rt_kprintf("%s: Permission denied.\n", cmd);
606 }
607 else
608#endif
609 {
610 rt_kprintf("%s: command not found.\n", cmd);
611 }
612 return -1;
613}
614
615static int str_common(const char *str1, const char *str2)
616{
617 const char *str = str1;
618
619 while ((*str != 0) && (*str2 != 0) && (*str == *str2))
620 {
621 str ++;
622 str2 ++;
623 }
624
625 return (str - str1);
626}
627
628#ifdef DFS_USING_POSIX
629void msh_auto_complete_path(char *path)
630{
631 DIR *dir = RT_NULL;
632 struct dirent *dirent = RT_NULL;
633 char *full_path, *ptr, *index;
634
635 if (!path)
636 return;
637
638 full_path = (char *)rt_malloc(256);
639 if (full_path == RT_NULL) return; /* out of memory */
640
641 if (*path != '/')
642 {
643 getcwd(full_path, 256);
644 if (full_path[rt_strlen(full_path) - 1] != '/')
645 strcat(full_path, "/");
646 }
647 else *full_path = '\0';
648
649 index = RT_NULL;
650 ptr = path;
651 for (;;)
652 {
653 if (*ptr == '/') index = ptr + 1;
654 if (!*ptr) break;
655
656 ptr ++;
657 }
658 if (index == RT_NULL) index = path;
659
660 if (index != RT_NULL)
661 {
662 char *dest = index;
663
664 /* fill the parent path */
665 ptr = full_path;
666 while (*ptr) ptr ++;
667
668 for (index = path; index != dest;)
669 *ptr++ = *index++;
670 *ptr = '\0';
671
672 dir = opendir(full_path);
673 if (dir == RT_NULL) /* open directory failed! */
674 {
675 rt_free(full_path);
676 return;
677 }
678
679 /* restore the index position */
680 index = dest;
681 }
682
683 /* auto complete the file or directory name */
684 if (*index == '\0') /* display all of files and directories */
685 {
686 for (;;)
687 {
688 dirent = readdir(dir);
689 if (dirent == RT_NULL) break;
690
691 rt_kprintf("%s\n", dirent->d_name);
692 }
693 }
694 else
695 {
696 int multi = 0;
697 rt_size_t length, min_length;
698
699 min_length = 0;
700 for (;;)
701 {
702 dirent = readdir(dir);
703 if (dirent == RT_NULL) break;
704
705 /* matched the prefix string */
706 if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
707 {
708 multi ++;
709 if (min_length == 0)
710 {
711 min_length = rt_strlen(dirent->d_name);
712 /* save dirent name */
713 strcpy(full_path, dirent->d_name);
714 }
715
716 length = str_common(dirent->d_name, full_path);
717
718 if (length < min_length)
719 {
720 min_length = length;
721 }
722 }
723 }
724
725 if (min_length)
726 {
727 if (multi > 1)
728 {
729 /* list the candidate */
730 rewinddir(dir);
731
732 for (;;)
733 {
734 dirent = readdir(dir);
735 if (dirent == RT_NULL) break;
736
737 if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
738 rt_kprintf("%s\n", dirent->d_name);
739 }
740 }
741
742 length = index - path;
743 rt_memcpy(index, full_path, min_length);
744 path[length + min_length] = '\0';
745
746 /* try to locate folder */
747 if (multi == 1)
748 {
749 struct stat buffer = {0};
750 if ((stat(path, &buffer) == 0))
751 {
752 if (S_ISDIR(buffer.st_mode))
753 {
754 strcat(path, "/");
755 }
756 else if (S_ISLNK(buffer.st_mode))
757 {
758 DIR *link_dir = opendir(path);
759 if (link_dir)
760 {
761 closedir(link_dir);
762 strcat(path, "/");
763 }
764 }
765 }
766 }
767 }
768 }
769
770 closedir(dir);
771 rt_free(full_path);
772}
773#endif /* DFS_USING_POSIX */
774
775void msh_auto_complete(char *prefix)
776{
777 int length, min_length;
778 const char *name_ptr, *cmd_name;
779 struct finsh_syscall *index;
780
781 min_length = 0;
782 name_ptr = RT_NULL;
783
784 if (*prefix == '\0')
785 {
786 msh_help(0, RT_NULL);
787 return;
788 }
789
790#ifdef DFS_USING_POSIX
791 /* check whether a spare in the command */
792 {
793 char *ptr;
794
795 ptr = prefix + rt_strlen(prefix);
796 while (ptr != prefix)
797 {
798 if (*ptr == ' ')
799 {
800 msh_auto_complete_path(ptr + 1);
801 break;
802 }
803
804 ptr --;
805 }
806#if defined(RT_USING_MODULE) || defined(RT_USING_SMART)
807 /* There is a chance that the user want to run the module directly. So
808 * try to complete the file names. If the completed path is not a
809 * module, the system won't crash anyway. */
810 if (ptr == prefix)
811 {
812 msh_auto_complete_path(ptr);
813 }
814#endif /* RT_USING_MODULE */
815 }
816#endif /* DFS_USING_POSIX */
817
818 /* checks in internal command */
819 {
820 for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
821 {
822 /* skip finsh shell function */
823 cmd_name = (const char *) index->name;
824 if (strncmp(prefix, cmd_name, strlen(prefix)) == 0)
825 {
826 if (min_length == 0)
827 {
828 /* set name_ptr */
829 name_ptr = cmd_name;
830 /* set initial length */
831 min_length = strlen(name_ptr);
832 }
833
834 length = str_common(name_ptr, cmd_name);
835 if (length < min_length)
836 min_length = length;
837
838 rt_kprintf("%s\n", cmd_name);
839 }
840 }
841 }
842
843 /* auto complete string */
844 if (name_ptr != NULL)
845 {
846 rt_strncpy(prefix, name_ptr, min_length);
847 }
848
849 return ;
850}
851
852#ifdef FINSH_USING_OPTION_COMPLETION
853static msh_cmd_opt_t *msh_get_cmd_opt(char *opt_str)
854{
855 struct finsh_syscall *index;
856 msh_cmd_opt_t *opt = RT_NULL;
857 char *ptr;
858 int len;
859
860 ptr = strchr(opt_str, ' ');
861 if (ptr)
862 {
863 len = ptr - opt_str;
864 }
865 else
866 {
867 len = strlen(opt_str);
868 }
869
870 for (index = _syscall_table_begin;
871 index < _syscall_table_end;
872 FINSH_NEXT_SYSCALL(index))
873 {
874 if (strncmp(index->name, opt_str, len) == 0 && index->name[len] == '\0')
875 {
876 opt = index->opt;
877 break;
878 }
879 }
880
881 return opt;
882}
883
884static int msh_get_argc(char *prefix, char **last_argv)
885{
886 int argc = 0;
887 char *ch = prefix;
888
889 while (*ch)
890 {
891 if ((*ch == ' ') && *(ch + 1) && (*(ch + 1) != ' '))
892 {
893 *last_argv = ch + 1;
894 argc++;
895 }
896 ch++;
897 }
898
899 return argc;
900}
901
902static void msh_opt_complete(char *opts_str, struct msh_cmd_opt *cmd_opt)
903{
904 struct msh_cmd_opt *opt = cmd_opt;
905 const char *name_ptr = RT_NULL;
906 int min_length = 0, length, opts_str_len;
907
908 opts_str_len = strlen(opts_str);
909
910 for (opt = cmd_opt; opt->id; opt++)
911 {
912 if (!strncmp(opt->name, opts_str, opts_str_len))
913 {
914 if (min_length == 0)
915 {
916 /* set name_ptr */
917 name_ptr = opt->name;
918 /* set initial length */
919 min_length = strlen(name_ptr);
920 }
921
922 length = str_common(name_ptr, opt->name);
923 if (length < min_length)
924 {
925 min_length = length;
926 }
927
928 rt_kprintf("%s\n", opt->name);
929 }
930 }
931 rt_kprintf("\n");
932
933 if (name_ptr != NULL)
934 {
935 strncpy(opts_str, name_ptr, min_length);
936 }
937}
938
939static void msh_opt_help(msh_cmd_opt_t *cmd_opt)
940{
941 msh_cmd_opt_t *opt = cmd_opt;
942
943 for (; opt->id; opt++)
944 {
945 rt_kprintf("%-16s - %s\n", opt->name, opt->des);
946 }
947 rt_kprintf("\n");
948}
949
950void msh_opt_auto_complete(char *prefix)
951{
952 int argc;
953 char *opt_str = RT_NULL;
954 msh_cmd_opt_t *opt = RT_NULL;
955
956 argc = msh_get_argc(prefix, &opt_str);
957 if (argc)
958 {
959 opt = msh_get_cmd_opt(prefix);
960 }
961 else if (!msh_get_cmd(prefix, strlen(prefix)) && (' ' == prefix[strlen(prefix) - 1]))
962 {
963 opt = msh_get_cmd_opt(prefix);
964 }
965
966 if (opt && opt->id)
967 {
968 switch (argc)
969 {
970 case 0:
971 msh_opt_help(opt);
972 break;
973
974 case 1:
975 msh_opt_complete(opt_str, opt);
976 break;
977
978 default:
979 break;
980 }
981 }
982}
983
984int msh_cmd_opt_id_get(int argc, char *argv[], void *options)
985{
986 msh_cmd_opt_t *opt = (msh_cmd_opt_t *) options;
987 int opt_id;
988
989 for (opt_id = 0; (argc >= 2) && opt && opt->id; opt++)
990 {
991 if (!strcmp(opt->name, argv[1]))
992 {
993 opt_id = opt->id;
994 break;
995 }
996 }
997
998 return opt_id;
999}
1000
1001void msh_opt_list_dump(void *options)
1002{
1003 msh_cmd_opt_t *opt = (msh_cmd_opt_t *) options;
1004
1005 for (; opt && opt->id; opt++)
1006 {
1007 rt_kprintf(" %-16s - %s\n", opt->name, opt->des);
1008 }
1009}
1010#endif /* FINSH_USING_OPTION_COMPLETION */
1011#endif /* RT_USING_FINSH */
long list_thread(void)
定义 cmd.c:159
struct finsh_syscall * _syscall_table_end
#define FINSH_NEXT_SYSCALL(index)
struct finsh_syscall * _syscall_table_begin
定义 shell.c:50
int closedir(DIR *d)
void rewinddir(DIR *d)
struct dirent * readdir(DIR *d)
DIR * opendir(const char *name)
int open(const char *file, int flags,...)
int close(int fd)
int stat(const char *file, struct stat *buf)
char * getcwd(char *buf, size_t size)
rt_uint8_t rt_object_get_type(rt_object_t object)
This function will return the type of object without RT_Object_Class_Static flag.
@ RT_Object_Class_Thread
#define rt_kprintf(...)
#define RT_ASSERT(EX)
rt_weak void rt_free(void *ptr)
This function will release the previously allocated memory block by rt_malloc. The released memory bl...
rt_weak void rt_memory_info(rt_size_t *total, rt_size_t *used, rt_size_t *max_used)
This function will caculate the total memory, the used memory, and the max used memory.
rt_weak void * rt_malloc(rt_size_t size)
Allocate a block of memory with a minimum of 'size' bytes.
#define RT_THREAD_CTRL_BIND_CPU
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
This function will control thread behaviors according to control command.
struct rt_thread * rt_thread_t
#define MSH_CMD_EXPORT_ALIAS(...)
int msh_exec(char *cmd, rt_size_t length)
定义 msh.c:540
void msh_auto_complete(char *prefix)
定义 msh.c:775
int(* cmd_function_t)(int argc, char **argv)
定义 msh.c:33
#define FINSH_ARG_MAX
定义 msh.c:19
int msh_exec_script(const char *cmd_line, int size)
int msh_exec_module(const char *cmd_line, int size)
int rt_bool_t
rt_base_t rt_err_t
unsigned char rt_uint8_t
#define RT_TRUE
rt_ubase_t rt_size_t
#define RT_FALSE
rt_uint32_t rt_ubase_t
#define RT_NULL
struct finsh_shell * shell
定义 shell.c:54
struct rt_object parent