xref: /nrf52832-nimble/rt-thread/components/finsh/msh.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2013-03-30     Bernard      the first verion for finsh
9*10465441SEvalZero  * 2014-01-03     Bernard      msh can execute module.
10*10465441SEvalZero  * 2017-07-19     Aubr.Cool    limit argc to RT_FINSH_ARG_MAX
11*10465441SEvalZero  */
12*10465441SEvalZero #include <rtthread.h>
13*10465441SEvalZero 
14*10465441SEvalZero #ifdef FINSH_USING_MSH
15*10465441SEvalZero 
16*10465441SEvalZero #include "msh.h"
17*10465441SEvalZero #include <finsh.h>
18*10465441SEvalZero #include <shell.h>
19*10465441SEvalZero 
20*10465441SEvalZero #ifdef RT_USING_DFS
21*10465441SEvalZero #include <dfs_posix.h>
22*10465441SEvalZero #endif
23*10465441SEvalZero 
24*10465441SEvalZero #ifdef RT_USING_MODULE
25*10465441SEvalZero #include <dlmodule.h>
26*10465441SEvalZero #endif
27*10465441SEvalZero 
28*10465441SEvalZero #ifndef FINSH_ARG_MAX
29*10465441SEvalZero #define FINSH_ARG_MAX    8
30*10465441SEvalZero #endif
31*10465441SEvalZero 
32*10465441SEvalZero typedef int (*cmd_function_t)(int argc, char **argv);
33*10465441SEvalZero 
34*10465441SEvalZero #ifdef FINSH_USING_MSH
35*10465441SEvalZero #ifdef FINSH_USING_MSH_ONLY
msh_is_used(void)36*10465441SEvalZero rt_bool_t msh_is_used(void)
37*10465441SEvalZero {
38*10465441SEvalZero     return RT_TRUE;
39*10465441SEvalZero }
40*10465441SEvalZero #else
41*10465441SEvalZero #ifdef FINSH_USING_MSH_DEFAULT
42*10465441SEvalZero static rt_bool_t __msh_state = RT_TRUE;
43*10465441SEvalZero #else
44*10465441SEvalZero static rt_bool_t __msh_state = RT_FALSE;
45*10465441SEvalZero #endif
msh_is_used(void)46*10465441SEvalZero rt_bool_t msh_is_used(void)
47*10465441SEvalZero {
48*10465441SEvalZero     return __msh_state;
49*10465441SEvalZero }
50*10465441SEvalZero 
msh_exit(int argc,char ** argv)51*10465441SEvalZero static int msh_exit(int argc, char **argv)
52*10465441SEvalZero {
53*10465441SEvalZero     /* return to finsh shell mode */
54*10465441SEvalZero     __msh_state = RT_FALSE;
55*10465441SEvalZero     return 0;
56*10465441SEvalZero }
57*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(msh_exit, __cmd_exit, return to RT-Thread shell mode.);
58*10465441SEvalZero 
msh_enter(void)59*10465441SEvalZero static int msh_enter(void)
60*10465441SEvalZero {
61*10465441SEvalZero     /* enter module shell mode */
62*10465441SEvalZero     __msh_state = RT_TRUE;
63*10465441SEvalZero     return 0;
64*10465441SEvalZero }
65*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(msh_enter, msh, use module shell);
66*10465441SEvalZero #endif
67*10465441SEvalZero 
msh_help(int argc,char ** argv)68*10465441SEvalZero int msh_help(int argc, char **argv)
69*10465441SEvalZero {
70*10465441SEvalZero     rt_kprintf("RT-Thread shell commands:\n");
71*10465441SEvalZero     {
72*10465441SEvalZero         struct finsh_syscall *index;
73*10465441SEvalZero 
74*10465441SEvalZero         for (index = _syscall_table_begin;
75*10465441SEvalZero                 index < _syscall_table_end;
76*10465441SEvalZero                 FINSH_NEXT_SYSCALL(index))
77*10465441SEvalZero         {
78*10465441SEvalZero             if (strncmp(index->name, "__cmd_", 6) != 0) continue;
79*10465441SEvalZero #if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
80*10465441SEvalZero             rt_kprintf("%-16s - %s\n", &index->name[6], index->desc);
81*10465441SEvalZero #else
82*10465441SEvalZero             rt_kprintf("%s ", &index->name[6]);
83*10465441SEvalZero #endif
84*10465441SEvalZero         }
85*10465441SEvalZero     }
86*10465441SEvalZero     rt_kprintf("\n");
87*10465441SEvalZero 
88*10465441SEvalZero     return 0;
89*10465441SEvalZero }
90*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(msh_help, __cmd_help, RT-Thread shell help.);
91*10465441SEvalZero 
msh_split(char * cmd,rt_size_t length,char * argv[FINSH_ARG_MAX])92*10465441SEvalZero static int msh_split(char *cmd, rt_size_t length, char *argv[FINSH_ARG_MAX])
93*10465441SEvalZero {
94*10465441SEvalZero     char *ptr;
95*10465441SEvalZero     rt_size_t position;
96*10465441SEvalZero     rt_size_t argc;
97*10465441SEvalZero     rt_size_t i;
98*10465441SEvalZero 
99*10465441SEvalZero     ptr = cmd;
100*10465441SEvalZero     position = 0; argc = 0;
101*10465441SEvalZero 
102*10465441SEvalZero     while (position < length)
103*10465441SEvalZero     {
104*10465441SEvalZero         /* strip bank and tab */
105*10465441SEvalZero         while ((*ptr == ' ' || *ptr == '\t') && position < length)
106*10465441SEvalZero         {
107*10465441SEvalZero             *ptr = '\0';
108*10465441SEvalZero             ptr ++; position ++;
109*10465441SEvalZero         }
110*10465441SEvalZero 
111*10465441SEvalZero         if(argc >= FINSH_ARG_MAX)
112*10465441SEvalZero         {
113*10465441SEvalZero             rt_kprintf("Too many args ! We only Use:\n");
114*10465441SEvalZero             for(i = 0; i < argc; i++)
115*10465441SEvalZero             {
116*10465441SEvalZero                 rt_kprintf("%s ", argv[i]);
117*10465441SEvalZero             }
118*10465441SEvalZero             rt_kprintf("\n");
119*10465441SEvalZero             break;
120*10465441SEvalZero         }
121*10465441SEvalZero 
122*10465441SEvalZero         if (position >= length) break;
123*10465441SEvalZero 
124*10465441SEvalZero         /* handle string */
125*10465441SEvalZero         if (*ptr == '"')
126*10465441SEvalZero         {
127*10465441SEvalZero             ptr ++; position ++;
128*10465441SEvalZero             argv[argc] = ptr; argc ++;
129*10465441SEvalZero 
130*10465441SEvalZero             /* skip this string */
131*10465441SEvalZero             while (*ptr != '"' && position < length)
132*10465441SEvalZero             {
133*10465441SEvalZero                 if (*ptr == '\\')
134*10465441SEvalZero                 {
135*10465441SEvalZero                     if (*(ptr + 1) == '"')
136*10465441SEvalZero                     {
137*10465441SEvalZero                         ptr ++; position ++;
138*10465441SEvalZero                     }
139*10465441SEvalZero                 }
140*10465441SEvalZero                 ptr ++; position ++;
141*10465441SEvalZero             }
142*10465441SEvalZero             if (position >= length) break;
143*10465441SEvalZero 
144*10465441SEvalZero             /* skip '"' */
145*10465441SEvalZero             *ptr = '\0'; ptr ++; position ++;
146*10465441SEvalZero         }
147*10465441SEvalZero         else
148*10465441SEvalZero         {
149*10465441SEvalZero             argv[argc] = ptr;
150*10465441SEvalZero             argc ++;
151*10465441SEvalZero             while ((*ptr != ' ' && *ptr != '\t') && position < length)
152*10465441SEvalZero             {
153*10465441SEvalZero                 ptr ++; position ++;
154*10465441SEvalZero             }
155*10465441SEvalZero             if (position >= length) break;
156*10465441SEvalZero         }
157*10465441SEvalZero     }
158*10465441SEvalZero 
159*10465441SEvalZero     return argc;
160*10465441SEvalZero }
161*10465441SEvalZero 
msh_get_cmd(char * cmd,int size)162*10465441SEvalZero static cmd_function_t msh_get_cmd(char *cmd, int size)
163*10465441SEvalZero {
164*10465441SEvalZero     struct finsh_syscall *index;
165*10465441SEvalZero     cmd_function_t cmd_func = RT_NULL;
166*10465441SEvalZero 
167*10465441SEvalZero     for (index = _syscall_table_begin;
168*10465441SEvalZero             index < _syscall_table_end;
169*10465441SEvalZero             FINSH_NEXT_SYSCALL(index))
170*10465441SEvalZero     {
171*10465441SEvalZero         if (strncmp(index->name, "__cmd_", 6) != 0) continue;
172*10465441SEvalZero 
173*10465441SEvalZero         if (strncmp(&index->name[6], cmd, size) == 0 &&
174*10465441SEvalZero                 index->name[6 + size] == '\0')
175*10465441SEvalZero         {
176*10465441SEvalZero             cmd_func = (cmd_function_t)index->func;
177*10465441SEvalZero             break;
178*10465441SEvalZero         }
179*10465441SEvalZero     }
180*10465441SEvalZero 
181*10465441SEvalZero     return cmd_func;
182*10465441SEvalZero }
183*10465441SEvalZero 
184*10465441SEvalZero #if defined(RT_USING_MODULE) && defined(RT_USING_DFS)
185*10465441SEvalZero /* Return 0 on module executed. Other value indicate error.
186*10465441SEvalZero  */
msh_exec_module(const char * cmd_line,int size)187*10465441SEvalZero int msh_exec_module(const char *cmd_line, int size)
188*10465441SEvalZero {
189*10465441SEvalZero     int ret;
190*10465441SEvalZero     int fd = -1;
191*10465441SEvalZero     char *pg_name;
192*10465441SEvalZero     int length, cmd_length = 0;
193*10465441SEvalZero 
194*10465441SEvalZero     if (size == 0)
195*10465441SEvalZero         return -RT_ERROR;
196*10465441SEvalZero     /* get the length of command0 */
197*10465441SEvalZero     while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size)
198*10465441SEvalZero         cmd_length ++;
199*10465441SEvalZero 
200*10465441SEvalZero     /* get name length */
201*10465441SEvalZero     length = cmd_length + 32;
202*10465441SEvalZero 
203*10465441SEvalZero     /* allocate program name memory */
204*10465441SEvalZero     pg_name = (char *) rt_malloc(length);
205*10465441SEvalZero     if (pg_name == RT_NULL)
206*10465441SEvalZero         return -RT_ENOMEM;
207*10465441SEvalZero 
208*10465441SEvalZero     /* copy command0 */
209*10465441SEvalZero     memcpy(pg_name, cmd_line, cmd_length);
210*10465441SEvalZero     pg_name[cmd_length] = '\0';
211*10465441SEvalZero 
212*10465441SEvalZero     if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL)
213*10465441SEvalZero     {
214*10465441SEvalZero         /* try to open program */
215*10465441SEvalZero         fd = open(pg_name, O_RDONLY, 0);
216*10465441SEvalZero 
217*10465441SEvalZero         /* search in /bin path */
218*10465441SEvalZero         if (fd < 0)
219*10465441SEvalZero         {
220*10465441SEvalZero             rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line);
221*10465441SEvalZero             fd = open(pg_name, O_RDONLY, 0);
222*10465441SEvalZero         }
223*10465441SEvalZero     }
224*10465441SEvalZero     else
225*10465441SEvalZero     {
226*10465441SEvalZero         /* add .mo and open program */
227*10465441SEvalZero 
228*10465441SEvalZero         /* try to open program */
229*10465441SEvalZero         strcat(pg_name, ".mo");
230*10465441SEvalZero         fd = open(pg_name, O_RDONLY, 0);
231*10465441SEvalZero 
232*10465441SEvalZero         /* search in /bin path */
233*10465441SEvalZero         if (fd < 0)
234*10465441SEvalZero         {
235*10465441SEvalZero             rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line);
236*10465441SEvalZero             fd = open(pg_name, O_RDONLY, 0);
237*10465441SEvalZero         }
238*10465441SEvalZero     }
239*10465441SEvalZero 
240*10465441SEvalZero     if (fd >= 0)
241*10465441SEvalZero     {
242*10465441SEvalZero         /* found program */
243*10465441SEvalZero         close(fd);
244*10465441SEvalZero         dlmodule_exec(pg_name, cmd_line, size);
245*10465441SEvalZero         ret = 0;
246*10465441SEvalZero     }
247*10465441SEvalZero     else
248*10465441SEvalZero     {
249*10465441SEvalZero         ret = -1;
250*10465441SEvalZero     }
251*10465441SEvalZero 
252*10465441SEvalZero     rt_free(pg_name);
253*10465441SEvalZero     return ret;
254*10465441SEvalZero }
255*10465441SEvalZero 
system(const char * command)256*10465441SEvalZero int system(const char *command)
257*10465441SEvalZero {
258*10465441SEvalZero     int ret = -RT_ENOMEM;
259*10465441SEvalZero     char *cmd = rt_strdup(command);
260*10465441SEvalZero 
261*10465441SEvalZero     if (cmd)
262*10465441SEvalZero     {
263*10465441SEvalZero         ret = msh_exec(cmd, rt_strlen(cmd));
264*10465441SEvalZero         rt_free(cmd);
265*10465441SEvalZero     }
266*10465441SEvalZero 
267*10465441SEvalZero     return ret;
268*10465441SEvalZero }
269*10465441SEvalZero RTM_EXPORT(system);
270*10465441SEvalZero #endif
271*10465441SEvalZero 
_msh_exec_cmd(char * cmd,rt_size_t length,int * retp)272*10465441SEvalZero static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp)
273*10465441SEvalZero {
274*10465441SEvalZero     int argc;
275*10465441SEvalZero     rt_size_t cmd0_size = 0;
276*10465441SEvalZero     cmd_function_t cmd_func;
277*10465441SEvalZero     char *argv[FINSH_ARG_MAX];
278*10465441SEvalZero 
279*10465441SEvalZero     RT_ASSERT(cmd);
280*10465441SEvalZero     RT_ASSERT(retp);
281*10465441SEvalZero 
282*10465441SEvalZero     /* find the size of first command */
283*10465441SEvalZero     while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
284*10465441SEvalZero         cmd0_size ++;
285*10465441SEvalZero     if (cmd0_size == 0)
286*10465441SEvalZero         return -RT_ERROR;
287*10465441SEvalZero 
288*10465441SEvalZero     cmd_func = msh_get_cmd(cmd, cmd0_size);
289*10465441SEvalZero     if (cmd_func == RT_NULL)
290*10465441SEvalZero         return -RT_ERROR;
291*10465441SEvalZero 
292*10465441SEvalZero     /* split arguments */
293*10465441SEvalZero     memset(argv, 0x00, sizeof(argv));
294*10465441SEvalZero     argc = msh_split(cmd, length, argv);
295*10465441SEvalZero     if (argc == 0)
296*10465441SEvalZero         return -RT_ERROR;
297*10465441SEvalZero 
298*10465441SEvalZero     /* exec this command */
299*10465441SEvalZero     *retp = cmd_func(argc, argv);
300*10465441SEvalZero     return 0;
301*10465441SEvalZero }
302*10465441SEvalZero 
303*10465441SEvalZero #if defined(RT_USING_LWP) && defined(RT_USING_DFS)
_msh_exec_lwp(char * cmd,rt_size_t length)304*10465441SEvalZero static int _msh_exec_lwp(char *cmd, rt_size_t length)
305*10465441SEvalZero {
306*10465441SEvalZero     int argc;
307*10465441SEvalZero     int cmd0_size = 0;
308*10465441SEvalZero     char *argv[FINSH_ARG_MAX];
309*10465441SEvalZero     int fd = -1;
310*10465441SEvalZero     char *pg_name;
311*10465441SEvalZero 
312*10465441SEvalZero     extern int exec(char*, int, char**);
313*10465441SEvalZero 
314*10465441SEvalZero     /* find the size of first command */
315*10465441SEvalZero     while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
316*10465441SEvalZero         cmd0_size ++;
317*10465441SEvalZero     if (cmd0_size == 0)
318*10465441SEvalZero         return -1;
319*10465441SEvalZero 
320*10465441SEvalZero     /* split arguments */
321*10465441SEvalZero     rt_memset(argv, 0x00, sizeof(argv));
322*10465441SEvalZero     argc = msh_split(cmd, length, argv);
323*10465441SEvalZero     if (argc == 0)
324*10465441SEvalZero         return -1;
325*10465441SEvalZero 
326*10465441SEvalZero     pg_name = argv[0];
327*10465441SEvalZero     /* try to open program */
328*10465441SEvalZero     fd = open(pg_name, O_RDONLY, 0);
329*10465441SEvalZero 
330*10465441SEvalZero     if (fd < 0)
331*10465441SEvalZero         return -1;
332*10465441SEvalZero 
333*10465441SEvalZero     /* found program */
334*10465441SEvalZero     close(fd);
335*10465441SEvalZero     exec(pg_name, argc, argv);
336*10465441SEvalZero 
337*10465441SEvalZero     return 0;
338*10465441SEvalZero }
339*10465441SEvalZero #endif
340*10465441SEvalZero 
msh_exec(char * cmd,rt_size_t length)341*10465441SEvalZero int msh_exec(char *cmd, rt_size_t length)
342*10465441SEvalZero {
343*10465441SEvalZero     int cmd_ret;
344*10465441SEvalZero 
345*10465441SEvalZero     /* strim the beginning of command */
346*10465441SEvalZero     while (*cmd  == ' ' || *cmd == '\t')
347*10465441SEvalZero     {
348*10465441SEvalZero         cmd++;
349*10465441SEvalZero         length--;
350*10465441SEvalZero     }
351*10465441SEvalZero 
352*10465441SEvalZero     if (length == 0)
353*10465441SEvalZero         return 0;
354*10465441SEvalZero 
355*10465441SEvalZero     /* Exec sequence:
356*10465441SEvalZero      * 1. built-in command
357*10465441SEvalZero      * 2. module(if enabled)
358*10465441SEvalZero      */
359*10465441SEvalZero     if (_msh_exec_cmd(cmd, length, &cmd_ret) == 0)
360*10465441SEvalZero     {
361*10465441SEvalZero         return cmd_ret;
362*10465441SEvalZero     }
363*10465441SEvalZero #ifdef RT_USING_DFS
364*10465441SEvalZero #ifdef DFS_USING_WORKDIR
365*10465441SEvalZero     if (msh_exec_script(cmd, length) == 0)
366*10465441SEvalZero     {
367*10465441SEvalZero         return 0;
368*10465441SEvalZero     }
369*10465441SEvalZero #endif
370*10465441SEvalZero 
371*10465441SEvalZero #ifdef RT_USING_MODULE
372*10465441SEvalZero     if (msh_exec_module(cmd, length) == 0)
373*10465441SEvalZero     {
374*10465441SEvalZero         return 0;
375*10465441SEvalZero     }
376*10465441SEvalZero #endif
377*10465441SEvalZero 
378*10465441SEvalZero #ifdef RT_USING_LWP
379*10465441SEvalZero     if (_msh_exec_lwp(cmd, length) == 0)
380*10465441SEvalZero     {
381*10465441SEvalZero         return 0;
382*10465441SEvalZero     }
383*10465441SEvalZero #endif
384*10465441SEvalZero #endif
385*10465441SEvalZero 
386*10465441SEvalZero     /* truncate the cmd at the first space. */
387*10465441SEvalZero     {
388*10465441SEvalZero         char *tcmd;
389*10465441SEvalZero         tcmd = cmd;
390*10465441SEvalZero         while (*tcmd != ' ' && *tcmd != '\0')
391*10465441SEvalZero         {
392*10465441SEvalZero             tcmd++;
393*10465441SEvalZero         }
394*10465441SEvalZero         *tcmd = '\0';
395*10465441SEvalZero     }
396*10465441SEvalZero     rt_kprintf("%s: command not found.\n", cmd);
397*10465441SEvalZero     return -1;
398*10465441SEvalZero }
399*10465441SEvalZero 
str_common(const char * str1,const char * str2)400*10465441SEvalZero static int str_common(const char *str1, const char *str2)
401*10465441SEvalZero {
402*10465441SEvalZero     const char *str = str1;
403*10465441SEvalZero 
404*10465441SEvalZero     while ((*str != 0) && (*str2 != 0) && (*str == *str2))
405*10465441SEvalZero     {
406*10465441SEvalZero         str ++;
407*10465441SEvalZero         str2 ++;
408*10465441SEvalZero     }
409*10465441SEvalZero 
410*10465441SEvalZero     return (str - str1);
411*10465441SEvalZero }
412*10465441SEvalZero 
413*10465441SEvalZero #ifdef RT_USING_DFS
msh_auto_complete_path(char * path)414*10465441SEvalZero void msh_auto_complete_path(char *path)
415*10465441SEvalZero {
416*10465441SEvalZero     DIR *dir = RT_NULL;
417*10465441SEvalZero     struct dirent *dirent = RT_NULL;
418*10465441SEvalZero     char *full_path, *ptr, *index;
419*10465441SEvalZero 
420*10465441SEvalZero     if (!path)
421*10465441SEvalZero         return;
422*10465441SEvalZero 
423*10465441SEvalZero     full_path = (char *)rt_malloc(256);
424*10465441SEvalZero     if (full_path == RT_NULL) return; /* out of memory */
425*10465441SEvalZero 
426*10465441SEvalZero     if (*path != '/')
427*10465441SEvalZero     {
428*10465441SEvalZero         getcwd(full_path, 256);
429*10465441SEvalZero         if (full_path[rt_strlen(full_path) - 1]  != '/')
430*10465441SEvalZero             strcat(full_path, "/");
431*10465441SEvalZero     }
432*10465441SEvalZero     else *full_path = '\0';
433*10465441SEvalZero 
434*10465441SEvalZero     index = RT_NULL;
435*10465441SEvalZero     ptr = path;
436*10465441SEvalZero     for (;;)
437*10465441SEvalZero     {
438*10465441SEvalZero         if (*ptr == '/') index = ptr + 1;
439*10465441SEvalZero         if (!*ptr) break;
440*10465441SEvalZero 
441*10465441SEvalZero         ptr ++;
442*10465441SEvalZero     }
443*10465441SEvalZero     if (index == RT_NULL) index = path;
444*10465441SEvalZero 
445*10465441SEvalZero     if (index != RT_NULL)
446*10465441SEvalZero     {
447*10465441SEvalZero         char *dest = index;
448*10465441SEvalZero 
449*10465441SEvalZero         /* fill the parent path */
450*10465441SEvalZero         ptr = full_path;
451*10465441SEvalZero         while (*ptr) ptr ++;
452*10465441SEvalZero 
453*10465441SEvalZero         for (index = path; index != dest;)
454*10465441SEvalZero             *ptr++ = *index++;
455*10465441SEvalZero         *ptr = '\0';
456*10465441SEvalZero 
457*10465441SEvalZero         dir = opendir(full_path);
458*10465441SEvalZero         if (dir == RT_NULL) /* open directory failed! */
459*10465441SEvalZero         {
460*10465441SEvalZero             rt_free(full_path);
461*10465441SEvalZero             return;
462*10465441SEvalZero         }
463*10465441SEvalZero 
464*10465441SEvalZero         /* restore the index position */
465*10465441SEvalZero         index = dest;
466*10465441SEvalZero     }
467*10465441SEvalZero 
468*10465441SEvalZero     /* auto complete the file or directory name */
469*10465441SEvalZero     if (*index == '\0') /* display all of files and directories */
470*10465441SEvalZero     {
471*10465441SEvalZero         for (;;)
472*10465441SEvalZero         {
473*10465441SEvalZero             dirent = readdir(dir);
474*10465441SEvalZero             if (dirent == RT_NULL) break;
475*10465441SEvalZero 
476*10465441SEvalZero             rt_kprintf("%s\n", dirent->d_name);
477*10465441SEvalZero         }
478*10465441SEvalZero     }
479*10465441SEvalZero     else
480*10465441SEvalZero     {
481*10465441SEvalZero         rt_size_t length, min_length;
482*10465441SEvalZero 
483*10465441SEvalZero         min_length = 0;
484*10465441SEvalZero         for (;;)
485*10465441SEvalZero         {
486*10465441SEvalZero             dirent = readdir(dir);
487*10465441SEvalZero             if (dirent == RT_NULL) break;
488*10465441SEvalZero 
489*10465441SEvalZero             /* matched the prefix string */
490*10465441SEvalZero             if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
491*10465441SEvalZero             {
492*10465441SEvalZero                 if (min_length == 0)
493*10465441SEvalZero                 {
494*10465441SEvalZero                     min_length = rt_strlen(dirent->d_name);
495*10465441SEvalZero                     /* save dirent name */
496*10465441SEvalZero                     strcpy(full_path, dirent->d_name);
497*10465441SEvalZero                 }
498*10465441SEvalZero 
499*10465441SEvalZero                 length = str_common(dirent->d_name, full_path);
500*10465441SEvalZero 
501*10465441SEvalZero                 if (length < min_length)
502*10465441SEvalZero                 {
503*10465441SEvalZero                     min_length = length;
504*10465441SEvalZero                 }
505*10465441SEvalZero             }
506*10465441SEvalZero         }
507*10465441SEvalZero 
508*10465441SEvalZero         if (min_length)
509*10465441SEvalZero         {
510*10465441SEvalZero             if (min_length < rt_strlen(full_path))
511*10465441SEvalZero             {
512*10465441SEvalZero                 /* list the candidate */
513*10465441SEvalZero                 rewinddir(dir);
514*10465441SEvalZero 
515*10465441SEvalZero                 for (;;)
516*10465441SEvalZero                 {
517*10465441SEvalZero                     dirent = readdir(dir);
518*10465441SEvalZero                     if (dirent == RT_NULL) break;
519*10465441SEvalZero 
520*10465441SEvalZero                     if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
521*10465441SEvalZero                         rt_kprintf("%s\n", dirent->d_name);
522*10465441SEvalZero                 }
523*10465441SEvalZero             }
524*10465441SEvalZero 
525*10465441SEvalZero             length = index - path;
526*10465441SEvalZero             memcpy(index, full_path, min_length);
527*10465441SEvalZero             path[length + min_length] = '\0';
528*10465441SEvalZero         }
529*10465441SEvalZero     }
530*10465441SEvalZero 
531*10465441SEvalZero     closedir(dir);
532*10465441SEvalZero     rt_free(full_path);
533*10465441SEvalZero }
534*10465441SEvalZero #endif
535*10465441SEvalZero 
msh_auto_complete(char * prefix)536*10465441SEvalZero void msh_auto_complete(char *prefix)
537*10465441SEvalZero {
538*10465441SEvalZero     int length, min_length;
539*10465441SEvalZero     const char *name_ptr, *cmd_name;
540*10465441SEvalZero     struct finsh_syscall *index;
541*10465441SEvalZero 
542*10465441SEvalZero     min_length = 0;
543*10465441SEvalZero     name_ptr = RT_NULL;
544*10465441SEvalZero 
545*10465441SEvalZero     if (*prefix == '\0')
546*10465441SEvalZero     {
547*10465441SEvalZero         msh_help(0, RT_NULL);
548*10465441SEvalZero         return;
549*10465441SEvalZero     }
550*10465441SEvalZero 
551*10465441SEvalZero #ifdef RT_USING_DFS
552*10465441SEvalZero     /* check whether a spare in the command */
553*10465441SEvalZero     {
554*10465441SEvalZero         char *ptr;
555*10465441SEvalZero 
556*10465441SEvalZero         ptr = prefix + rt_strlen(prefix);
557*10465441SEvalZero         while (ptr != prefix)
558*10465441SEvalZero         {
559*10465441SEvalZero             if (*ptr == ' ')
560*10465441SEvalZero             {
561*10465441SEvalZero                 msh_auto_complete_path(ptr + 1);
562*10465441SEvalZero                 break;
563*10465441SEvalZero             }
564*10465441SEvalZero 
565*10465441SEvalZero             ptr --;
566*10465441SEvalZero         }
567*10465441SEvalZero #ifdef RT_USING_MODULE
568*10465441SEvalZero         /* There is a chance that the user want to run the module directly. So
569*10465441SEvalZero          * try to complete the file names. If the completed path is not a
570*10465441SEvalZero          * module, the system won't crash anyway. */
571*10465441SEvalZero         if (ptr == prefix)
572*10465441SEvalZero         {
573*10465441SEvalZero             msh_auto_complete_path(ptr);
574*10465441SEvalZero         }
575*10465441SEvalZero #endif
576*10465441SEvalZero     }
577*10465441SEvalZero #endif
578*10465441SEvalZero 
579*10465441SEvalZero     /* checks in internal command */
580*10465441SEvalZero     {
581*10465441SEvalZero         for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
582*10465441SEvalZero         {
583*10465441SEvalZero             /* skip finsh shell function */
584*10465441SEvalZero             if (strncmp(index->name, "__cmd_", 6) != 0) continue;
585*10465441SEvalZero 
586*10465441SEvalZero             cmd_name = (const char *) &index->name[6];
587*10465441SEvalZero             if (strncmp(prefix, cmd_name, strlen(prefix)) == 0)
588*10465441SEvalZero             {
589*10465441SEvalZero                 if (min_length == 0)
590*10465441SEvalZero                 {
591*10465441SEvalZero                     /* set name_ptr */
592*10465441SEvalZero                     name_ptr = cmd_name;
593*10465441SEvalZero                     /* set initial length */
594*10465441SEvalZero                     min_length = strlen(name_ptr);
595*10465441SEvalZero                 }
596*10465441SEvalZero 
597*10465441SEvalZero                 length = str_common(name_ptr, cmd_name);
598*10465441SEvalZero                 if (length < min_length)
599*10465441SEvalZero                     min_length = length;
600*10465441SEvalZero 
601*10465441SEvalZero                 rt_kprintf("%s\n", cmd_name);
602*10465441SEvalZero             }
603*10465441SEvalZero         }
604*10465441SEvalZero     }
605*10465441SEvalZero 
606*10465441SEvalZero     /* auto complete string */
607*10465441SEvalZero     if (name_ptr != NULL)
608*10465441SEvalZero     {
609*10465441SEvalZero         rt_strncpy(prefix, name_ptr, min_length);
610*10465441SEvalZero     }
611*10465441SEvalZero 
612*10465441SEvalZero     return ;
613*10465441SEvalZero }
614*10465441SEvalZero #endif
615*10465441SEvalZero 
616*10465441SEvalZero #endif /* FINSH_USING_MSH */
617