仓库迁移
This commit is contained in:
		
							
								
								
									
										1141
									
								
								source/rt_thread/components/finsh/cmd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1141
									
								
								source/rt_thread/components/finsh/cmd.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										249
									
								
								source/rt_thread/components/finsh/finsh.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								source/rt_thread/components/finsh/finsh.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2010-03-22     Bernard      first version | ||||
|  */ | ||||
| #ifndef __FINSH_H__ | ||||
| #define __FINSH_H__ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include "finsh_api.h" | ||||
|  | ||||
| /* -- the beginning of option -- */ | ||||
| #define FINSH_NAME_MAX          16      /* max length of identifier */ | ||||
| #define FINSH_NODE_MAX          16      /* max number of node */ | ||||
|  | ||||
| #define FINSH_HEAP_MAX          128     /* max length of heap */ | ||||
| #define FINSH_STRING_MAX        128     /* max length of string */ | ||||
| #define FINSH_VARIABLE_MAX      8       /* max number of variable */ | ||||
|  | ||||
| #define FINSH_STACK_MAX         64      /* max stack size */ | ||||
| #define FINSH_TEXT_MAX          128     /* max text segment size */ | ||||
|  | ||||
| #define HEAP_ALIGNMENT          4       /* heap alignment */ | ||||
|  | ||||
| #define FINSH_GET16(x)    (*(x)) | (*((x)+1) << 8) | ||||
| #define FINSH_GET32(x)    (rt_uint32_t)(*(x)) | ((rt_uint32_t)*((x)+1) << 8) | \ | ||||
|     ((rt_uint32_t)*((x)+2) << 16) | ((rt_uint32_t)*((x)+3) << 24) | ||||
|  | ||||
| #define FINSH_SET16(x, v)           \ | ||||
|     do                              \ | ||||
|     {                               \ | ||||
|         *(x)     = (v) & 0x00ff;    \ | ||||
|         (*((x)+1)) = (v) >> 8;      \ | ||||
|     } while ( 0 ) | ||||
|  | ||||
| #define FINSH_SET32(x, v)                                       \ | ||||
|     do                                                          \ | ||||
|     {                                                           \ | ||||
|         *(x)     = (rt_uint32_t)(v)  & 0x000000ff;              \ | ||||
|         (*((x)+1)) = ((rt_uint32_t)(v) >> 8) & 0x000000ff;      \ | ||||
|         (*((x)+2)) = ((rt_uint32_t)(v) >> 16) & 0x000000ff;     \ | ||||
|         (*((x)+3)) = ((rt_uint32_t)(v) >> 24);                  \ | ||||
|     } while ( 0 ) | ||||
|  | ||||
| /* -- the end of option -- */ | ||||
|  | ||||
| /* std header file */ | ||||
| #include <stdio.h> | ||||
| #include <ctype.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define FINSH_VERSION_MAJOR         1 | ||||
| #define FINSH_VERSION_MINOR         0 | ||||
|  | ||||
| /** | ||||
|  * @addtogroup finsh | ||||
|  */ | ||||
| /*@{*/ | ||||
| #define FINSH_ERROR_OK              0   /**< No error           */ | ||||
| #define FINSH_ERROR_INVALID_TOKEN   1   /**< Invalid token      */ | ||||
| #define FINSH_ERROR_EXPECT_TYPE     2   /**< Expect a type      */ | ||||
| #define FINSH_ERROR_UNKNOWN_TYPE    3   /**< Unknown type       */ | ||||
| #define FINSH_ERROR_VARIABLE_EXIST  4   /**< Variable exist     */ | ||||
| #define FINSH_ERROR_EXPECT_OPERATOR 5   /**< Expect a operator  */ | ||||
| #define FINSH_ERROR_MEMORY_FULL     6   /**< Memory full        */ | ||||
| #define FINSH_ERROR_UNKNOWN_OP      7   /**< Unknown operator   */ | ||||
| #define FINSH_ERROR_UNKNOWN_NODE    8   /**< Unknown node       */ | ||||
| #define FINSH_ERROR_EXPECT_CHAR     9   /**< Expect a character */ | ||||
| #define FINSH_ERROR_UNEXPECT_END    10  /**< Unexpect end       */ | ||||
| #define FINSH_ERROR_UNKNOWN_TOKEN   11  /**< Unknown token      */ | ||||
| #define FINSH_ERROR_NO_FLOAT        12  /**< Float not supported */ | ||||
| #define FINSH_ERROR_UNKNOWN_SYMBOL  13  /**< Unknown symbol     */ | ||||
| #define FINSH_ERROR_NULL_NODE       14  /**< Null node          */ | ||||
| /*@}*/ | ||||
|  | ||||
| /* system call item */ | ||||
| struct finsh_syscall_item | ||||
| { | ||||
|     struct finsh_syscall_item* next;    /* next item */ | ||||
|     struct finsh_syscall syscall;       /* syscall */ | ||||
| }; | ||||
| extern struct finsh_syscall_item *global_syscall_list; | ||||
|  | ||||
| /* system variable table */ | ||||
| struct finsh_sysvar | ||||
| { | ||||
|     const char*     name;       /* the name of variable */ | ||||
| #if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) | ||||
|     const char*     desc;       /* description of system variable */ | ||||
| #endif | ||||
|     uint8_t      type;      /* the type of variable */ | ||||
|     void*        var ;      /* the address of variable */ | ||||
| }; | ||||
|  | ||||
| #if defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__)) | ||||
| struct finsh_syscall* finsh_syscall_next(struct finsh_syscall* call); | ||||
| struct finsh_sysvar* finsh_sysvar_next(struct finsh_sysvar* call); | ||||
| #define FINSH_NEXT_SYSCALL(index)  index=finsh_syscall_next(index) | ||||
| #define FINSH_NEXT_SYSVAR(index)   index=finsh_sysvar_next(index) | ||||
| #else | ||||
| #define FINSH_NEXT_SYSCALL(index)  index++ | ||||
| #define FINSH_NEXT_SYSVAR(index)   index++ | ||||
| #endif | ||||
|  | ||||
| /* system variable item */ | ||||
| struct finsh_sysvar_item | ||||
| { | ||||
|     struct finsh_sysvar_item *next;     /* next item */ | ||||
|     struct finsh_sysvar sysvar;         /* system variable */ | ||||
| }; | ||||
| extern struct finsh_sysvar *_sysvar_table_begin, *_sysvar_table_end; | ||||
| extern struct finsh_sysvar_item* global_sysvar_list; | ||||
|  | ||||
| /* find out system variable, which should be implemented in user program */ | ||||
| struct finsh_sysvar* finsh_sysvar_lookup(const char* name); | ||||
|  | ||||
|  | ||||
| struct finsh_token | ||||
| { | ||||
|     char eof; | ||||
|     char replay; | ||||
|  | ||||
|     int  position; | ||||
|     uint8_t current_token; | ||||
|  | ||||
|     union { | ||||
|         char char_value; | ||||
|         int int_value; | ||||
|         long long_value; | ||||
|     } value; | ||||
|     uint8_t string[FINSH_STRING_MAX]; | ||||
|  | ||||
|     uint8_t* line; | ||||
| }; | ||||
|  | ||||
| #define FINSH_IDTYPE_VAR        0x01 | ||||
| #define FINSH_IDTYPE_SYSVAR     0x02 | ||||
| #define FINSH_IDTYPE_SYSCALL    0x04 | ||||
| #define FINSH_IDTYPE_ADDRESS    0x08 | ||||
| struct finsh_node | ||||
| { | ||||
|     uint8_t node_type;  /* node node_type */ | ||||
|     uint8_t data_type;  /* node data node_type */ | ||||
|     uint8_t idtype;     /* id node information */ | ||||
|  | ||||
|     union {         /* value node */ | ||||
|         char    char_value; | ||||
|         short   short_value; | ||||
|         int     int_value; | ||||
|         long    long_value; | ||||
|         void*   ptr; | ||||
|     } value; | ||||
|     union | ||||
|     { | ||||
|         /* point to variable identifier or function identifier */ | ||||
|         struct finsh_var    *var; | ||||
|         struct finsh_sysvar *sysvar; | ||||
|         struct finsh_syscall*syscall; | ||||
|     }id; | ||||
|  | ||||
|     /* sibling and child node */ | ||||
|     struct finsh_node *sibling, *child; | ||||
| }; | ||||
|  | ||||
| struct finsh_parser | ||||
| { | ||||
|     uint8_t* parser_string; | ||||
|  | ||||
|     struct finsh_token token; | ||||
|     struct finsh_node* root; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * The basic data type in finsh shell | ||||
|  */ | ||||
| enum finsh_type { | ||||
|     finsh_type_unknown = 0, /**< unknown data type */ | ||||
|     finsh_type_void,        /**< void           */ | ||||
|     finsh_type_voidp,       /**< void pointer   */ | ||||
|     finsh_type_char,        /**< char           */ | ||||
|     finsh_type_uchar,       /**< unsigned char  */ | ||||
|     finsh_type_charp,       /**< char pointer   */ | ||||
|     finsh_type_short,       /**< short          */ | ||||
|     finsh_type_ushort,      /**< unsigned short */ | ||||
|     finsh_type_shortp,      /**< short pointer  */ | ||||
|     finsh_type_int,         /**< int            */ | ||||
|     finsh_type_uint,        /**< unsigned int   */ | ||||
|     finsh_type_intp,        /**< int pointer    */ | ||||
|     finsh_type_long,        /**< long           */ | ||||
|     finsh_type_ulong,       /**< unsigned long  */ | ||||
|     finsh_type_longp        /**< long pointer   */ | ||||
| }; | ||||
|  | ||||
| /* init finsh environment */ | ||||
| int finsh_init(struct finsh_parser* parser); | ||||
| /* flush finsh node, text segment */ | ||||
| int finsh_flush(struct finsh_parser* parser); | ||||
| /* reset all of finsh */ | ||||
| int finsh_reset(struct finsh_parser* parser); | ||||
| #ifdef RT_USING_DEVICE | ||||
| void finsh_set_device(const char* device_name); | ||||
| #endif | ||||
|  | ||||
| /* run finsh parser to generate abstract synatx tree */ | ||||
| void finsh_parser_run (struct finsh_parser* parser, const unsigned char* string); | ||||
| /* run compiler to compile abstract syntax tree */ | ||||
| int finsh_compiler_run(struct finsh_node* node); | ||||
| /* run finsh virtual machine */ | ||||
| void finsh_vm_run(void); | ||||
|  | ||||
| /* get variable value */ | ||||
| struct finsh_var* finsh_var_lookup(const char* name); | ||||
| /* get bottom value of stack */ | ||||
| long finsh_stack_bottom(void); | ||||
|  | ||||
| /* get error number of finsh */ | ||||
| uint8_t finsh_errno(void); | ||||
| /* get error string */ | ||||
| const char* finsh_error_string(uint8_t type); | ||||
|  | ||||
| #ifdef RT_USING_HEAP | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function appends a system call to finsh runtime environment | ||||
|  * @param name the name of system call | ||||
|  * @param func the function pointer of system call | ||||
|  */ | ||||
| void finsh_syscall_append(const char* name, syscall_func func); | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function appends a system variable to finsh runtime environment | ||||
|  * @param name the name of system variable | ||||
|  * @param type the data type of system variable | ||||
|  * @param addr the address of system variable | ||||
|  */ | ||||
| void finsh_sysvar_append(const char* name, uint8_t type, void* addr); | ||||
| #endif | ||||
| #endif | ||||
							
								
								
									
										220
									
								
								source/rt_thread/components/finsh/finsh_api.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								source/rt_thread/components/finsh/finsh_api.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2010-03-22     Bernard      first version | ||||
|  */ | ||||
| #ifndef FINSH_API_H__ | ||||
| #define FINSH_API_H__ | ||||
|  | ||||
| #include "finsh_config.h" | ||||
|  | ||||
| #if defined(_MSC_VER) | ||||
| #pragma section("FSymTab$f",read) | ||||
| #pragma section("VSymTab",read) | ||||
| #endif | ||||
|  | ||||
| typedef long (*syscall_func)(void); | ||||
|  | ||||
| /* system call table */ | ||||
| struct finsh_syscall | ||||
| { | ||||
|     const char*     name;       /* the name of system call */ | ||||
| #if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) | ||||
|     const char*     desc;       /* description of system call */ | ||||
| #endif | ||||
|     syscall_func func;      /* the function address of system call */ | ||||
| }; | ||||
| extern struct finsh_syscall *_syscall_table_begin, *_syscall_table_end; | ||||
|  | ||||
| /* find out system call, which should be implemented in user program */ | ||||
| struct finsh_syscall* finsh_syscall_lookup(const char* name); | ||||
|  | ||||
| #ifdef FINSH_USING_SYMTAB | ||||
|  | ||||
| #ifdef __TI_COMPILER_VERSION__ | ||||
| #define __TI_FINSH_EXPORT_FUNCTION(f)  PRAGMA(DATA_SECTION(f,"FSymTab")) | ||||
| #define __TI_FINSH_EXPORT_VAR(v)       PRAGMA(DATA_SECTION(v,"VSymTab")) | ||||
| #endif | ||||
|  | ||||
|     #ifdef FINSH_USING_DESCRIPTION | ||||
|         #ifdef _MSC_VER | ||||
|             #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \ | ||||
|                 const char __fsym_##cmd##_name[] = #cmd;            \ | ||||
|                 const char __fsym_##cmd##_desc[] = #desc;           \ | ||||
|                 __declspec(allocate("FSymTab$f"))                   \ | ||||
|                 const struct finsh_syscall __fsym_##cmd =           \ | ||||
|                 {                           \ | ||||
|                     __fsym_##cmd##_name,    \ | ||||
|                     __fsym_##cmd##_desc,    \ | ||||
|                     (syscall_func)&name     \ | ||||
|                 }; | ||||
|             #pragma comment(linker, "/merge:FSymTab=mytext") | ||||
|  | ||||
|             #define FINSH_VAR_EXPORT(name, type, desc)              \ | ||||
|                 const char __vsym_##name##_name[] = #name;          \ | ||||
|                 const char __vsym_##name##_desc[] = #desc;          \ | ||||
|                 __declspec(allocate("VSymTab"))                     \ | ||||
|                 const struct finsh_sysvar __vsym_##name =           \ | ||||
|                 {                           \ | ||||
|                     __vsym_##name##_name,   \ | ||||
|                     __vsym_##name##_desc,   \ | ||||
|                     type,                   \ | ||||
|                     (void*)&name            \ | ||||
|                 }; | ||||
|  | ||||
|         #elif defined(__TI_COMPILER_VERSION__) | ||||
|             #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \ | ||||
|                 __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd);           \ | ||||
|                 const char __fsym_##cmd##_name[] = #cmd;            \ | ||||
|                 const char __fsym_##cmd##_desc[] = #desc;           \ | ||||
|                 const struct finsh_syscall __fsym_##cmd =           \ | ||||
|                 {                           \ | ||||
|                     __fsym_##cmd##_name,    \ | ||||
|                     __fsym_##cmd##_desc,    \ | ||||
|                     (syscall_func)&name     \ | ||||
|                 }; | ||||
|  | ||||
|             #define FINSH_VAR_EXPORT(name, type, desc)              \ | ||||
|                 __TI_FINSH_EXPORT_VAR(__vsym_##name);               \ | ||||
|                 const char __vsym_##name##_name[] = #name;          \ | ||||
|                 const char __vsym_##name##_desc[] = #desc;          \ | ||||
|                 const struct finsh_sysvar __vsym_##name =           \ | ||||
|                 {                           \ | ||||
|                     __vsym_##name##_name,   \ | ||||
|                     __vsym_##name##_desc,   \ | ||||
|                     type,                   \ | ||||
|                     (void*)&name            \ | ||||
|                 }; | ||||
|  | ||||
|         #else | ||||
|             #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc)                      \ | ||||
|                 const char __fsym_##cmd##_name[] SECTION(".rodata.name") = #cmd;    \ | ||||
|                 const char __fsym_##cmd##_desc[] SECTION(".rodata.name") = #desc;   \ | ||||
|                 RT_USED const struct finsh_syscall __fsym_##cmd SECTION("FSymTab")= \ | ||||
|                 {                           \ | ||||
|                     __fsym_##cmd##_name,    \ | ||||
|                     __fsym_##cmd##_desc,    \ | ||||
|                     (syscall_func)&name     \ | ||||
|                 }; | ||||
|  | ||||
|             #define FINSH_VAR_EXPORT(name, type, desc)                              \ | ||||
|                 const char __vsym_##name##_name[] SECTION(".rodata.name") = #name;  \ | ||||
|                 const char __vsym_##name##_desc[] SECTION(".rodata.name") = #desc;  \ | ||||
|                 RT_USED const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \ | ||||
|                 {                           \ | ||||
|                     __vsym_##name##_name,   \ | ||||
|                     __vsym_##name##_desc,   \ | ||||
|                     type,                   \ | ||||
|                     (void*)&name            \ | ||||
|                 }; | ||||
|  | ||||
|         #endif | ||||
|     #else | ||||
|         #ifdef _MSC_VER | ||||
|             #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \ | ||||
|                 const char __fsym_##cmd##_name[] = #cmd;            \ | ||||
|                 __declspec(allocate("FSymTab$f"))                   \ | ||||
|                 const struct finsh_syscall __fsym_##cmd =           \ | ||||
|                 {                           \ | ||||
|                     __fsym_##cmd##_name,    \ | ||||
|                     (syscall_func)&name     \ | ||||
|                 }; | ||||
|             #pragma comment(linker, "/merge:FSymTab=mytext") | ||||
|  | ||||
|             #define FINSH_VAR_EXPORT(name, type, desc)              \ | ||||
|                 const char __vsym_##name##_name[] = #name;          \ | ||||
|                 __declspec(allocate("VSymTab")) const struct finsh_sysvar __vsym_##name = \ | ||||
|                 {                                                                         \ | ||||
|                     __vsym_##name##_name,                                                 \ | ||||
|                     type,                                                                 \ | ||||
|                     (void*)&name                                                          \ | ||||
|                 }; | ||||
|  | ||||
|         #elif defined(__TI_COMPILER_VERSION__) | ||||
|             #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc)      \ | ||||
|                 __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd);           \ | ||||
|                 const char __fsym_##cmd##_name[] = #cmd;            \ | ||||
|                 const struct finsh_syscall __fsym_##cmd =           \ | ||||
|                 {                           \ | ||||
|                     __fsym_##cmd##_name,    \ | ||||
|                     (syscall_func)&name     \ | ||||
|                 }; | ||||
|  | ||||
|             #define FINSH_VAR_EXPORT(name, type, desc)              \ | ||||
|                 __TI_FINSH_EXPORT_VAR(__vsym_##name);               \ | ||||
|                 const char __vsym_##name##_name[] = #name;          \ | ||||
|                 const struct finsh_sysvar __vsym_##name =           \ | ||||
|                 {                                                   \ | ||||
|                     __vsym_##name##_name,                           \ | ||||
|                     type,                                           \ | ||||
|                     (void*)&name                                    \ | ||||
|                 }; | ||||
|  | ||||
|         #else | ||||
|             #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc)                      \ | ||||
|                 const char __fsym_##cmd##_name[] = #cmd;                            \ | ||||
|                 RT_USED const struct finsh_syscall __fsym_##cmd SECTION("FSymTab")= \ | ||||
|                 {                                                                   \ | ||||
|                     __fsym_##cmd##_name,                                            \ | ||||
|                     (syscall_func)&name                                             \ | ||||
|                 }; | ||||
|  | ||||
|             #define FINSH_VAR_EXPORT(name, type, desc)                              \ | ||||
|                 const char __vsym_##name##_name[] = #name;                          \ | ||||
|                 RT_USED const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \ | ||||
|                 {                                                                   \ | ||||
|                     __vsym_##name##_name,                                           \ | ||||
|                     type,                                                           \ | ||||
|                     (void*)&name                                                    \ | ||||
|                 }; | ||||
|  | ||||
|         #endif | ||||
|     #endif /* end of FINSH_USING_DESCRIPTION */ | ||||
| #endif /* end of FINSH_USING_SYMTAB */ | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This macro exports a system function to finsh shell. | ||||
|  * | ||||
|  * @param name the name of function. | ||||
|  * @param desc the description of function, which will show in help. | ||||
|  */ | ||||
| #define FINSH_FUNCTION_EXPORT(name, desc)   \ | ||||
|     FINSH_FUNCTION_EXPORT_CMD(name, name, desc) | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This macro exports a system function with an alias name to finsh shell. | ||||
|  * | ||||
|  * @param name the name of function. | ||||
|  * @param alias the alias name of function. | ||||
|  * @param desc the description of function, which will show in help. | ||||
|  */ | ||||
| #define FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc)  \ | ||||
|         FINSH_FUNCTION_EXPORT_CMD(name, alias, desc) | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This macro exports a command to module shell. | ||||
|  * | ||||
|  * @param command the name of command. | ||||
|  * @param desc the description of command, which will show in help. | ||||
|  */ | ||||
| #ifdef FINSH_USING_MSH | ||||
| #define MSH_CMD_EXPORT(command, desc)   \ | ||||
|     FINSH_FUNCTION_EXPORT_CMD(command, __cmd_##command, desc) | ||||
| #define MSH_CMD_EXPORT_ALIAS(command, alias, desc)  \ | ||||
|     FINSH_FUNCTION_EXPORT_ALIAS(command, __cmd_##alias, desc) | ||||
| #else | ||||
| #define MSH_CMD_EXPORT(command, desc) | ||||
| #define MSH_CMD_EXPORT_ALIAS(command, alias, desc) | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										29
									
								
								source/rt_thread/components/finsh/finsh_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								source/rt_thread/components/finsh/finsh_config.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| /* FinSH config file */ | ||||
|  | ||||
| #ifndef __MSH_CFG_H__ | ||||
| #define __MSH_CFG_H__ | ||||
|  | ||||
| // <<< Use Configuration Wizard in Context Menu >>> | ||||
| #define RT_USING_FINSH | ||||
| #define FINSH_USING_MSH | ||||
| #define FINSH_USING_MSH_ONLY | ||||
| // <h>FinSH Configuration | ||||
| // <o>the priority of finsh thread <1-30> | ||||
| //  <i>the priority of finsh thread | ||||
| //  <i>Default: 21 | ||||
| #define FINSH_THREAD_PRIORITY       21 | ||||
| // <o>the stack of finsh thread <1-4096> | ||||
| //  <i>the stack of finsh thread | ||||
| //  <i>Default: 4096  (4096Byte) | ||||
| #define FINSH_THREAD_STACK_SIZE     1024 | ||||
|  | ||||
| #define FINSH_USING_SYMTAB | ||||
| // <c1>Enable command description | ||||
| //  <i>Enable command description | ||||
| #define FINSH_USING_DESCRIPTION | ||||
| //  </c> | ||||
| // </h> | ||||
|  | ||||
| // <<< end of configuration section >>> | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										30
									
								
								source/rt_thread/components/finsh/finsh_port.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								source/rt_thread/components/finsh/finsh_port.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  */ | ||||
|  | ||||
| #include <rthw.h> | ||||
| #include <rtconfig.h> | ||||
|  | ||||
| #ifndef RT_USING_FINSH | ||||
| #error Please uncomment the line <#include "finsh_config.h"> in the rtconfig.h  | ||||
| #endif | ||||
|  | ||||
| #ifdef RT_USING_FINSH | ||||
|  | ||||
| RT_WEAK char rt_hw_console_getchar(void) | ||||
| { | ||||
|     /* Note: the initial value of ch must < 0 */ | ||||
|     int ch = -1; | ||||
|  | ||||
| #error "TODO 4: Read a char from the uart and assign it to 'ch'." | ||||
|  | ||||
|     return ch; | ||||
| } | ||||
|  | ||||
| #endif /* RT_USING_FINSH */ | ||||
|  | ||||
							
								
								
									
										648
									
								
								source/rt_thread/components/finsh/msh.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										648
									
								
								source/rt_thread/components/finsh/msh.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,648 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2013-03-30     Bernard      the first verion for finsh | ||||
|  * 2014-01-03     Bernard      msh can execute module. | ||||
|  * 2017-07-19     Aubr.Cool    limit argc to RT_FINSH_ARG_MAX | ||||
|  */ | ||||
| #include <rtthread.h> | ||||
| #include <finsh_config.h> | ||||
|  | ||||
| #ifdef FINSH_USING_MSH | ||||
|  | ||||
| #include "msh.h" | ||||
| #include <finsh.h> | ||||
| #include <shell.h> | ||||
|  | ||||
| #ifdef RT_USING_DFS | ||||
| #include <dfs_posix.h> | ||||
| #endif | ||||
|  | ||||
| #ifdef RT_USING_MODULE | ||||
| #include <dlmodule.h> | ||||
| #endif | ||||
|  | ||||
| #ifndef FINSH_ARG_MAX | ||||
| #define FINSH_ARG_MAX    8 | ||||
| #endif | ||||
|  | ||||
| typedef int (*cmd_function_t)(int argc, char **argv); | ||||
|  | ||||
| #ifdef FINSH_USING_MSH | ||||
| #ifdef FINSH_USING_MSH_ONLY | ||||
| rt_bool_t msh_is_used(void) | ||||
| { | ||||
|     return RT_TRUE; | ||||
| } | ||||
| #else | ||||
| #ifdef FINSH_USING_MSH_DEFAULT | ||||
| static rt_bool_t __msh_state = RT_TRUE; | ||||
| #else | ||||
| static rt_bool_t __msh_state = RT_FALSE; | ||||
| #endif | ||||
| rt_bool_t msh_is_used(void) | ||||
| { | ||||
|     return __msh_state; | ||||
| } | ||||
|  | ||||
| static int msh_exit(int argc, char **argv) | ||||
| { | ||||
|     /* return to finsh shell mode */ | ||||
|     __msh_state = RT_FALSE; | ||||
|     return 0; | ||||
| } | ||||
| FINSH_FUNCTION_EXPORT_ALIAS(msh_exit, __cmd_exit, return to RT-Thread shell mode.); | ||||
|  | ||||
| static int msh_enter(void) | ||||
| { | ||||
|     /* enter module shell mode */ | ||||
|     __msh_state = RT_TRUE; | ||||
|     return 0; | ||||
| } | ||||
| FINSH_FUNCTION_EXPORT_ALIAS(msh_enter, msh, use module shell); | ||||
| #endif | ||||
|  | ||||
| int msh_help(int argc, char **argv) | ||||
| { | ||||
|     rt_kprintf("RT-Thread shell commands:\n"); | ||||
|     { | ||||
|         struct finsh_syscall *index; | ||||
|  | ||||
|         for (index = _syscall_table_begin; | ||||
|                 index < _syscall_table_end; | ||||
|                 FINSH_NEXT_SYSCALL(index)) | ||||
|         { | ||||
|             if (strncmp(index->name, "__cmd_", 6) != 0) continue; | ||||
| #if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) | ||||
|             rt_kprintf("%-16s - %s\n", &index->name[6], index->desc); | ||||
| #else | ||||
|             rt_kprintf("%s ", &index->name[6]); | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
|     rt_kprintf("\n"); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| FINSH_FUNCTION_EXPORT_ALIAS(msh_help, __cmd_help, RT-Thread shell help.); | ||||
|  | ||||
| int cmd_ps(int argc, char **argv) | ||||
| { | ||||
|     extern long list_thread(void); | ||||
|     extern int list_module(void); | ||||
|  | ||||
| #ifdef RT_USING_MODULE | ||||
|     if ((argc == 2) && (strcmp(argv[1], "-m") == 0)) | ||||
|         list_module(); | ||||
|     else | ||||
| #endif | ||||
|         list_thread(); | ||||
|     return 0; | ||||
| } | ||||
| FINSH_FUNCTION_EXPORT_ALIAS(cmd_ps, __cmd_ps, List threads in the system.); | ||||
|  | ||||
| #ifdef RT_USING_HEAP | ||||
| int cmd_free(int argc, char **argv) | ||||
| { | ||||
|     extern void list_mem(void); | ||||
|     extern void list_memheap(void); | ||||
|  | ||||
| #ifdef RT_USING_MEMHEAP_AS_HEAP | ||||
|     list_memheap(); | ||||
| #else | ||||
|     list_mem(); | ||||
| #endif | ||||
|     return 0; | ||||
| } | ||||
| FINSH_FUNCTION_EXPORT_ALIAS(cmd_free, __cmd_free, Show the memory usage in the system.); | ||||
| #endif | ||||
|  | ||||
| static int msh_split(char *cmd, rt_size_t length, char *argv[FINSH_ARG_MAX]) | ||||
| { | ||||
|     char *ptr; | ||||
|     rt_size_t position; | ||||
|     rt_size_t argc; | ||||
|     rt_size_t i; | ||||
|  | ||||
|     ptr = cmd; | ||||
|     position = 0; argc = 0; | ||||
|  | ||||
|     while (position < length) | ||||
|     { | ||||
|         /* strip bank and tab */ | ||||
|         while ((*ptr == ' ' || *ptr == '\t') && position < length) | ||||
|         { | ||||
|             *ptr = '\0'; | ||||
|             ptr ++; position ++; | ||||
|         } | ||||
|  | ||||
|         if(argc >= FINSH_ARG_MAX) | ||||
|         { | ||||
|             rt_kprintf("Too many args ! We only Use:\n"); | ||||
|             for(i = 0; i < argc; i++) | ||||
|             { | ||||
|                 rt_kprintf("%s ", argv[i]); | ||||
|             } | ||||
|             rt_kprintf("\n"); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         if (position >= length) break; | ||||
|  | ||||
|         /* handle string */ | ||||
|         if (*ptr == '"') | ||||
|         { | ||||
|             ptr ++; position ++; | ||||
|             argv[argc] = ptr; argc ++; | ||||
|  | ||||
|             /* skip this string */ | ||||
|             while (*ptr != '"' && position < length) | ||||
|             { | ||||
|                 if (*ptr == '\\') | ||||
|                 { | ||||
|                     if (*(ptr + 1) == '"') | ||||
|                     { | ||||
|                         ptr ++; position ++; | ||||
|                     } | ||||
|                 } | ||||
|                 ptr ++; position ++; | ||||
|             } | ||||
|             if (position >= length) break; | ||||
|  | ||||
|             /* skip '"' */ | ||||
|             *ptr = '\0'; ptr ++; position ++; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             argv[argc] = ptr; | ||||
|             argc ++; | ||||
|             while ((*ptr != ' ' && *ptr != '\t') && position < length) | ||||
|             { | ||||
|                 ptr ++; position ++; | ||||
|             } | ||||
|             if (position >= length) break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return argc; | ||||
| } | ||||
|  | ||||
| static cmd_function_t msh_get_cmd(char *cmd, int size) | ||||
| { | ||||
|     struct finsh_syscall *index; | ||||
|     cmd_function_t cmd_func = RT_NULL; | ||||
|  | ||||
|     for (index = _syscall_table_begin; | ||||
|             index < _syscall_table_end; | ||||
|             FINSH_NEXT_SYSCALL(index)) | ||||
|     { | ||||
|         if (strncmp(index->name, "__cmd_", 6) != 0) continue; | ||||
|  | ||||
|         if (strncmp(&index->name[6], cmd, size) == 0 && | ||||
|                 index->name[6 + size] == '\0') | ||||
|         { | ||||
|             cmd_func = (cmd_function_t)index->func; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return cmd_func; | ||||
| } | ||||
|  | ||||
| #if defined(RT_USING_MODULE) && defined(RT_USING_DFS) | ||||
| /* Return 0 on module executed. Other value indicate error. | ||||
|  */ | ||||
| int msh_exec_module(const char *cmd_line, int size) | ||||
| { | ||||
|     int ret; | ||||
|     int fd = -1; | ||||
|     char *pg_name; | ||||
|     int length, cmd_length = 0; | ||||
|  | ||||
|     if (size == 0) | ||||
|         return -RT_ERROR; | ||||
|     /* get the length of command0 */ | ||||
|     while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size) | ||||
|         cmd_length ++; | ||||
|  | ||||
|     /* get name length */ | ||||
|     length = cmd_length + 32; | ||||
|  | ||||
|     /* allocate program name memory */ | ||||
|     pg_name = (char *) rt_malloc(length); | ||||
|     if (pg_name == RT_NULL) | ||||
|         return -RT_ENOMEM; | ||||
|  | ||||
|     /* copy command0 */ | ||||
|     memcpy(pg_name, cmd_line, cmd_length); | ||||
|     pg_name[cmd_length] = '\0'; | ||||
|  | ||||
|     if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL) | ||||
|     { | ||||
|         /* try to open program */ | ||||
|         fd = open(pg_name, O_RDONLY, 0); | ||||
|  | ||||
|         /* search in /bin path */ | ||||
|         if (fd < 0) | ||||
|         { | ||||
|             rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line); | ||||
|             fd = open(pg_name, O_RDONLY, 0); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         /* add .mo and open program */ | ||||
|  | ||||
|         /* try to open program */ | ||||
|         strcat(pg_name, ".mo"); | ||||
|         fd = open(pg_name, O_RDONLY, 0); | ||||
|  | ||||
|         /* search in /bin path */ | ||||
|         if (fd < 0) | ||||
|         { | ||||
|             rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line); | ||||
|             fd = open(pg_name, O_RDONLY, 0); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (fd >= 0) | ||||
|     { | ||||
|         /* found program */ | ||||
|         close(fd); | ||||
|         dlmodule_exec(pg_name, cmd_line, size); | ||||
|         ret = 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ret = -1; | ||||
|     } | ||||
|  | ||||
|     rt_free(pg_name); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| int system(const char *command) | ||||
| { | ||||
|     int ret = -RT_ENOMEM; | ||||
|     char *cmd = rt_strdup(command); | ||||
|  | ||||
|     if (cmd) | ||||
|     { | ||||
|         ret = msh_exec(cmd, rt_strlen(cmd)); | ||||
|         rt_free(cmd); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp) | ||||
| { | ||||
|     int argc; | ||||
|     rt_size_t cmd0_size = 0; | ||||
|     cmd_function_t cmd_func; | ||||
|     char *argv[FINSH_ARG_MAX]; | ||||
|  | ||||
|     RT_ASSERT(cmd); | ||||
|     RT_ASSERT(retp); | ||||
|  | ||||
|     /* find the size of first command */ | ||||
|     while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) | ||||
|         cmd0_size ++; | ||||
|     if (cmd0_size == 0) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     cmd_func = msh_get_cmd(cmd, cmd0_size); | ||||
|     if (cmd_func == RT_NULL) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     /* split arguments */ | ||||
|     memset(argv, 0x00, sizeof(argv)); | ||||
|     argc = msh_split(cmd, length, argv); | ||||
|     if (argc == 0) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     /* exec this command */ | ||||
|     *retp = cmd_func(argc, argv); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #if defined(RT_USING_LWP) && defined(RT_USING_DFS) | ||||
| static int _msh_exec_lwp(char *cmd, rt_size_t length) | ||||
| { | ||||
|     int argc; | ||||
|     int cmd0_size = 0; | ||||
|     char *argv[FINSH_ARG_MAX]; | ||||
|     int fd = -1; | ||||
|     char *pg_name; | ||||
|  | ||||
|     extern int exec(char*, int, char**); | ||||
|  | ||||
|     /* find the size of first command */ | ||||
|     while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) | ||||
|         cmd0_size ++; | ||||
|     if (cmd0_size == 0) | ||||
|         return -1; | ||||
|  | ||||
|     /* split arguments */ | ||||
|     rt_memset(argv, 0x00, sizeof(argv)); | ||||
|     argc = msh_split(cmd, length, argv); | ||||
|     if (argc == 0) | ||||
|         return -1; | ||||
|  | ||||
|     pg_name = argv[0]; | ||||
|     /* try to open program */ | ||||
|     fd = open(pg_name, O_RDONLY, 0); | ||||
|  | ||||
|     if (fd < 0) | ||||
|         return -1; | ||||
|  | ||||
|     /* found program */ | ||||
|     close(fd); | ||||
|     exec(pg_name, argc, argv); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| int msh_exec(char *cmd, rt_size_t length) | ||||
| { | ||||
|     int cmd_ret; | ||||
|  | ||||
|     /* strim the beginning of command */ | ||||
|     while ((length > 0) && (*cmd == ' ' || *cmd == '\t')) | ||||
|     { | ||||
|         cmd++; | ||||
|         length--; | ||||
|     } | ||||
|  | ||||
|     if (length == 0) | ||||
|         return 0; | ||||
|  | ||||
|     /* Exec sequence: | ||||
|      * 1. built-in command | ||||
|      * 2. module(if enabled) | ||||
|      */ | ||||
|     if (_msh_exec_cmd(cmd, length, &cmd_ret) == 0) | ||||
|     { | ||||
|         return cmd_ret; | ||||
|     } | ||||
| #ifdef RT_USING_DFS | ||||
| #ifdef DFS_USING_WORKDIR | ||||
|     if (msh_exec_script(cmd, length) == 0) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifdef RT_USING_MODULE | ||||
|     if (msh_exec_module(cmd, length) == 0) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifdef RT_USING_LWP | ||||
|     if (_msh_exec_lwp(cmd, length) == 0) | ||||
|     { | ||||
|         return 0; | ||||
|     } | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|     /* truncate the cmd at the first space. */ | ||||
|     { | ||||
|         char *tcmd; | ||||
|         tcmd = cmd; | ||||
|         while (*tcmd != ' ' && *tcmd != '\0') | ||||
|         { | ||||
|             tcmd++; | ||||
|         } | ||||
|         *tcmd = '\0'; | ||||
|     } | ||||
|     rt_kprintf("%s: command not found.\n", cmd); | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| static int str_common(const char *str1, const char *str2) | ||||
| { | ||||
|     const char *str = str1; | ||||
|  | ||||
|     while ((*str != 0) && (*str2 != 0) && (*str == *str2)) | ||||
|     { | ||||
|         str ++; | ||||
|         str2 ++; | ||||
|     } | ||||
|  | ||||
|     return (str - str1); | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DFS | ||||
| void msh_auto_complete_path(char *path) | ||||
| { | ||||
|     DIR *dir = RT_NULL; | ||||
|     struct dirent *dirent = RT_NULL; | ||||
|     char *full_path, *ptr, *index; | ||||
|  | ||||
|     if (!path) | ||||
|         return; | ||||
|  | ||||
|     full_path = (char *)rt_malloc(256); | ||||
|     if (full_path == RT_NULL) return; /* out of memory */ | ||||
|  | ||||
|     if (*path != '/') | ||||
|     { | ||||
|         getcwd(full_path, 256); | ||||
|         if (full_path[rt_strlen(full_path) - 1]  != '/') | ||||
|             strcat(full_path, "/"); | ||||
|     } | ||||
|     else *full_path = '\0'; | ||||
|  | ||||
|     index = RT_NULL; | ||||
|     ptr = path; | ||||
|     for (;;) | ||||
|     { | ||||
|         if (*ptr == '/') index = ptr + 1; | ||||
|         if (!*ptr) break; | ||||
|  | ||||
|         ptr ++; | ||||
|     } | ||||
|     if (index == RT_NULL) index = path; | ||||
|  | ||||
|     if (index != RT_NULL) | ||||
|     { | ||||
|         char *dest = index; | ||||
|  | ||||
|         /* fill the parent path */ | ||||
|         ptr = full_path; | ||||
|         while (*ptr) ptr ++; | ||||
|  | ||||
|         for (index = path; index != dest;) | ||||
|             *ptr++ = *index++; | ||||
|         *ptr = '\0'; | ||||
|  | ||||
|         dir = opendir(full_path); | ||||
|         if (dir == RT_NULL) /* open directory failed! */ | ||||
|         { | ||||
|             rt_free(full_path); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         /* restore the index position */ | ||||
|         index = dest; | ||||
|     } | ||||
|  | ||||
|     /* auto complete the file or directory name */ | ||||
|     if (*index == '\0') /* display all of files and directories */ | ||||
|     { | ||||
|         for (;;) | ||||
|         { | ||||
|             dirent = readdir(dir); | ||||
|             if (dirent == RT_NULL) break; | ||||
|  | ||||
|             rt_kprintf("%s\n", dirent->d_name); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_size_t length, min_length; | ||||
|  | ||||
|         min_length = 0; | ||||
|         for (;;) | ||||
|         { | ||||
|             dirent = readdir(dir); | ||||
|             if (dirent == RT_NULL) break; | ||||
|  | ||||
|             /* matched the prefix string */ | ||||
|             if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0) | ||||
|             { | ||||
|                 if (min_length == 0) | ||||
|                 { | ||||
|                     min_length = rt_strlen(dirent->d_name); | ||||
|                     /* save dirent name */ | ||||
|                     strcpy(full_path, dirent->d_name); | ||||
|                 } | ||||
|  | ||||
|                 length = str_common(dirent->d_name, full_path); | ||||
|  | ||||
|                 if (length < min_length) | ||||
|                 { | ||||
|                     min_length = length; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (min_length) | ||||
|         { | ||||
|             if (min_length < rt_strlen(full_path)) | ||||
|             { | ||||
|                 /* list the candidate */ | ||||
|                 rewinddir(dir); | ||||
|  | ||||
|                 for (;;) | ||||
|                 { | ||||
|                     dirent = readdir(dir); | ||||
|                     if (dirent == RT_NULL) break; | ||||
|  | ||||
|                     if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0) | ||||
|                         rt_kprintf("%s\n", dirent->d_name); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             length = index - path; | ||||
|             memcpy(index, full_path, min_length); | ||||
|             path[length + min_length] = '\0'; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     closedir(dir); | ||||
|     rt_free(full_path); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void msh_auto_complete(char *prefix) | ||||
| { | ||||
|     int length, min_length; | ||||
|     const char *name_ptr, *cmd_name; | ||||
|     struct finsh_syscall *index; | ||||
|  | ||||
|     min_length = 0; | ||||
|     name_ptr = RT_NULL; | ||||
|  | ||||
|     if (*prefix == '\0') | ||||
|     { | ||||
|         msh_help(0, RT_NULL); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
| #ifdef RT_USING_DFS | ||||
|     /* check whether a spare in the command */ | ||||
|     { | ||||
|         char *ptr; | ||||
|  | ||||
|         ptr = prefix + rt_strlen(prefix); | ||||
|         while (ptr != prefix) | ||||
|         { | ||||
|             if (*ptr == ' ') | ||||
|             { | ||||
|                 msh_auto_complete_path(ptr + 1); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             ptr --; | ||||
|         } | ||||
| #ifdef RT_USING_MODULE | ||||
|         /* There is a chance that the user want to run the module directly. So | ||||
|          * try to complete the file names. If the completed path is not a | ||||
|          * module, the system won't crash anyway. */ | ||||
|         if (ptr == prefix) | ||||
|         { | ||||
|             msh_auto_complete_path(ptr); | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     /* checks in internal command */ | ||||
|     { | ||||
|         for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index)) | ||||
|         { | ||||
|             /* skip finsh shell function */ | ||||
|             if (strncmp(index->name, "__cmd_", 6) != 0) continue; | ||||
|  | ||||
|             cmd_name = (const char *) &index->name[6]; | ||||
|             if (strncmp(prefix, cmd_name, strlen(prefix)) == 0) | ||||
|             { | ||||
|                 if (min_length == 0) | ||||
|                 { | ||||
|                     /* set name_ptr */ | ||||
|                     name_ptr = cmd_name; | ||||
|                     /* set initial length */ | ||||
|                     min_length = strlen(name_ptr); | ||||
|                 } | ||||
|  | ||||
|                 length = str_common(name_ptr, cmd_name); | ||||
|                 if (length < min_length) | ||||
|                     min_length = length; | ||||
|  | ||||
|                 rt_kprintf("%s\n", cmd_name); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* auto complete string */ | ||||
|     if (name_ptr != NULL) | ||||
|     { | ||||
|         rt_strncpy(prefix, name_ptr, min_length); | ||||
|     } | ||||
|  | ||||
|     return ; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif /* FINSH_USING_MSH */ | ||||
							
								
								
									
										23
									
								
								source/rt_thread/components/finsh/msh.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								source/rt_thread/components/finsh/msh.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2013-03-30     Bernard      the first verion for FinSH | ||||
|  */ | ||||
|  | ||||
| #ifndef __M_SHELL__ | ||||
| #define __M_SHELL__ | ||||
|  | ||||
| #include <rtthread.h> | ||||
|  | ||||
| rt_bool_t msh_is_used(void); | ||||
| int msh_exec(char *cmd, rt_size_t length); | ||||
| void msh_auto_complete(char *prefix); | ||||
|  | ||||
| int msh_exec_module(const char *cmd_line, int size); | ||||
| int msh_exec_script(const char *cmd_line, int size); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										904
									
								
								source/rt_thread/components/finsh/shell.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										904
									
								
								source/rt_thread/components/finsh/shell.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,904 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2006-04-30     Bernard      the first version for FinSH | ||||
|  * 2006-05-08     Bernard      change finsh thread stack to 2048 | ||||
|  * 2006-06-03     Bernard      add support for skyeye | ||||
|  * 2006-09-24     Bernard      remove the code related with hardware | ||||
|  * 2010-01-18     Bernard      fix down then up key bug. | ||||
|  * 2010-03-19     Bernard      fix backspace issue and fix device read in shell. | ||||
|  * 2010-04-01     Bernard      add prompt output when start and remove the empty history | ||||
|  * 2011-02-23     Bernard      fix variable section end issue of finsh shell | ||||
|  *                             initialization when use GNU GCC compiler. | ||||
|  * 2016-11-26     armink       add password authentication | ||||
|  * 2018-07-02     aozima       add custome prompt support. | ||||
|  */ | ||||
|  | ||||
| #include <rthw.h> | ||||
| #include <finsh_config.h> | ||||
|  | ||||
| #ifdef RT_USING_FINSH | ||||
|  | ||||
| #include "finsh.h" | ||||
| #include "shell.h" | ||||
|  | ||||
| #ifdef FINSH_USING_MSH | ||||
| #include "msh.h" | ||||
| #endif | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #include <stdio.h> /* for putchar */ | ||||
| #endif | ||||
|  | ||||
| /* finsh thread */ | ||||
| #ifndef RT_USING_HEAP | ||||
| static struct rt_thread finsh_thread; | ||||
| ALIGN(RT_ALIGN_SIZE) | ||||
| static char finsh_thread_stack[FINSH_THREAD_STACK_SIZE]; | ||||
| struct finsh_shell _shell; | ||||
| #endif | ||||
|  | ||||
| /* finsh symtab */ | ||||
| #ifdef FINSH_USING_SYMTAB | ||||
| struct finsh_syscall *_syscall_table_begin  = NULL; | ||||
| struct finsh_syscall *_syscall_table_end    = NULL; | ||||
| struct finsh_sysvar *_sysvar_table_begin    = NULL; | ||||
| struct finsh_sysvar *_sysvar_table_end      = NULL; | ||||
| #endif | ||||
|  | ||||
| struct finsh_shell *shell; | ||||
| static char *finsh_prompt_custom = RT_NULL; | ||||
|  | ||||
| #if defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__)) | ||||
| struct finsh_syscall* finsh_syscall_next(struct finsh_syscall* call) | ||||
| { | ||||
|     unsigned int *ptr; | ||||
|     ptr = (unsigned int*) (call + 1); | ||||
|     while ((*ptr == 0) && ((unsigned int*)ptr < (unsigned int*) _syscall_table_end)) | ||||
|         ptr ++; | ||||
|  | ||||
|     return (struct finsh_syscall*)ptr; | ||||
| } | ||||
|  | ||||
| struct finsh_sysvar* finsh_sysvar_next(struct finsh_sysvar* call) | ||||
| { | ||||
|     unsigned int *ptr; | ||||
|     ptr = (unsigned int*) (call + 1); | ||||
|     while ((*ptr == 0) && ((unsigned int*)ptr < (unsigned int*) _sysvar_table_end)) | ||||
|         ptr ++; | ||||
|  | ||||
|     return (struct finsh_sysvar*)ptr; | ||||
| } | ||||
| #endif /* defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__)) */ | ||||
|  | ||||
| #ifdef RT_USING_HEAP | ||||
| int finsh_set_prompt(const char * prompt) | ||||
| { | ||||
|     if(finsh_prompt_custom) | ||||
|     { | ||||
|         rt_free(finsh_prompt_custom); | ||||
|         finsh_prompt_custom = RT_NULL; | ||||
|     } | ||||
|  | ||||
|     /* strdup */ | ||||
|     if(prompt) | ||||
|     { | ||||
|         finsh_prompt_custom = (char *)rt_malloc(strlen(prompt)+1); | ||||
|         if(finsh_prompt_custom) | ||||
|         { | ||||
|             strcpy(finsh_prompt_custom, prompt); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| #endif /* RT_USING_HEAP */ | ||||
|  | ||||
| #if defined(RT_USING_DFS) | ||||
| #include <dfs_posix.h> | ||||
| #endif /* RT_USING_DFS */ | ||||
|  | ||||
| const char *finsh_get_prompt() | ||||
| { | ||||
| #define _MSH_PROMPT "msh " | ||||
| #define _PROMPT     "finsh " | ||||
|     static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0}; | ||||
|  | ||||
|     /* check prompt mode */ | ||||
|     if (!shell->prompt_mode) | ||||
|     { | ||||
|         finsh_prompt[0] = '\0'; | ||||
|         return finsh_prompt; | ||||
|     } | ||||
|  | ||||
|     if(finsh_prompt_custom) | ||||
|     { | ||||
|         strncpy(finsh_prompt, finsh_prompt_custom, sizeof(finsh_prompt)-1); | ||||
|         return finsh_prompt; | ||||
|     } | ||||
|  | ||||
| #ifdef FINSH_USING_MSH | ||||
|     if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT); | ||||
|     else | ||||
| #endif | ||||
|         strcpy(finsh_prompt, _PROMPT); | ||||
|  | ||||
| #if defined(RT_USING_DFS) && defined(DFS_USING_WORKDIR) | ||||
|     /* get current working directory */ | ||||
|     getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt)); | ||||
| #endif | ||||
|  | ||||
|     strcat(finsh_prompt, ">"); | ||||
|  | ||||
|     return finsh_prompt; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function get the prompt mode of finsh shell. | ||||
|  * | ||||
|  * @return prompt the prompt mode, 0 disable prompt mode, other values enable prompt mode. | ||||
|  */ | ||||
| rt_uint32_t finsh_get_prompt_mode(void) | ||||
| { | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|     return shell->prompt_mode; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function set the prompt mode of finsh shell. | ||||
|  * | ||||
|  * The parameter 0 disable prompt mode, other values enable prompt mode. | ||||
|  * | ||||
|  * @param prompt the prompt mode | ||||
|  */ | ||||
| void finsh_set_prompt_mode(rt_uint32_t prompt_mode) | ||||
| { | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|     shell->prompt_mode = prompt_mode; | ||||
| } | ||||
|  | ||||
| static int finsh_getchar(void) | ||||
| { | ||||
| #ifdef RT_USING_DEVICE | ||||
| #ifdef RT_USING_POSIX | ||||
|     return getchar(); | ||||
| #else | ||||
|     char ch = 0; | ||||
|  | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|  | ||||
|     if(shell->device) | ||||
|     { | ||||
|         while (rt_device_read(shell->device, -1, &ch, 1) != 1) | ||||
|             rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER); | ||||
|  | ||||
|         return (int)ch; | ||||
|     } | ||||
|     else | ||||
| #endif | ||||
| #endif | ||||
|     { | ||||
|         extern char rt_hw_console_getchar(void); | ||||
|         return rt_hw_console_getchar(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #if !defined(RT_USING_POSIX) && defined(RT_USING_DEVICE) | ||||
| static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size) | ||||
| { | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|  | ||||
|     /* release semaphore to let finsh thread rx data */ | ||||
|     rt_sem_release(&shell->rx_sem); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function sets the input device of finsh shell. | ||||
|  * | ||||
|  * @param device_name the name of new input device. | ||||
|  */ | ||||
| void finsh_set_device(const char *device_name) | ||||
| { | ||||
|     rt_device_t dev = RT_NULL; | ||||
|  | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|     dev = rt_device_find(device_name); | ||||
|     if (dev == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("finsh: can not find device: %s\n", device_name); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /* check whether it's a same device */ | ||||
|     if (dev == shell->device) return; | ||||
|     /* open this device and set the new device in finsh shell */ | ||||
|     if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | \ | ||||
|                        RT_DEVICE_FLAG_STREAM) == RT_EOK) | ||||
|     { | ||||
|         if (shell->device != RT_NULL) | ||||
|         { | ||||
|             /* close old finsh device */ | ||||
|             rt_device_close(shell->device); | ||||
|             rt_device_set_rx_indicate(shell->device, RT_NULL); | ||||
|         } | ||||
|  | ||||
|         /* clear line buffer before switch to new device */ | ||||
|         memset(shell->line, 0, sizeof(shell->line)); | ||||
|         shell->line_curpos = shell->line_position = 0; | ||||
|  | ||||
|         shell->device = dev; | ||||
|         rt_device_set_rx_indicate(dev, finsh_rx_ind); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function returns current finsh shell input device. | ||||
|  * | ||||
|  * @return the finsh shell input device name is returned. | ||||
|  */ | ||||
| const char *finsh_get_device() | ||||
| { | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|     return shell->device->parent.name; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function set the echo mode of finsh shell. | ||||
|  * | ||||
|  * FINSH_OPTION_ECHO=0x01 is echo mode, other values are none-echo mode. | ||||
|  * | ||||
|  * @param echo the echo mode | ||||
|  */ | ||||
| void finsh_set_echo(rt_uint32_t echo) | ||||
| { | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|     shell->echo_mode = (rt_uint8_t)echo; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function gets the echo mode of finsh shell. | ||||
|  * | ||||
|  * @return the echo mode | ||||
|  */ | ||||
| rt_uint32_t finsh_get_echo() | ||||
| { | ||||
|     RT_ASSERT(shell != RT_NULL); | ||||
|  | ||||
|     return shell->echo_mode; | ||||
| } | ||||
|  | ||||
| #ifdef FINSH_USING_AUTH | ||||
| /** | ||||
|  * set a new password for finsh | ||||
|  * | ||||
|  * @param password new password | ||||
|  * | ||||
|  * @return result, RT_EOK on OK, -RT_ERROR on the new password length is less than | ||||
|  *  FINSH_PASSWORD_MIN or greater than FINSH_PASSWORD_MAX | ||||
|  */ | ||||
| rt_err_t finsh_set_password(const char *password) { | ||||
|     rt_ubase_t level; | ||||
|     rt_size_t pw_len = rt_strlen(password); | ||||
|  | ||||
|     if (pw_len < FINSH_PASSWORD_MIN || pw_len > FINSH_PASSWORD_MAX) | ||||
|         return -RT_ERROR; | ||||
|  | ||||
|     level = rt_hw_interrupt_disable(); | ||||
|     rt_strncpy(shell->password, password, FINSH_PASSWORD_MAX); | ||||
|     rt_hw_interrupt_enable(level); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * get the finsh password | ||||
|  * | ||||
|  * @return password | ||||
|  */ | ||||
| const char *finsh_get_password(void) | ||||
| { | ||||
|     return shell->password; | ||||
| } | ||||
|  | ||||
| static void finsh_wait_auth(void) | ||||
| { | ||||
|     int ch; | ||||
|     rt_bool_t input_finish = RT_FALSE; | ||||
|     char password[FINSH_PASSWORD_MAX] = { 0 }; | ||||
|     rt_size_t cur_pos = 0; | ||||
|     /* password not set */ | ||||
|     if (rt_strlen(finsh_get_password()) == 0) return; | ||||
|  | ||||
|     while (1) | ||||
|     { | ||||
|         rt_kprintf("Password for login: "); | ||||
|         while (!input_finish) | ||||
|         { | ||||
|             while (1) | ||||
|             { | ||||
|                 /* read one character from device */ | ||||
|                 ch = finsh_getchar(); | ||||
|                 if (ch < 0) | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 if (ch >= ' ' && ch <= '~' && cur_pos < FINSH_PASSWORD_MAX) | ||||
|                 { | ||||
|                     /* change the printable characters to '*' */ | ||||
|                     rt_kprintf("*"); | ||||
|                     password[cur_pos++] = ch; | ||||
|                 } | ||||
|                 else if (ch == '\b' && cur_pos > 0) | ||||
|                 { | ||||
|                     /* backspace */ | ||||
|                     cur_pos--; | ||||
|                     password[cur_pos] = '\0'; | ||||
|                     rt_kprintf("\b \b"); | ||||
|                 } | ||||
|                 else if (ch == '\r' || ch == '\n') | ||||
|                 { | ||||
|                     rt_kprintf("\n"); | ||||
|                     input_finish = RT_TRUE; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (!rt_strncmp(shell->password, password, FINSH_PASSWORD_MAX)) return; | ||||
|         else | ||||
|         { | ||||
|             /* authentication failed, delay 2S for retry */ | ||||
|             rt_thread_delay(2 * RT_TICK_PER_SECOND); | ||||
|             rt_kprintf("Sorry, try again.\n"); | ||||
|             cur_pos = 0; | ||||
|             input_finish = RT_FALSE; | ||||
|             rt_memset(password, '\0', FINSH_PASSWORD_MAX); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| #endif /* FINSH_USING_AUTH */ | ||||
|  | ||||
| static void shell_auto_complete(char *prefix) | ||||
| { | ||||
|  | ||||
|     rt_kprintf("\n"); | ||||
| #ifdef FINSH_USING_MSH | ||||
|     if (msh_is_used() == RT_TRUE) | ||||
|     { | ||||
|         msh_auto_complete(prefix); | ||||
|     } | ||||
|     else | ||||
| #endif | ||||
|     { | ||||
| #ifndef FINSH_USING_MSH_ONLY | ||||
|         extern void list_prefix(char * prefix); | ||||
|         list_prefix(prefix); | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     rt_kprintf("%s%s", FINSH_PROMPT, prefix); | ||||
| } | ||||
|  | ||||
| #ifndef FINSH_USING_MSH_ONLY | ||||
| void finsh_run_line(struct finsh_parser *parser, const char *line) | ||||
| { | ||||
|     const char *err_str; | ||||
|  | ||||
|     if(shell->echo_mode) | ||||
|         rt_kprintf("\n"); | ||||
|     finsh_parser_run(parser, (unsigned char *)line); | ||||
|  | ||||
|     /* compile node root */ | ||||
|     if (finsh_errno() == 0) | ||||
|     { | ||||
|         finsh_compiler_run(parser->root); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         err_str = finsh_error_string(finsh_errno()); | ||||
|         rt_kprintf("%s\n", err_str); | ||||
|     } | ||||
|  | ||||
|     /* run virtual machine */ | ||||
|     if (finsh_errno() == 0) | ||||
|     { | ||||
|         char ch; | ||||
|         finsh_vm_run(); | ||||
|  | ||||
|         ch = (unsigned char)finsh_stack_bottom(); | ||||
|         if (ch > 0x20 && ch < 0x7e) | ||||
|         { | ||||
|             rt_kprintf("\t'%c', %d, 0x%08x\n", | ||||
|                        (unsigned char)finsh_stack_bottom(), | ||||
|                        (unsigned int)finsh_stack_bottom(), | ||||
|                        (unsigned int)finsh_stack_bottom()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             rt_kprintf("\t%d, 0x%08x\n", | ||||
|                        (unsigned int)finsh_stack_bottom(), | ||||
|                        (unsigned int)finsh_stack_bottom()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     finsh_flush(parser); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #ifdef FINSH_USING_HISTORY | ||||
| static rt_bool_t shell_handle_history(struct finsh_shell *shell) | ||||
| { | ||||
| #if defined(_WIN32) | ||||
|     int i; | ||||
|     rt_kprintf("\r"); | ||||
|  | ||||
|     for (i = 0; i <= 60; i++) | ||||
|         putchar(' '); | ||||
|     rt_kprintf("\r"); | ||||
|  | ||||
| #else | ||||
|     rt_kprintf("\033[2K\r"); | ||||
| #endif | ||||
|     rt_kprintf("%s%s", FINSH_PROMPT, shell->line); | ||||
|     return RT_FALSE; | ||||
| } | ||||
|  | ||||
| static void shell_push_history(struct finsh_shell *shell) | ||||
| { | ||||
|     if (shell->line_position != 0) | ||||
|     { | ||||
|         /* push history */ | ||||
|         if (shell->history_count >= FINSH_HISTORY_LINES) | ||||
|         { | ||||
|             /* if current cmd is same as last cmd, don't push */ | ||||
|             if (memcmp(&shell->cmd_history[FINSH_HISTORY_LINES - 1], shell->line, FINSH_CMD_SIZE)) | ||||
|             { | ||||
|                 /* move history */ | ||||
|                 int index; | ||||
|                 for (index = 0; index < FINSH_HISTORY_LINES - 1; index ++) | ||||
|                 { | ||||
|                     memcpy(&shell->cmd_history[index][0], | ||||
|                            &shell->cmd_history[index + 1][0], FINSH_CMD_SIZE); | ||||
|                 } | ||||
|                 memset(&shell->cmd_history[index][0], 0, FINSH_CMD_SIZE); | ||||
|                 memcpy(&shell->cmd_history[index][0], shell->line, shell->line_position); | ||||
|  | ||||
|                 /* it's the maximum history */ | ||||
|                 shell->history_count = FINSH_HISTORY_LINES; | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             /* if current cmd is same as last cmd, don't push */ | ||||
|             if (shell->history_count == 0 || memcmp(&shell->cmd_history[shell->history_count - 1], shell->line, FINSH_CMD_SIZE)) | ||||
|             { | ||||
|                 shell->current_history = shell->history_count; | ||||
|                 memset(&shell->cmd_history[shell->history_count][0], 0, FINSH_CMD_SIZE); | ||||
|                 memcpy(&shell->cmd_history[shell->history_count][0], shell->line, shell->line_position); | ||||
|  | ||||
|                 /* increase count and set current history position */ | ||||
|                 shell->history_count ++; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     shell->current_history = shell->history_count; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void finsh_thread_entry(void *parameter) | ||||
| { | ||||
|     int ch; | ||||
|  | ||||
|     /* normal is echo mode */ | ||||
| #ifndef FINSH_ECHO_DISABLE_DEFAULT | ||||
|     shell->echo_mode = 1; | ||||
| #else | ||||
|     shell->echo_mode = 0; | ||||
| #endif | ||||
|  | ||||
| #ifndef FINSH_USING_MSH_ONLY | ||||
|     finsh_init(&shell->parser); | ||||
| #endif | ||||
|  | ||||
| #if !defined(RT_USING_POSIX) && defined(RT_USING_DEVICE) | ||||
|     /* set console device as shell device */ | ||||
|     if (shell->device == RT_NULL) | ||||
|     { | ||||
|         rt_device_t console = rt_console_get_device(); | ||||
|         if (console) | ||||
|         { | ||||
|             finsh_set_device(console->parent.name); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
| #ifdef FINSH_USING_AUTH | ||||
|     /* set the default password when the password isn't setting */ | ||||
|     if (rt_strlen(finsh_get_password()) == 0) | ||||
|     { | ||||
|         if (finsh_set_password(FINSH_DEFAULT_PASSWORD) != RT_EOK) | ||||
|         { | ||||
|             rt_kprintf("Finsh password set failed.\n"); | ||||
|         } | ||||
|     } | ||||
|     /* waiting authenticate success */ | ||||
|     finsh_wait_auth(); | ||||
| #endif | ||||
|  | ||||
|     rt_kprintf(FINSH_PROMPT); | ||||
|  | ||||
|     while (1) | ||||
|     { | ||||
|         ch = finsh_getchar(); | ||||
|         if (ch < 0) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         /* | ||||
|          * handle control key | ||||
|          * up key  : 0x1b 0x5b 0x41 | ||||
|          * down key: 0x1b 0x5b 0x42 | ||||
|          * right key:0x1b 0x5b 0x43 | ||||
|          * left key: 0x1b 0x5b 0x44 | ||||
|          */ | ||||
|         if (ch == 0x1b) | ||||
|         { | ||||
|             shell->stat = WAIT_SPEC_KEY; | ||||
|             continue; | ||||
|         } | ||||
|         else if (shell->stat == WAIT_SPEC_KEY) | ||||
|         { | ||||
|             if (ch == 0x5b) | ||||
|             { | ||||
|                 shell->stat = WAIT_FUNC_KEY; | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             shell->stat = WAIT_NORMAL; | ||||
|         } | ||||
|         else if (shell->stat == WAIT_FUNC_KEY) | ||||
|         { | ||||
|             shell->stat = WAIT_NORMAL; | ||||
|  | ||||
|             if (ch == 0x41) /* up key */ | ||||
|             { | ||||
| #ifdef FINSH_USING_HISTORY | ||||
|                 /* prev history */ | ||||
|                 if (shell->current_history > 0) | ||||
|                     shell->current_history --; | ||||
|                 else | ||||
|                 { | ||||
|                     shell->current_history = 0; | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 /* copy the history command */ | ||||
|                 memcpy(shell->line, &shell->cmd_history[shell->current_history][0], | ||||
|                        FINSH_CMD_SIZE); | ||||
|                 shell->line_curpos = shell->line_position = strlen(shell->line); | ||||
|                 shell_handle_history(shell); | ||||
| #endif | ||||
|                 continue; | ||||
|             } | ||||
|             else if (ch == 0x42) /* down key */ | ||||
|             { | ||||
| #ifdef FINSH_USING_HISTORY | ||||
|                 /* next history */ | ||||
|                 if (shell->current_history < shell->history_count - 1) | ||||
|                     shell->current_history ++; | ||||
|                 else | ||||
|                 { | ||||
|                     /* set to the end of history */ | ||||
|                     if (shell->history_count != 0) | ||||
|                         shell->current_history = shell->history_count - 1; | ||||
|                     else | ||||
|                         continue; | ||||
|                 } | ||||
|  | ||||
|                 memcpy(shell->line, &shell->cmd_history[shell->current_history][0], | ||||
|                        FINSH_CMD_SIZE); | ||||
|                 shell->line_curpos = shell->line_position = strlen(shell->line); | ||||
|                 shell_handle_history(shell); | ||||
| #endif | ||||
|                 continue; | ||||
|             } | ||||
|             else if (ch == 0x44) /* left key */ | ||||
|             { | ||||
|                 if (shell->line_curpos) | ||||
|                 { | ||||
|                     rt_kprintf("\b"); | ||||
|                     shell->line_curpos --; | ||||
|                 } | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|             else if (ch == 0x43) /* right key */ | ||||
|             { | ||||
|                 if (shell->line_curpos < shell->line_position) | ||||
|                 { | ||||
|                     rt_kprintf("%c", shell->line[shell->line_curpos]); | ||||
|                     shell->line_curpos ++; | ||||
|                 } | ||||
|  | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /* received null or error */ | ||||
|         if (ch == '\0' || ch == 0xFF) continue; | ||||
|         /* handle tab key */ | ||||
|         else if (ch == '\t') | ||||
|         { | ||||
|             int i; | ||||
|             /* move the cursor to the beginning of line */ | ||||
|             for (i = 0; i < shell->line_curpos; i++) | ||||
|                 rt_kprintf("\b"); | ||||
|  | ||||
|             /* auto complete */ | ||||
|             shell_auto_complete(&shell->line[0]); | ||||
|             /* re-calculate position */ | ||||
|             shell->line_curpos = shell->line_position = strlen(shell->line); | ||||
|  | ||||
|             continue; | ||||
|         } | ||||
|         /* handle backspace key */ | ||||
|         else if (ch == 0x7f || ch == 0x08) | ||||
|         { | ||||
|             /* note that shell->line_curpos >= 0 */ | ||||
|             if (shell->line_curpos == 0) | ||||
|                 continue; | ||||
|  | ||||
|             shell->line_position--; | ||||
|             shell->line_curpos--; | ||||
|  | ||||
|             if (shell->line_position > shell->line_curpos) | ||||
|             { | ||||
|                 int i; | ||||
|  | ||||
|                 rt_memmove(&shell->line[shell->line_curpos], | ||||
|                            &shell->line[shell->line_curpos + 1], | ||||
|                            shell->line_position - shell->line_curpos); | ||||
|                 shell->line[shell->line_position] = 0; | ||||
|  | ||||
|                 rt_kprintf("\b%s  \b", &shell->line[shell->line_curpos]); | ||||
|  | ||||
|                 /* move the cursor to the origin position */ | ||||
|                 for (i = shell->line_curpos; i <= shell->line_position; i++) | ||||
|                     rt_kprintf("\b"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 rt_kprintf("\b \b"); | ||||
|                 shell->line[shell->line_position] = 0; | ||||
|             } | ||||
|  | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         /* handle end of line, break */ | ||||
|         if (ch == '\r' || ch == '\n') | ||||
|         { | ||||
| #ifdef FINSH_USING_HISTORY | ||||
|             shell_push_history(shell); | ||||
| #endif | ||||
|  | ||||
| #ifdef FINSH_USING_MSH | ||||
|             if (msh_is_used() == RT_TRUE) | ||||
|             { | ||||
|                 if (shell->echo_mode) | ||||
|                     rt_kprintf("\n"); | ||||
|                 msh_exec(shell->line, shell->line_position); | ||||
|             } | ||||
|             else | ||||
| #endif | ||||
|             { | ||||
| #ifndef FINSH_USING_MSH_ONLY | ||||
|                 /* add ';' and run the command line */ | ||||
|                 shell->line[shell->line_position] = ';'; | ||||
|  | ||||
|                 if (shell->line_position != 0) finsh_run_line(&shell->parser, shell->line); | ||||
|                 else | ||||
|                     if (shell->echo_mode) rt_kprintf("\n"); | ||||
| #endif | ||||
|             } | ||||
|  | ||||
|             rt_kprintf(FINSH_PROMPT); | ||||
|             memset(shell->line, 0, sizeof(shell->line)); | ||||
|             shell->line_curpos = shell->line_position = 0; | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         /* it's a large line, discard it */ | ||||
|         if (shell->line_position >= FINSH_CMD_SIZE) | ||||
|             shell->line_position = 0; | ||||
|  | ||||
|         /* normal character */ | ||||
|         if (shell->line_curpos < shell->line_position) | ||||
|         { | ||||
|             int i; | ||||
|  | ||||
|             rt_memmove(&shell->line[shell->line_curpos + 1], | ||||
|                        &shell->line[shell->line_curpos], | ||||
|                        shell->line_position - shell->line_curpos); | ||||
|             shell->line[shell->line_curpos] = ch; | ||||
|             if (shell->echo_mode) | ||||
|                 rt_kprintf("%s", &shell->line[shell->line_curpos]); | ||||
|  | ||||
|             /* move the cursor to new position */ | ||||
|             for (i = shell->line_curpos; i < shell->line_position; i++) | ||||
|                 rt_kprintf("\b"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             shell->line[shell->line_position] = ch; | ||||
|             if (shell->echo_mode) | ||||
|                 rt_kprintf("%c", ch); | ||||
|         } | ||||
|  | ||||
|         ch = 0; | ||||
|         shell->line_position ++; | ||||
|         shell->line_curpos++; | ||||
|         if (shell->line_position >= FINSH_CMD_SIZE) | ||||
|         { | ||||
|             /* clear command line */ | ||||
|             shell->line_position = 0; | ||||
|             shell->line_curpos = 0; | ||||
|         } | ||||
|     } /* end of device read */ | ||||
| } | ||||
|  | ||||
| void finsh_system_function_init(const void *begin, const void *end) | ||||
| { | ||||
|     _syscall_table_begin = (struct finsh_syscall *) begin; | ||||
|     _syscall_table_end = (struct finsh_syscall *) end; | ||||
| } | ||||
|  | ||||
| void finsh_system_var_init(const void *begin, const void *end) | ||||
| { | ||||
|     _sysvar_table_begin = (struct finsh_sysvar *) begin; | ||||
|     _sysvar_table_end = (struct finsh_sysvar *) end; | ||||
| } | ||||
|  | ||||
| #if defined(__ICCARM__) || defined(__ICCRX__)               /* for IAR compiler */ | ||||
| #ifdef FINSH_USING_SYMTAB | ||||
| #pragma section="FSymTab" | ||||
| #pragma section="VSymTab" | ||||
| #endif | ||||
| #elif defined(__ADSPBLACKFIN__) /* for VisaulDSP++ Compiler*/ | ||||
| #ifdef FINSH_USING_SYMTAB | ||||
| extern "asm" int __fsymtab_start; | ||||
| extern "asm" int __fsymtab_end; | ||||
| extern "asm" int __vsymtab_start; | ||||
| extern "asm" int __vsymtab_end; | ||||
| #endif | ||||
| #elif defined(_MSC_VER) | ||||
| #pragma section("FSymTab$a", read) | ||||
| const char __fsym_begin_name[] = "__start"; | ||||
| const char __fsym_begin_desc[] = "begin of finsh"; | ||||
| __declspec(allocate("FSymTab$a")) const struct finsh_syscall __fsym_begin = | ||||
| { | ||||
|     __fsym_begin_name, | ||||
|     __fsym_begin_desc, | ||||
|     NULL | ||||
| }; | ||||
|  | ||||
| #pragma section("FSymTab$z", read) | ||||
| const char __fsym_end_name[] = "__end"; | ||||
| const char __fsym_end_desc[] = "end of finsh"; | ||||
| __declspec(allocate("FSymTab$z")) const struct finsh_syscall __fsym_end = | ||||
| { | ||||
|     __fsym_end_name, | ||||
|     __fsym_end_desc, | ||||
|     NULL | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * @ingroup finsh | ||||
|  * | ||||
|  * This function will initialize finsh shell | ||||
|  */ | ||||
| int finsh_system_init(void) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_thread_t tid; | ||||
|  | ||||
| #ifdef FINSH_USING_SYMTAB | ||||
| #if defined(__CC_ARM) || defined(__CLANG_ARM)          /* ARM C Compiler */ | ||||
|     extern const int FSymTab$$Base; | ||||
|     extern const int FSymTab$$Limit; | ||||
|     extern const int VSymTab$$Base; | ||||
|     extern const int VSymTab$$Limit; | ||||
|     finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit); | ||||
| #ifndef FINSH_USING_MSH_ONLY | ||||
|     finsh_system_var_init(&VSymTab$$Base, &VSymTab$$Limit); | ||||
| #endif | ||||
| #elif defined (__ICCARM__) || defined(__ICCRX__)      /* for IAR Compiler */ | ||||
|     finsh_system_function_init(__section_begin("FSymTab"), | ||||
|                                __section_end("FSymTab")); | ||||
|     finsh_system_var_init(__section_begin("VSymTab"), | ||||
|                           __section_end("VSymTab")); | ||||
| #elif defined (__GNUC__) || defined(__TI_COMPILER_VERSION__) | ||||
|     /* GNU GCC Compiler and TI CCS */ | ||||
|     extern const int __fsymtab_start; | ||||
|     extern const int __fsymtab_end; | ||||
|     extern const int __vsymtab_start; | ||||
|     extern const int __vsymtab_end; | ||||
|     finsh_system_function_init(&__fsymtab_start, &__fsymtab_end); | ||||
|     finsh_system_var_init(&__vsymtab_start, &__vsymtab_end); | ||||
| #elif defined(__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */ | ||||
|     finsh_system_function_init(&__fsymtab_start, &__fsymtab_end); | ||||
|     finsh_system_var_init(&__vsymtab_start, &__vsymtab_end); | ||||
| #elif defined(_MSC_VER) | ||||
|     unsigned int *ptr_begin, *ptr_end; | ||||
|  | ||||
|     if(shell) | ||||
|     { | ||||
|         rt_kprintf("finsh shell already init.\n"); | ||||
|         return RT_EOK; | ||||
|     } | ||||
|  | ||||
|     ptr_begin = (unsigned int *)&__fsym_begin; | ||||
|     ptr_begin += (sizeof(struct finsh_syscall) / sizeof(unsigned int)); | ||||
|     while (*ptr_begin == 0) ptr_begin ++; | ||||
|  | ||||
|     ptr_end = (unsigned int *) &__fsym_end; | ||||
|     ptr_end --; | ||||
|     while (*ptr_end == 0) ptr_end --; | ||||
|  | ||||
|     finsh_system_function_init(ptr_begin, ptr_end); | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef RT_USING_HEAP | ||||
|     /* create or set shell structure */ | ||||
|     shell = (struct finsh_shell *)rt_calloc(1, sizeof(struct finsh_shell)); | ||||
|     if (shell == RT_NULL) | ||||
|     { | ||||
|         rt_kprintf("no memory for shell\n"); | ||||
|         return -1; | ||||
|     } | ||||
|     tid = rt_thread_create(FINSH_THREAD_NAME, | ||||
|                            finsh_thread_entry, RT_NULL, | ||||
|                            FINSH_THREAD_STACK_SIZE, FINSH_THREAD_PRIORITY, 10); | ||||
| #else | ||||
|     shell = &_shell; | ||||
|     tid = &finsh_thread; | ||||
|     result = rt_thread_init(&finsh_thread, | ||||
|                             FINSH_THREAD_NAME, | ||||
|                             finsh_thread_entry, RT_NULL, | ||||
|                             &finsh_thread_stack[0], sizeof(finsh_thread_stack), | ||||
|                             FINSH_THREAD_PRIORITY, 10); | ||||
| #endif /* RT_USING_HEAP */ | ||||
|  | ||||
|     rt_sem_init(&(shell->rx_sem), "shrx", 0, 0); | ||||
|     finsh_set_prompt_mode(1); | ||||
|  | ||||
|     if (tid != NULL && result == RT_EOK) | ||||
|         rt_thread_startup(tid); | ||||
|     return 0; | ||||
| } | ||||
| INIT_APP_EXPORT(finsh_system_init); | ||||
|  | ||||
| #endif /* RT_USING_FINSH */ | ||||
|  | ||||
							
								
								
									
										110
									
								
								source/rt_thread/components/finsh/shell.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								source/rt_thread/components/finsh/shell.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2021, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2011-06-02     Bernard      Add finsh_get_prompt function declaration | ||||
|  */ | ||||
|  | ||||
| #ifndef __SHELL_H__ | ||||
| #define __SHELL_H__ | ||||
|  | ||||
| #include <rtthread.h> | ||||
| #include "finsh.h" | ||||
|  | ||||
| #ifndef FINSH_THREAD_PRIORITY | ||||
| #define FINSH_THREAD_PRIORITY 20 | ||||
| #endif | ||||
| #ifndef FINSH_THREAD_STACK_SIZE | ||||
| #define FINSH_THREAD_STACK_SIZE 2048 | ||||
| #endif | ||||
| #ifndef FINSH_CMD_SIZE | ||||
| #define FINSH_CMD_SIZE      80 | ||||
| #endif | ||||
|  | ||||
| #define FINSH_OPTION_ECHO   0x01 | ||||
|  | ||||
| #define FINSH_PROMPT        finsh_get_prompt() | ||||
| const char* finsh_get_prompt(void); | ||||
| int finsh_set_prompt(const char * prompt); | ||||
|  | ||||
| #ifdef FINSH_USING_HISTORY | ||||
|     #ifndef FINSH_HISTORY_LINES | ||||
|         #define FINSH_HISTORY_LINES 5 | ||||
|     #endif | ||||
| #endif | ||||
|  | ||||
| #ifdef FINSH_USING_AUTH | ||||
|     #ifndef FINSH_PASSWORD_MAX | ||||
|         #define FINSH_PASSWORD_MAX RT_NAME_MAX | ||||
|     #endif | ||||
|     #ifndef FINSH_PASSWORD_MIN | ||||
|         #define FINSH_PASSWORD_MIN 6 | ||||
|     #endif | ||||
|     #ifndef FINSH_DEFAULT_PASSWORD | ||||
|         #define FINSH_DEFAULT_PASSWORD "rtthread" | ||||
|     #endif | ||||
| #endif /* FINSH_USING_AUTH */ | ||||
|  | ||||
| #ifndef FINSH_THREAD_NAME | ||||
| #define FINSH_THREAD_NAME   "tshell" | ||||
| #endif | ||||
|  | ||||
| enum input_stat | ||||
| { | ||||
|     WAIT_NORMAL, | ||||
|     WAIT_SPEC_KEY, | ||||
|     WAIT_FUNC_KEY, | ||||
| }; | ||||
| struct finsh_shell | ||||
| { | ||||
|     struct rt_semaphore rx_sem; | ||||
|  | ||||
|     enum input_stat stat; | ||||
|  | ||||
|     rt_uint8_t echo_mode:1; | ||||
|     rt_uint8_t prompt_mode: 1; | ||||
|  | ||||
| #ifdef FINSH_USING_HISTORY | ||||
|     rt_uint16_t current_history; | ||||
|     rt_uint16_t history_count; | ||||
|  | ||||
|     char cmd_history[FINSH_HISTORY_LINES][FINSH_CMD_SIZE]; | ||||
| #endif | ||||
|  | ||||
| #ifndef FINSH_USING_MSH_ONLY | ||||
|     struct finsh_parser parser; | ||||
| #endif | ||||
|  | ||||
|     char line[FINSH_CMD_SIZE]; | ||||
|     rt_uint16_t line_position; | ||||
|     rt_uint16_t line_curpos; | ||||
|  | ||||
| #if !defined(RT_USING_POSIX) && defined(RT_USING_DEVICE) | ||||
|     rt_device_t device; | ||||
| #endif | ||||
|  | ||||
| #ifdef FINSH_USING_AUTH | ||||
|     char password[FINSH_PASSWORD_MAX]; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| void finsh_set_echo(rt_uint32_t echo); | ||||
| rt_uint32_t finsh_get_echo(void); | ||||
|  | ||||
| int finsh_system_init(void); | ||||
| void finsh_set_device(const char* device_name); | ||||
| const char* finsh_get_device(void); | ||||
|  | ||||
| rt_uint32_t finsh_get_prompt_mode(void); | ||||
| void finsh_set_prompt_mode(rt_uint32_t prompt_mode); | ||||
|  | ||||
| #ifdef FINSH_USING_AUTH | ||||
| rt_err_t finsh_set_password(const char *password); | ||||
| const char *finsh_get_password(void); | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 andy
					andy