msh.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*
  2. * Copyright (c) 2006-2018, 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. #if defined(RT_USING_MSH) || defined(FINSH_USING_MSH)
  14. #ifndef FINSH_ARG_MAX
  15. #define FINSH_ARG_MAX 8
  16. #endif
  17. #include "msh.h"
  18. #include "shell.h"
  19. #include <string.h>
  20. #ifdef RT_USING_DFS
  21. #include <dfs_posix.h>
  22. #endif
  23. #ifdef RT_USING_MODULE
  24. #include <dlmodule.h>
  25. #endif
  26. typedef int (*cmd_function_t)(int argc, char **argv);
  27. int msh_help(int argc, char **argv)
  28. {
  29. rt_kprintf("RT-Thread shell commands:\n");
  30. {
  31. struct finsh_syscall *index;
  32. for (index = _syscall_table_begin;
  33. index < _syscall_table_end;
  34. FINSH_NEXT_SYSCALL(index))
  35. {
  36. if (strncmp(index->name, "__cmd_", 6) != 0) continue;
  37. #if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
  38. rt_kprintf("%-16s - %s\n", &index->name[6], index->desc);
  39. #else
  40. rt_kprintf("%s ", &index->name[6]);
  41. #endif
  42. }
  43. }
  44. rt_kprintf("\n");
  45. return 0;
  46. }
  47. MSH_CMD_EXPORT_ALIAS(msh_help, help, RT-Thread shell help.);
  48. int cmd_ps(int argc, char **argv)
  49. {
  50. extern long list_thread(void);
  51. extern int list_module(void);
  52. #ifdef RT_USING_MODULE
  53. if ((argc == 2) && (strcmp(argv[1], "-m") == 0))
  54. list_module();
  55. else
  56. #endif
  57. list_thread();
  58. return 0;
  59. }
  60. MSH_CMD_EXPORT_ALIAS(cmd_ps, ps, List threads in the system.);
  61. #ifdef RT_USING_HEAP
  62. int cmd_free(int argc, char **argv)
  63. {
  64. extern void list_mem(void);
  65. extern void list_memheap(void);
  66. #ifdef RT_USING_MEMHEAP_AS_HEAP
  67. list_memheap();
  68. #else
  69. list_mem();
  70. #endif
  71. return 0;
  72. }
  73. MSH_CMD_EXPORT_ALIAS(cmd_free, free, Show the memory usage in the system.);
  74. #endif
  75. static int msh_split(char *cmd, rt_size_t length, char *argv[FINSH_ARG_MAX])
  76. {
  77. char *ptr;
  78. rt_size_t position;
  79. rt_size_t argc;
  80. rt_size_t i;
  81. ptr = cmd;
  82. position = 0; argc = 0;
  83. while (position < length)
  84. {
  85. /* strip bank and tab */
  86. while ((*ptr == ' ' || *ptr == '\t') && position < length)
  87. {
  88. *ptr = '\0';
  89. ptr ++; position ++;
  90. }
  91. if(argc >= FINSH_ARG_MAX)
  92. {
  93. rt_kprintf("Too many args ! We only Use:\n");
  94. for(i = 0; i < argc; i++)
  95. {
  96. rt_kprintf("%s ", argv[i]);
  97. }
  98. rt_kprintf("\n");
  99. break;
  100. }
  101. if (position >= length) break;
  102. /* handle string */
  103. if (*ptr == '"')
  104. {
  105. ptr ++; position ++;
  106. argv[argc] = ptr; argc ++;
  107. /* skip this string */
  108. while (*ptr != '"' && position < length)
  109. {
  110. if (*ptr == '\\')
  111. {
  112. if (*(ptr + 1) == '"')
  113. {
  114. ptr ++; position ++;
  115. }
  116. }
  117. ptr ++; position ++;
  118. }
  119. if (position >= length) break;
  120. /* skip '"' */
  121. *ptr = '\0'; ptr ++; position ++;
  122. }
  123. else
  124. {
  125. argv[argc] = ptr;
  126. argc ++;
  127. while ((*ptr != ' ' && *ptr != '\t') && position < length)
  128. {
  129. ptr ++; position ++;
  130. }
  131. if (position >= length) break;
  132. }
  133. }
  134. return argc;
  135. }
  136. static cmd_function_t msh_get_cmd(char *cmd, int size)
  137. {
  138. struct finsh_syscall *index;
  139. cmd_function_t cmd_func = RT_NULL;
  140. for (index = _syscall_table_begin;
  141. index < _syscall_table_end;
  142. FINSH_NEXT_SYSCALL(index))
  143. {
  144. if (strncmp(index->name, "__cmd_", 6) != 0) continue;
  145. if (strncmp(&index->name[6], cmd, size) == 0 &&
  146. index->name[6 + size] == '\0')
  147. {
  148. cmd_func = (cmd_function_t)index->func;
  149. break;
  150. }
  151. }
  152. return cmd_func;
  153. }
  154. #if defined(RT_USING_MODULE) && defined(RT_USING_DFS)
  155. /* Return 0 on module executed. Other value indicate error.
  156. */
  157. int msh_exec_module(const char *cmd_line, int size)
  158. {
  159. int ret;
  160. int fd = -1;
  161. char *pg_name;
  162. int length, cmd_length = 0;
  163. if (size == 0)
  164. return -RT_ERROR;
  165. /* get the length of command0 */
  166. while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size)
  167. cmd_length ++;
  168. /* get name length */
  169. length = cmd_length + 32;
  170. /* allocate program name memory */
  171. pg_name = (char *) rt_malloc(length + 3);
  172. if (pg_name == RT_NULL)
  173. return -RT_ENOMEM;
  174. /* copy command0 */
  175. memcpy(pg_name, cmd_line, cmd_length);
  176. pg_name[cmd_length] = '\0';
  177. if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL)
  178. {
  179. /* try to open program */
  180. fd = open(pg_name, O_RDONLY, 0);
  181. /* search in /bin path */
  182. if (fd < 0)
  183. {
  184. rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line);
  185. fd = open(pg_name, O_RDONLY, 0);
  186. }
  187. }
  188. else
  189. {
  190. /* add .mo and open program */
  191. /* try to open program */
  192. strcat(pg_name, ".mo");
  193. fd = open(pg_name, O_RDONLY, 0);
  194. /* search in /bin path */
  195. if (fd < 0)
  196. {
  197. rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line);
  198. fd = open(pg_name, O_RDONLY, 0);
  199. }
  200. }
  201. if (fd >= 0)
  202. {
  203. /* found program */
  204. close(fd);
  205. dlmodule_exec(pg_name, cmd_line, size);
  206. ret = 0;
  207. }
  208. else
  209. {
  210. ret = -1;
  211. }
  212. rt_free(pg_name);
  213. return ret;
  214. }
  215. int system(const char *command)
  216. {
  217. int ret = -RT_ENOMEM;
  218. char *cmd = rt_strdup(command);
  219. if (cmd)
  220. {
  221. ret = msh_exec(cmd, rt_strlen(cmd));
  222. rt_free(cmd);
  223. }
  224. return ret;
  225. }
  226. RTM_EXPORT(system);
  227. #endif
  228. static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp)
  229. {
  230. int argc;
  231. rt_size_t cmd0_size = 0;
  232. cmd_function_t cmd_func;
  233. char *argv[FINSH_ARG_MAX];
  234. RT_ASSERT(cmd);
  235. RT_ASSERT(retp);
  236. /* find the size of first command */
  237. while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
  238. cmd0_size ++;
  239. if (cmd0_size == 0)
  240. return -RT_ERROR;
  241. cmd_func = msh_get_cmd(cmd, cmd0_size);
  242. if (cmd_func == RT_NULL)
  243. return -RT_ERROR;
  244. /* split arguments */
  245. memset(argv, 0x00, sizeof(argv));
  246. argc = msh_split(cmd, length, argv);
  247. if (argc == 0)
  248. return -RT_ERROR;
  249. /* exec this command */
  250. *retp = cmd_func(argc, argv);
  251. return 0;
  252. }
  253. pid_t exec(char*, int, int, char**);
  254. #if defined(RT_USING_LWP) && defined(RT_USING_DFS)
  255. /* check whether a file of the given path exits */
  256. static rt_bool_t _msh_lwp_cmd_exists(const char *path)
  257. {
  258. int fd = -1;
  259. fd = open(path, O_RDONLY, 0);
  260. if (fd < 0)
  261. {
  262. return RT_FALSE;
  263. }
  264. close(fd);
  265. return RT_TRUE;
  266. }
  267. /*
  268. * search for the file named "pg_name" or "pg_name.elf" at the given directory,
  269. * and return its path. return NULL when not found.
  270. */
  271. static char *_msh_exec_search_path(const char *path, const char *pg_name)
  272. {
  273. char *path_buffer = RT_NULL;
  274. ssize_t pg_len = strlen(pg_name);
  275. ssize_t base_len = 0;
  276. if (path)
  277. {
  278. base_len = strlen(path);
  279. }
  280. path_buffer = rt_malloc(base_len + pg_len + 6);
  281. if (path_buffer == RT_NULL)
  282. {
  283. return RT_NULL; /* no mem */
  284. }
  285. if (base_len > 0)
  286. {
  287. memcpy(path_buffer, path, base_len);
  288. path_buffer[base_len] = '/';
  289. path_buffer[base_len + 1] = '\0';
  290. }
  291. else
  292. {
  293. *path_buffer = '\0';
  294. }
  295. strcat(path_buffer, pg_name);
  296. if (_msh_lwp_cmd_exists(path_buffer))
  297. {
  298. return path_buffer;
  299. }
  300. if (strstr(path_buffer, ".elf") != NULL)
  301. {
  302. goto not_found;
  303. }
  304. strcat(path_buffer, ".elf");
  305. if (_msh_lwp_cmd_exists(path_buffer))
  306. {
  307. return path_buffer;
  308. }
  309. not_found:
  310. rt_free(path_buffer);
  311. return RT_NULL;
  312. }
  313. /*
  314. * search for the file named "pg_name" or "pg_name.elf" at each env path,
  315. * and return its path. return NULL when not found.
  316. */
  317. static char *_msh_exec_search_env(const char *pg_name)
  318. {
  319. char *result = RT_NULL;
  320. char *exec_path = RT_NULL;
  321. char *search_path = RT_NULL;
  322. char *pos = RT_NULL;
  323. char tmp_ch = '\0';
  324. if (!(exec_path = getenv("PATH")))
  325. {
  326. return RT_NULL;
  327. }
  328. /* exec path may need to be modified */
  329. if (!(exec_path = strdup(exec_path)))
  330. {
  331. return RT_NULL;
  332. }
  333. pos = exec_path;
  334. search_path = exec_path;
  335. /* walk through the entire exec_path until finding the program wanted
  336. or hitting its end */
  337. while (1)
  338. {
  339. /* env paths are seperated by ':' */
  340. if (*pos == ':' || *pos == '\0')
  341. {
  342. tmp_ch = *pos;
  343. *pos = '\0';
  344. result = _msh_exec_search_path(search_path, pg_name);
  345. if (result || tmp_ch == '\0')
  346. {
  347. goto ret;
  348. }
  349. pos++;
  350. search_path = pos;
  351. continue;
  352. }
  353. pos++;
  354. }
  355. /* release the duplicated exec_path and return */
  356. ret:
  357. rt_free(exec_path);
  358. return result;
  359. }
  360. int _msh_exec_lwp(int debug, char *cmd, rt_size_t length)
  361. {
  362. int argc;
  363. int cmd0_size = 0;
  364. char *argv[FINSH_ARG_MAX];
  365. char *pg_name;
  366. int ret;
  367. /* find the size of first command */
  368. while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length)
  369. cmd0_size ++;
  370. if (cmd0_size == 0)
  371. return -1;
  372. /* split arguments */
  373. rt_memset(argv, 0x00, sizeof(argv));
  374. argc = msh_split(cmd, length, argv);
  375. if (argc == 0)
  376. return -1;
  377. /* try to find program in working directory */
  378. pg_name = _msh_exec_search_path("", argv[0]);
  379. if (pg_name)
  380. {
  381. goto found_program;
  382. }
  383. /* only check these paths when the first argument doesn't contain path
  384. seperator */
  385. if (strstr(argv[0], "/"))
  386. {
  387. return -1;
  388. }
  389. /* try to find program in /bin */
  390. pg_name = _msh_exec_search_path("/bin", argv[0]);
  391. if (pg_name)
  392. {
  393. goto found_program;
  394. }
  395. /* try to find program in dirs registered to env path */
  396. pg_name = _msh_exec_search_env(argv[0]);
  397. if (pg_name)
  398. {
  399. goto found_program;
  400. }
  401. /* not found in anywhere */
  402. return -1;
  403. /* found program */
  404. found_program:
  405. ret = exec(pg_name, debug, argc, argv);
  406. rt_free(pg_name);
  407. return ret;
  408. }
  409. #endif
  410. #if defined(RT_USING_DFS)
  411. static int msh_readline(int fd, char *line_buf, int size)
  412. {
  413. char ch;
  414. int index = 0;
  415. do
  416. {
  417. if (read(fd, &ch, 1) != 1)
  418. {
  419. /* nothing in this file */
  420. return 0;
  421. }
  422. }
  423. while (ch == '\n' || ch == '\r');
  424. /* set the first character */
  425. line_buf[index ++] = ch;
  426. while (index < size)
  427. {
  428. if (read(fd, &ch, 1) == 1)
  429. {
  430. if (ch == '\n' || ch == '\r')
  431. {
  432. line_buf[index] = '\0';
  433. break;
  434. }
  435. line_buf[index++] = ch;
  436. }
  437. else
  438. {
  439. line_buf[index] = '\0';
  440. break;
  441. }
  442. }
  443. return index;
  444. }
  445. int msh_exec_script(const char *cmd_line, int size)
  446. {
  447. int ret;
  448. int fd = -1;
  449. char *pg_name;
  450. int length, cmd_length = 0;
  451. if (size == 0) return -RT_ERROR;
  452. /* get the length of command0 */
  453. while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size)
  454. cmd_length ++;
  455. /* get name length */
  456. length = cmd_length + 32;
  457. /* allocate program name memory */
  458. pg_name = (char *) rt_malloc(length);
  459. if (pg_name == RT_NULL) return -RT_ENOMEM;
  460. /* copy command0 */
  461. memcpy(pg_name, cmd_line, cmd_length);
  462. pg_name[cmd_length] = '\0';
  463. if (strstr(pg_name, ".sh") != RT_NULL || strstr(pg_name, ".SH") != RT_NULL)
  464. {
  465. /* try to open program */
  466. fd = open(pg_name, O_RDONLY, 0);
  467. /* search in /bin path */
  468. if (fd < 0)
  469. {
  470. rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line);
  471. fd = open(pg_name, O_RDONLY, 0);
  472. }
  473. }
  474. rt_free(pg_name);
  475. if (fd >= 0)
  476. {
  477. /* found script */
  478. char *line_buf;
  479. int length;
  480. line_buf = (char *) rt_malloc(RT_CONSOLEBUF_SIZE);
  481. if (line_buf == RT_NULL)
  482. {
  483. close(fd);
  484. return -RT_ENOMEM;
  485. }
  486. /* read line by line and then exec it */
  487. do
  488. {
  489. length = msh_readline(fd, line_buf, RT_CONSOLEBUF_SIZE);
  490. if (length > 0)
  491. {
  492. char ch = '\0';
  493. int index;
  494. for (index = 0; index < length; index ++)
  495. {
  496. ch = line_buf[index];
  497. if (ch == ' ' || ch == '\t') continue;
  498. else break;
  499. }
  500. if (ch != '#') /* not a comment */
  501. msh_exec(line_buf, length);
  502. }
  503. }
  504. while (length > 0);
  505. close(fd);
  506. rt_free(line_buf);
  507. ret = 0;
  508. }
  509. else
  510. {
  511. ret = -1;
  512. }
  513. return ret;
  514. }
  515. #endif
  516. int msh_exec(char *cmd, rt_size_t length)
  517. {
  518. int cmd_ret;
  519. /* strim the beginning of command */
  520. while (*cmd == ' ' || *cmd == '\t')
  521. {
  522. cmd++;
  523. length--;
  524. }
  525. if (length == 0)
  526. return 0;
  527. /* Exec sequence:
  528. * 1. built-in command
  529. * 2. module(if enabled)
  530. */
  531. if (_msh_exec_cmd(cmd, length, &cmd_ret) == 0)
  532. {
  533. return cmd_ret;
  534. }
  535. #ifdef RT_USING_DFS
  536. #ifdef DFS_USING_WORKDIR
  537. if (msh_exec_script(cmd, length) == 0)
  538. {
  539. return 0;
  540. }
  541. #endif
  542. #ifdef RT_USING_MODULE
  543. if (msh_exec_module(cmd, length) == 0)
  544. {
  545. return 0;
  546. }
  547. #endif
  548. #ifdef RT_USING_LWP
  549. /* exec from msh_exec , debug = 0*/
  550. /* _msh_exec_lwp return is pid , <= 0 means failed */
  551. if (_msh_exec_lwp(0, cmd, length) > 0)
  552. {
  553. return 0;
  554. }
  555. #endif
  556. #endif
  557. /* truncate the cmd at the first space. */
  558. {
  559. char *tcmd;
  560. tcmd = cmd;
  561. while (*tcmd != ' ' && *tcmd != '\0')
  562. {
  563. tcmd++;
  564. }
  565. *tcmd = '\0';
  566. }
  567. rt_kprintf("%s: command not found.\n", cmd);
  568. return -1;
  569. }
  570. static int str_common(const char *str1, const char *str2)
  571. {
  572. const char *str = str1;
  573. while ((*str != 0) && (*str2 != 0) && (*str == *str2))
  574. {
  575. str ++;
  576. str2 ++;
  577. }
  578. return (str - str1);
  579. }
  580. #ifdef RT_USING_DFS
  581. void msh_auto_complete_path(char *path)
  582. {
  583. DIR *dir = RT_NULL;
  584. struct dirent *dirent = RT_NULL;
  585. char *full_path, *ptr, *index;
  586. if (!path)
  587. return;
  588. full_path = (char *)rt_malloc(256);
  589. if (full_path == RT_NULL) return; /* out of memory */
  590. if (*path != '/')
  591. {
  592. getcwd(full_path, 256);
  593. if (full_path[rt_strlen(full_path) - 1] != '/')
  594. strcat(full_path, "/");
  595. }
  596. else *full_path = '\0';
  597. index = RT_NULL;
  598. ptr = path;
  599. for (;;)
  600. {
  601. if (*ptr == '/') index = ptr + 1;
  602. if (!*ptr) break;
  603. ptr ++;
  604. }
  605. if (index == RT_NULL) index = path;
  606. if (index != RT_NULL)
  607. {
  608. char *dest = index;
  609. /* fill the parent path */
  610. ptr = full_path;
  611. while (*ptr) ptr ++;
  612. for (index = path; index != dest;)
  613. *ptr++ = *index++;
  614. *ptr = '\0';
  615. dir = opendir(full_path);
  616. if (dir == RT_NULL) /* open directory failed! */
  617. {
  618. rt_free(full_path);
  619. return;
  620. }
  621. /* restore the index position */
  622. index = dest;
  623. }
  624. /* auto complete the file or directory name */
  625. if (*index == '\0') /* display all of files and directories */
  626. {
  627. for (;;)
  628. {
  629. dirent = readdir(dir);
  630. if (dirent == RT_NULL) break;
  631. rt_kprintf("%s\n", dirent->d_name);
  632. }
  633. }
  634. else
  635. {
  636. int multi = 0;
  637. rt_size_t length, min_length;
  638. min_length = 0;
  639. for (;;)
  640. {
  641. dirent = readdir(dir);
  642. if (dirent == RT_NULL) break;
  643. /* matched the prefix string */
  644. if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
  645. {
  646. multi ++;
  647. if (min_length == 0)
  648. {
  649. min_length = rt_strlen(dirent->d_name);
  650. /* save dirent name */
  651. strcpy(full_path, dirent->d_name);
  652. }
  653. length = str_common(dirent->d_name, full_path);
  654. if (length < min_length)
  655. {
  656. min_length = length;
  657. }
  658. }
  659. }
  660. if (min_length)
  661. {
  662. if (multi > 1)
  663. {
  664. /* list the candidate */
  665. rewinddir(dir);
  666. for (;;)
  667. {
  668. dirent = readdir(dir);
  669. if (dirent == RT_NULL) break;
  670. if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0)
  671. rt_kprintf("%s\n", dirent->d_name);
  672. }
  673. }
  674. length = index - path;
  675. memcpy(index, full_path, min_length);
  676. path[length + min_length] = '\0';
  677. /* try to locate folder */
  678. if (multi == 1)
  679. {
  680. struct stat buffer = {0};
  681. if ((stat(path, &buffer) == 0) && (S_ISDIR(buffer.st_mode)))
  682. {
  683. strcat(path, "/");
  684. }
  685. }
  686. }
  687. }
  688. closedir(dir);
  689. rt_free(full_path);
  690. }
  691. #endif
  692. void msh_auto_complete(char *prefix)
  693. {
  694. int length, min_length;
  695. const char *name_ptr = RT_NULL;
  696. min_length = 0;
  697. if (*prefix == '\0')
  698. {
  699. msh_help(0, RT_NULL);
  700. return;
  701. }
  702. #ifdef RT_USING_DFS
  703. /* check whether a spare in the command */
  704. {
  705. char *ptr;
  706. ptr = prefix + rt_strlen(prefix);
  707. while (ptr != prefix)
  708. {
  709. if (*ptr == ' ')
  710. {
  711. msh_auto_complete_path(ptr + 1);
  712. break;
  713. }
  714. ptr --;
  715. }
  716. #if defined(RT_USING_MODULE) || defined(RT_USING_LWP)
  717. /* There is a chance that the user want to run the module directly. So
  718. * try to complete the file names. If the completed path is not a
  719. * module, the system won't crash anyway. */
  720. if (ptr == prefix)
  721. {
  722. msh_auto_complete_path(ptr);
  723. }
  724. #endif
  725. }
  726. #endif
  727. /* checks in internal command */
  728. {
  729. struct finsh_syscall *index;
  730. const char *cmd_name = RT_NULL;
  731. for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
  732. {
  733. /* skip finsh shell function */
  734. if (strncmp(index->name, "__cmd_", 6) != 0) continue;
  735. cmd_name = (const char *) &index->name[6];
  736. if (strncmp(prefix, cmd_name, strlen(prefix)) == 0)
  737. {
  738. if (min_length == 0)
  739. {
  740. /* set name_ptr */
  741. name_ptr = cmd_name;
  742. /* set initial length */
  743. min_length = strlen(name_ptr);
  744. }
  745. length = str_common(name_ptr, cmd_name);
  746. if (length < min_length)
  747. min_length = length;
  748. rt_kprintf("%s\n", cmd_name);
  749. }
  750. }
  751. /* auto complete string */
  752. if (name_ptr != NULL)
  753. {
  754. rt_strncpy(prefix, name_ptr, min_length);
  755. }
  756. }
  757. return ;
  758. }
  759. #endif /* RT_USING_MSH */