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