| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053 |
- /*
- * Copyright (c) 2022, Egahp
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <stdio.h>
- #include <stdarg.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <string.h>
- #include <signal.h>
- #include "csh.h"
- #include "CherryRL/chry_readline.c"
- #if defined(CONFIG_CSH_DEBUG) && CONFIG_CSH_DEBUG
- #define CHRY_SHELL_PARAM_CHECK(__expr, __ret) \
- do { \
- if (!(__expr)) { \
- return __ret; \
- } \
- } while (0)
- #else
- #define CHRY_SHELL_PARAM_CHECK(__expr, __ret) ((void)0)
- #endif
- #if defined(__CC_ARM) || defined(__CLANG_ARM) || defined(__GNUC__) || defined(__ADSPBLACKFIN__) || defined(__ICCARM__) || defined(__ICCRX__) || defined(__ICCRISCV__)
- #ifndef __weak
- #define __weak __attribute__((weak))
- #endif
- #else
- #ifndef __weak
- #define __weak
- #endif
- #endif
- #define chry_shell_offsetof(type, member) ((size_t) & (((type *)0)->member))
- #define chry_shell_container_of(ptr, type, member) ((type *)((char *)(ptr)-chry_shell_offsetof(type, member)))
- /*!< prompt segment index */
- #define CSH_PROMPT_SEG_USER 0
- #define CSH_PROMPT_SEG_HOST 2
- #define CSH_PROMPT_SEG_PATH 4
- extern void chry_shell_port_default_handler(chry_shell_t *csh, int sig);
- extern int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **argv);
- extern int chry_shell_port_hash_strcmp(const char *hash, const char *str);
- #if defined(CONFIG_CSH_MULTI_THREAD) && CONFIG_CSH_MULTI_THREAD
- /* static const uint8_t sigmap[CSH_SIGNAL_COUNT] = { CSH_SIGINT, CSH_SIGQUIT, CSH_SIGKILL, CSH_SIGTERM, CSH_SIGSTOP, CSH_SIGTSTP, CSH_SIGCONT }; */
- #if !defined(CONFIG_CSH_SIGNAL_HANDLER) || (CONFIG_CSH_SIGNAL_HANDLER == 0)
- static chry_sighandler_t sighdl[CSH_SIGNAL_COUNT] = {
- chry_shell_port_default_handler,
- chry_shell_port_default_handler,
- chry_shell_port_default_handler,
- chry_shell_port_default_handler,
- chry_shell_port_default_handler,
- chry_shell_port_default_handler,
- chry_shell_port_default_handler,
- };
- #endif
- /*****************************************************************************
- * @brief default signal handler
- *
- * @param[in] signum signal number
- *
- *****************************************************************************/
- __weak void chry_shell_port_default_handler(chry_shell_t *csh, int sig)
- {
- (void)csh;
- switch (sig) {
- case CSH_SIGINT:
- break;
- case CSH_SIGQUIT:
- break;
- case CSH_SIGKILL:
- break;
- case CSH_SIGTERM:
- break;
- case CSH_SIGSTOP:
- break;
- case CSH_SIGTSTP:
- break;
- case CSH_SIGCONT:
- break;
- default:
- break;
- }
- }
- /*****************************************************************************
- * @brief create context to execute
- *
- * @param[in] csh shell instance
- * @param[in] argc argument count
- * @param[in] argv argument value
- *
- * @retval 0:success -1:error
- *****************************************************************************/
- __weak int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **argv)
- {
- (void)csh;
- (void)argc;
- (void)argv;
- return -1;
- }
- /*****************************************************************************
- * @brief conversion signum
- *
- * @param[in] signum signal number
- *
- * @retval 0<= signal index -1:not find
- *****************************************************************************/
- /*
- static int chry_shell_conversion_signum(int signum)
- {
- int sigidx = -1;
- for (uint8_t i = 0; i < CSH_SIGNAL_COUNT; i++) {
- if (sigmap[i] == signum) {
- sigidx = i;
- break;
- }
- }
- return sigidx;
- }
- */
- #endif
- /*****************************************************************************
- * @brief hash str then compare
- *
- * @param[in] hash hash
- * @param[in] str string
- *
- * @retval 0:Equal 1:hash>str -1:str>hash
- *****************************************************************************/
- __weak int chry_shell_port_hash_strcmp(const char *hash, const char *str)
- {
- /*!< simple demo */
- return strcmp(hash, str);
- }
- #if defined(CONFIG_CSH_COMPLETION) && CONFIG_CSH_COMPLETION
- /*****************************************************************************
- * @brief completion callback
- *
- * @param[in] rl readline instance
- * @param[in] pre pre string
- * @param[in] size strlen(pre)
- * @param[in] argv argument value (completion)
- * @param[in] argl argument length (completion length)
- * @param[in] argcmax argument max count (max completion count)
- *
- * @retval argc:argument count, max is argcmax
- *****************************************************************************/
- static uint8_t chry_shell_completion_callback(chry_readline_t *rl, char *pre, uint16_t *size, const char **argv, uint8_t *argl, uint8_t argcmax)
- {
- chry_shell_t *csh = chry_shell_container_of(rl, chry_shell_t, rl);
- uint8_t argc = 0;
- if (*size == 0) {
- return argc;
- }
- /*!< environment variable */
- if (*size && pre[0] == '$') {
- pre++; /*!< skip $ */
- *size = *size - 1; /*!< skip $ */
- for (const chry_sysvar_t *var = csh->var_tbl_beg; var < csh->var_tbl_end; var++) {
- if (strncmp(pre, var->name, *size) == 0) {
- argv[argc] = var->name;
- argl[argc] = strlen(var->name);
- argc++;
- if (argc >= argcmax) {
- break;
- }
- }
- }
- return argc;
- }
- const char *PATH = NULL;
- uint8_t Pargc;
- uint8_t Pargl[CONFIG_CSH_MAXSEG_PATH + 1];
- const char *Pargv[CONFIG_CSH_MAXSEG_PATH + 1];
- if (((*size >= 1) && (pre[0] == '/')) ||
- ((*size >= 2) && (pre[0] == '.') && (pre[1] == '/')) ||
- ((*size >= 3) && (pre[0] == '.') && (pre[1] == '.') && (pre[2] == '/'))) {
- /*!< search from the current path */
- PATH = csh->path;
- } else {
- /*!< search from the environment PATH */
- for (const chry_sysvar_t *var = csh->var_tbl_beg; var < csh->var_tbl_end; var++) {
- if (strcmp("PATH", var->name) == 0) {
- PATH = var->var;
- break;
- }
- }
- }
- while (PATH != NULL) {
- Pargc = chry_shell_path_resolve(PATH, pre, Pargv, Pargl, CONFIG_CSH_MAXSEG_PATH + 1);
- *size = Pargl[Pargc - 1];
- /*!< match from system path */
- for (const chry_syscall_t *call = csh->cmd_tbl_beg; call < csh->cmd_tbl_end; call++) {
- uint8_t clen = 0;
- const char *cpath_next;
- const char *cpath_prev = NULL;
- const char *cpath = call->path;
- bool match = true;
- for (uint8_t Pargi = 0;; Pargi++) {
- if (Pargi >= Pargc) {
- bool exist = false;
- for (uint8_t i = 0; i < argc; i++) {
- if ((clen == argl[i]) && (strncmp(argv[i], cpath_prev, clen) == 0)) {
- exist = true;
- break;
- }
- }
- if (exist == false) {
- argv[argc] = cpath_prev;
- argl[argc] = clen;
- argc++;
- if (argc >= argcmax) {
- return argc;
- }
- }
- break;
- }
- if ((cpath == NULL) || (match == false)) {
- break;
- }
- cpath++;
- if (strncmp(cpath, Pargv[Pargi], Pargl[Pargi]) != 0) {
- break;
- }
- cpath_next = strchr(cpath, '/');
- if (cpath_next == NULL) {
- clen = strlen(cpath);
- } else {
- clen = (uint8_t)(cpath_next - cpath);
- }
- match = (clen == Pargl[Pargi]);
- cpath_prev = cpath;
- if (cpath != call->name) {
- cpath = cpath_next == NULL ? (call->name - 1) : cpath_next;
- } else {
- cpath = cpath_next;
- }
- }
- }
- /*!< match from port of file system */
- PATH = strchr(PATH, ':');
- PATH = (PATH != NULL) ? PATH + 1 : PATH;
- }
- return argc;
- }
- #endif
- #if defined(CONFIG_CSH_USER_CALLBACK) && CONFIG_CSH_USER_CALLBACK
- /*****************************************************************************
- * @brief user callback
- *
- * @param[in] rl readline instance
- * @param[in] exec exec code
- *
- * @retval status
- *****************************************************************************/
- static int chry_shell_user_callback(chry_readline_t *rl, uint8_t exec)
- {
- chry_shell_t *csh = chry_shell_container_of(rl, chry_shell_t, rl);
- (void)csh;
- /*!< user event callback will not output newline automatically */
- switch (exec) {
- case CHRY_READLINE_EXEC_EOF:
- chry_readline_newline(rl);
- break;
- #if defined(CONFIG_CSH_MULTI_THREAD) && CONFIG_CSH_MULTI_THREAD
- #if defined(CONFIG_CSH_SIGNAL_HANDLER) && CONFIG_CSH_SIGNAL_HANDLER
- case CHRY_READLINE_EXEC_SIGINT:
- csh->sighdl[0](csh, CSH_SIGINT);
- return 0;
- case CHRY_READLINE_EXEC_SIGQUIT:
- csh->sighdl[1](csh, CSH_SIGQUIT);
- return 0;
- case CHRY_READLINE_EXEC_SIGCONT:
- csh->sighdl[6](csh, CSH_SIGCONT);
- return 1;
- case CHRY_READLINE_EXEC_SIGSTOP:
- csh->sighdl[4](csh, CSH_SIGSTOP);
- return 1;
- case CHRY_READLINE_EXEC_SIGTSTP:
- csh->sighdl[5](csh, CSH_SIGTSTP);
- return 1;
- #else
- case CHRY_READLINE_EXEC_SIGINT:
- sighdl[0](csh, CSH_SIGINT);
- return 0;
- case CHRY_READLINE_EXEC_SIGQUIT:
- sighdl[1](csh, CSH_SIGQUIT);
- return 0;
- case CHRY_READLINE_EXEC_SIGCONT:
- sighdl[6](csh, CSH_SIGCONT);
- return 1;
- case CHRY_READLINE_EXEC_SIGSTOP:
- sighdl[4](csh, CSH_SIGSTOP);
- return 1;
- case CHRY_READLINE_EXEC_SIGTSTP:
- sighdl[5](csh, CSH_SIGTSTP);
- return 1;
- #endif
- #else
- case CHRY_READLINE_EXEC_SIGINT:
- return 0;
- case CHRY_READLINE_EXEC_SIGQUIT:
- return 0;
- case CHRY_READLINE_EXEC_SIGCONT:
- return 1;
- case CHRY_READLINE_EXEC_SIGSTOP:
- return 1;
- case CHRY_READLINE_EXEC_SIGTSTP:
- return 1;
- #endif
- case CHRY_READLINE_EXEC_F1 ... CHRY_READLINE_EXEC_F12:
- chry_readline_newline(rl);
- break;
- case CHRY_READLINE_EXEC_USER ... CHRY_READLINE_EXEC_END:
- chry_readline_newline(rl);
- break;
- default:
- return -1;
- }
- /*!< return 1 will not refresh */
- /*!< return 0 to refresh whole line (include prompt) */
- /*!< return -1 to end readline (error) */
- return 0;
- }
- #endif
- /*****************************************************************************
- * @brief init shell
- *
- * @param[in] csh shell instance
- * @param[in] init init config
- *
- * @retval 0:Success -1:Error
- *****************************************************************************/
- int chry_shell_init(chry_shell_t *csh, const chry_shell_init_t *init)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, -1);
- CHRY_SHELL_PARAM_CHECK(NULL != init, -1);
- CHRY_SHELL_PARAM_CHECK(NULL != init->sget, -1);
- CHRY_SHELL_PARAM_CHECK(NULL != init->sput, -1);
- #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT
- CHRY_SHELL_PARAM_CHECK(NULL != init->prompt_buffer, -1);
- #endif
- #if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY
- CHRY_SHELL_PARAM_CHECK(NULL != init->history_buffer, -1);
- #endif
- #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC
- CHRY_SHELL_PARAM_CHECK(NULL != init->line_buffer, -1);
- #endif
- int ret = 0;
- chry_readline_init_t rl_init;
- /*!< do readline init */
- #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT
- rl_init.prompt = init->prompt_buffer;
- rl_init.pptsize = init->prompt_buffer_size;
- #else
- rl_init.prompt = "$ ";
- rl_init.pptsize = 3;
- #endif
- rl_init.history = init->history_buffer;
- rl_init.histsize = init->history_buffer_size;
- rl_init.sput = init->sput;
- rl_init.sget = init->sget;
- if (chry_readline_init(&csh->rl, &rl_init)) {
- return -1;
- }
- csh->cmd_tbl_beg = init->command_table_beg;
- csh->cmd_tbl_end = init->command_table_end;
- csh->var_tbl_beg = init->variable_table_beg;
- csh->var_tbl_end = init->variable_table_end;
- #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC
- csh->linebuff = init->line_buffer;
- csh->buffsize = init->line_buffer_size;
- csh->linesize = 0;
- #endif
- csh->exec_code = 0;
- csh->exec = CSH_STATUS_EXEC_IDLE;
- /*!< set default user id */
- if ((init->uid >= CONFIG_CSH_MAX_USER) || (init->uid < 0)) {
- return -1;
- }
- csh->uid = init->uid;
- /*!< set host name */
- if (strnlen(init->host, 255) == 255) {
- return -1;
- }
- csh->host = init->host;
- /*!< set users name */
- for (uint8_t i = 0; i < CONFIG_CSH_MAX_USER; i++) {
- if (strnlen(init->user[i], 255) == 255) {
- return -1;
- }
- if (strnlen(init->hash[i], 255) == 255) {
- return -1;
- }
- csh->user[i] = init->user[i];
- csh->hash[i] = init->hash[i];
- }
- /*!< set default path */
- #if defined(CONFIG_CSH_MAXLEN_PATH) && CONFIG_CSH_MAXLEN_PATH
- csh->path[0] = '/';
- csh->path[1] = '\0';
- #else
- csh->path = "/";
- #endif
- csh->data = NULL;
- csh->user_data = init->user_data;
- #if defined(CONFIG_CSH_COMPLETION) && CONFIG_CSH_COMPLETION
- chry_readline_set_completion_cb(&csh->rl, chry_shell_completion_callback);
- #endif
- #if defined(CONFIG_CSH_USER_CALLBACK) && CONFIG_CSH_USER_CALLBACK
- chry_readline_set_user_cb(&csh->rl, chry_shell_user_callback);
- #endif
- #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT
- ret |= chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_USER, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_GREEN, .bold = 1 }.raw, csh->user[csh->uid]);
- ret |= chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_USER + 1, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_GREEN, .bold = 1 }.raw, "@");
- ret |= chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_HOST, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_GREEN, .bold = 1 }.raw, csh->host);
- ret |= chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_HOST + 1, 0, ":");
- ret |= chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_PATH, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_BLUE, .bold = 1 }.raw, csh->path);
- ret |= chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_PATH + 1, 0, "$ ");
- #else
- #endif
- return ret;
- }
- /*****************************************************************************
- * @brief execute task internal
- *
- * @param[in] csh shell instance
- *
- *****************************************************************************/
- static void chry_shell_task_exec_internal(chry_shell_t *csh, int argc, const char **argv)
- {
- volatile uint8_t *pexec = (void *)&csh->exec;
- volatile int *pcode = (void *)&csh->exec_code;
- /*!< if stage find */
- if (*pexec == CSH_STATUS_EXEC_FIND) {
- /*!< stage prepare */
- *pexec = CSH_STATUS_EXEC_PREP;
- *pcode = ((chry_syscall_func_t)argv[argc + 2])(argc, (void *)argv);
- /*!< stage done */
- *pexec = CSH_STATUS_EXEC_DONE;
- }
- }
- /*****************************************************************************
- * @brief execute task
- *
- * @param[in] csh shell instance
- *
- *****************************************************************************/
- void chry_shell_task_exec(chry_shell_t *csh)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, );
- (void)csh;
- #if defined(CONFIG_CSH_MULTI_THREAD) && CONFIG_CSH_MULTI_THREAD
- chry_shell_task_exec_internal(csh, csh->exec_argc, &csh->exec_argv[0]);
- #endif
- }
- /*****************************************************************************
- * @brief read eval print loop task
- *
- * @param[in] csh shell instance
- *
- * @retval 0:Success -1:Error 1:Continue
- *****************************************************************************/
- int chry_shell_task_repl(chry_shell_t *csh)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, -1);
- char *csh_linebuff;
- uint16_t *csh_linesize;
- #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC
- csh_linebuff = csh->linebuff;
- csh_linesize = &csh->linesize;
- char *line = chry_readline(&csh->rl, csh_linebuff, csh->buffsize, csh_linesize);
- #else
- char linebuff[CONFIG_CSH_LNBUFF_SIZE];
- uint16_t linesize;
- csh_linebuff = linebuff;
- csh_linesize = &linesize;
- char *line = chry_readline(&csh->rl, csh_linebuff, CONFIG_CSH_LNBUFF_SIZE, csh_linesize);
- #endif
- if (line == NULL) {
- return -1;
- } else if (line == (void *)-1) {
- return 1;
- } else if (*csh_linesize) {
- int *argc;
- const char **argv;
- volatile uint8_t *pexec = (void *)&csh->exec;
- volatile uint32_t *pcode = (void *)&csh->exec_code;
- *pcode = 0xBAD2BE8E; /*!< a magic number */
- #if defined(CONFIG_CSH_MULTI_THREAD) && CONFIG_CSH_MULTI_THREAD
- argc = &csh->exec_argc;
- argv = &csh->exec_argv[0];
- #else
- int csh_exec_argc;
- const char *csh_exec_argv[CONFIG_CSH_MAX_ARG + 3];
- argc = &csh_exec_argc;
- argv = &csh_exec_argv[0];
- #endif
- *argc = chry_shell_parse(line, *csh_linesize, argv, CONFIG_CSH_MAX_ARG + 1);
- /*!< compile environment variable */
- for (uint8_t i = 0; i < *argc;) {
- if (argv[i][0] == '$') {
- const char *param = chry_shell_getenv(csh, argv[i] + 1);
- if (param == NULL) {
- memmove(&argv[i], &argv[i + 1], (*argc - i) * sizeof(char *));
- *argc = (*argc > 0) ? *argc - 1 : 0;
- } else {
- argv[i] = param;
- i++;
- }
- } else {
- i++;
- }
- }
- argv[*argc + 1] = (void *)csh;
- argv[*argc + 2] = NULL;
- if (*argc) {
- uint8_t size = strlen(argv[0]);
- const char *PATH = NULL;
- uint8_t Pargc;
- uint8_t Pargl[CONFIG_CSH_MAXSEG_PATH + 1];
- const char *Pargv[CONFIG_CSH_MAXSEG_PATH + 1];
- if (((size >= 1) && (argv[0][0] == '/')) ||
- ((size >= 2) && (argv[0][0] == '.') && (argv[0][1] == '/')) ||
- ((size >= 3) && (argv[0][0] == '.') && (argv[0][1] == '.') && (argv[0][2] == '/'))) {
- /*!< search from the current path */
- PATH = csh->path;
- } else {
- /*!< search from the environment PATH */
- for (const chry_sysvar_t *var = csh->var_tbl_beg; var < csh->var_tbl_end; var++) {
- if (strcmp("PATH", var->name) == 0) {
- PATH = var->var;
- break;
- }
- }
- }
- while (PATH != NULL) {
- Pargc = chry_shell_path_resolve(PATH, argv[0], Pargv, Pargl, CONFIG_CSH_MAXSEG_PATH + 1);
- /*!< match from system path */
- for (const chry_syscall_t *call = csh->cmd_tbl_beg; call < csh->cmd_tbl_end; call++) {
- uint8_t clen = 0;
- const char *cpath_next;
- const char *cpath = call->path;
- for (uint8_t Pargi = 0;; Pargi++) {
- if (Pargi >= Pargc) {
- if (cpath == NULL) {
- /*!< match success */
- argv[*argc + 2] = (void *)call->func;
- goto found;
- } else {
- /*!< argv[0] end */
- break;
- }
- }
- if (cpath == NULL) {
- /*!< path+name end */
- break;
- }
- cpath++;
- if (strncmp(cpath, Pargv[Pargi], Pargl[Pargi]) != 0) {
- /*!< match failed */
- break;
- }
- cpath_next = strchr(cpath, '/');
- if (cpath_next == NULL) {
- clen = strlen(cpath);
- } else {
- clen = (uint8_t)(cpath_next - cpath);
- }
- if (clen != Pargl[Pargi]) {
- /*!< len not equal */
- break;
- }
- if (cpath != call->name) {
- cpath = cpath_next == NULL ? (call->name - 1) : cpath_next;
- } else {
- cpath = cpath_next;
- }
- }
- }
- /*!< match from port of file system */
- PATH = strchr(PATH, ':');
- PATH = (PATH != NULL) ? PATH + 1 : PATH;
- }
- found:
- if (NULL == argv[*argc + 2]) {
- *pexec = CSH_STATUS_EXEC_IDLE;
- csh->rl.sput(&csh->rl, argv[0], strlen(argv[0]));
- csh->rl.sput(&csh->rl, ": command not found" CONFIG_CSH_NEWLINE CONFIG_CSH_NEWLINE,
- 19 + (sizeof(CONFIG_CSH_NEWLINE) ? (sizeof(CONFIG_CSH_NEWLINE) - 1) * 2 : 0));
- } else {
- #if defined(CONFIG_CSH_MULTI_THREAD) && CONFIG_CSH_MULTI_THREAD
- *pexec = CSH_STATUS_EXEC_FIND;
- chry_readline_ignore(&csh->rl, true); /*!< accepts only signal inputs */
- chry_readline_auto_refresh(&csh->rl, false);
- /*!< reset signal handler to default */
- for (uint8_t i = 0; i < CSH_SIGNAL_COUNT; i++) {
- #if defined(CONFIG_CSH_SIGNAL_HANDLER) && CONFIG_CSH_SIGNAL_HANDLER
- csh->sighdl[i] = chry_shell_port_default_handler;
- #else
- sighdl[i] = chry_shell_port_default_handler;
- #endif
- }
- /*!< try to create execute context */
- if (0 != chry_shell_port_create_context(csh, *argc, argv)) {
- *pexec = CSH_STATUS_EXEC_IDLE;
- csh->rl.sput(&csh->rl, argv[0], strlen(argv[0]));
- csh->rl.sput(&csh->rl, ": context creation error" CONFIG_CSH_NEWLINE CONFIG_CSH_NEWLINE,
- 24 + (sizeof(CONFIG_CSH_NEWLINE) ? (sizeof(CONFIG_CSH_NEWLINE) - 1) * 2 : 0));
- }
- #else
- *pexec = CSH_STATUS_EXEC_FIND;
- chry_shell_task_exec_internal(csh, *argc, argv);
- *pexec = CSH_STATUS_EXEC_IDLE;
- #endif
- }
- }
- return 0;
- }
- return 0;
- }
- /*****************************************************************************
- * @brief parse line to argc,argv[]
- *
- * @param[in] line read line
- * @param[in] linesize strlen(line)
- * @param[out] argv argument value
- * @param[out] argcmax max argument count (max segment count)
- *
- * @retval argc:argument count, max is argcmax
- *****************************************************************************/
- int chry_shell_parse(char *line, uint32_t linesize, const char **argv, uint8_t argcmax)
- {
- int argc = 0;
- bool ignore = false;
- bool start = false;
- bool escape = false;
- argcmax = (argcmax > 0) ? argcmax - 1 : argcmax;
- while (linesize) {
- char c = *line;
- if (c == '\0') {
- break;
- } else if ((escape == false) && (c == '\\')) {
- escape = true;
- memmove(line, line + 1, linesize);
- line--;
- } else if ((escape == false) && (ignore == false) && (c == ' ')) {
- start = false;
- *line = '\0';
- } else if ((escape == false) && (c == '"')) {
- memmove(line, line + 1, linesize);
- line--;
- ignore = !ignore;
- } else if (!start) {
- argv[argc] = line;
- if (argc < argcmax) {
- argc++;
- } else {
- break;
- }
- start = true;
- escape = false;
- } else {
- escape = false;
- }
- line++;
- linesize--;
- }
- *line = '\0';
- argv[argc] = NULL;
- return argc;
- }
- /*****************************************************************************
- * @brief resolve path to argc,argv[],argl[]
- *
- * @param[in] cur current path
- * @param[in] path path
- * @param[out] argv argument value (path segment)
- * @param[out] argl argument length (path segment length)
- * @param[out] argcmax argument max count (max segment count)
- *
- * @retval argc:argument count, max is argcmax
- *****************************************************************************/
- int chry_shell_path_resolve(const char *cur, const char *path, const char **argv, uint8_t *argl, uint8_t argcmax)
- {
- uint8_t len;
- uint8_t argc = 0;
- bool expr;
- if (cur == NULL || path == NULL) {
- return argc;
- }
- expr = (*path == '/') || ((cur[0] == '/') && (cur[1] == '\0'));
- if (expr) {
- cur = path;
- }
- argcmax = (argcmax > 0) ? argcmax - 1 : argcmax;
- resolve:
- while ((cur != NULL) && (*cur != '\0') && (*cur != ':')) {
- while (*cur == '/') {
- cur++;
- }
- argv[argc] = cur;
- cur = strchr(cur, '/');
- if (cur == NULL) {
- len = strlen(argv[argc]);
- } else {
- len = (uint8_t)(cur - argv[argc]);
- const char *sep = memchr(argv[argc], ':', len);
- if (sep != NULL) {
- len = (uint8_t)(sep - argv[argc]);
- cur = NULL;
- }
- }
- if (len == 1) {
- bool match_dot1 = argv[argc][0] == '.';
- if (!match_dot1) {
- argl[argc] = len;
- argc++;
- }
- } else if (len == 2) {
- bool match_dot1 = argv[argc][0] == '.';
- bool match_dot2 = argv[argc][1] == '.';
- if (match_dot1 && match_dot2) {
- if (argc > 0) {
- argc--;
- }
- } else {
- argl[argc] = len;
- argc++;
- }
- } else {
- argl[argc] = len;
- argc++;
- }
- if (argc >= argcmax) {
- argv[argc] = NULL;
- argl[argc] = 0;
- return argcmax;
- }
- }
- if (!expr) {
- cur = path;
- expr = true;
- goto resolve;
- }
- argv[argc] = NULL;
- argl[argc] = 0;
- return argc;
- }
- /*****************************************************************************
- * @brief set host
- *
- * @param[in] csh shell instance
- * @param[in] host pointer of host
- *
- * @retval 0:Success -1:Error
- *****************************************************************************/
- int chry_shell_set_host(chry_shell_t *csh, const char *host)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, -1);
- CHRY_SHELL_PARAM_CHECK(NULL != host, -1);
- if (strnlen(host, 255) == 255) {
- return -1;
- }
- csh->host = host;
- return chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_HOST, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_GREEN, .bold = 1 }.raw, csh->host);
- }
- /*****************************************************************************
- * @brief set user
- *
- * @param[in] csh shell instance
- * @param[in] uid user id
- * @param[in] user pointer of user
- * @param[in] user pointer of user password hash
- *
- * @retval 0:Success -1:Error
- *****************************************************************************/
- int chry_shell_set_user(chry_shell_t *csh, uint8_t uid, const char *user, const char *hash)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, -1);
- CHRY_SHELL_PARAM_CHECK(NULL != user, -1);
- if (uid < CONFIG_CSH_MAX_USER) {
- if (strnlen(user, 255) == 255) {
- return -1;
- }
- if (strnlen(hash, 255) == 255) {
- return -1;
- }
- csh->user[uid] = user;
- csh->hash[uid] = hash;
- if (uid == csh->uid) {
- return chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_USER, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_GREEN, .bold = 1 }.raw, csh->user[uid]);
- }
- return 0;
- }
- return -1;
- }
- /*****************************************************************************
- * @brief set path
- *
- * @param[in] csh shell instance
- * @param[in] size strlen(path) + 1, include \0.
- * ignore when CONFIG_CSH_MAXLEN_PATH = 0
- * @param[in] path shell instance
- *
- * @retval 0:Success -1:Error
- *****************************************************************************/
- int chry_shell_set_path(chry_shell_t *csh, uint8_t size, const char *path)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, -1);
- CHRY_SHELL_PARAM_CHECK(NULL != path, -1);
- #if defined(CONFIG_CSH_MAXLEN_PATH) && CONFIG_CSH_MAXLEN_PATH
- if (size > CONFIG_CSH_MAXLEN_PATH) {
- return -1;
- }
- memcpy(csh->path, path, size);
- csh->path[size] = '\0';
- #else
- if (strnlen(path, 255) == 255) {
- return -1;
- }
- csh->path = path;
- #endif
- return chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_PATH, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_BLUE, .bold = 1 }.raw, csh->path);
- }
- /*****************************************************************************
- * @brief get path
- *
- * @param[in] csh shell instance
- * @param[in] size path buffer size
- * @param[in] path path buffer
- *
- *****************************************************************************/
- void chry_shell_get_path(chry_shell_t *csh, uint8_t size, char *path)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, );
- CHRY_SHELL_PARAM_CHECK(NULL != path, );
- #if defined(CONFIG_CSH_MAXLEN_PATH) && CONFIG_CSH_MAXLEN_PATH
- size = size < CONFIG_CSH_MAXLEN_PATH ? size : CONFIG_CSH_MAXLEN_PATH;
- #endif
- strncpy(path, csh->path, size);
- path[size - 1] = '\0';
- }
- /*****************************************************************************
- * @brief substitute user
- *
- * @param[in] csh shell instance
- * @param[in] uid user id
- * @param[in] password password
- *
- * @retval 0:Success -1:Error
- *****************************************************************************/
- int chry_shell_substitute_user(chry_shell_t *csh, uint8_t uid, const char *password)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, -1);
- if (uid < CONFIG_CSH_MAX_USER) {
- if (csh->hash[uid]) {
- if (chry_shell_port_hash_strcmp(csh->hash[uid], password) != 0) {
- return -1;
- }
- }
- csh->uid = uid;
- return chry_readline_prompt_edit(&csh->rl, CSH_PROMPT_SEG_USER, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_GREEN, .bold = 1 }.raw, csh->user[uid]);
- }
- return -1;
- }
- /*****************************************************************************
- * @brief get environment variable
- *
- * @param[in] csh shell instance
- * @param[in] name env name
- *
- * @retval env string pointer or NULL
- * @note env string maybe read-only
- *****************************************************************************/
- char *chry_shell_getenv(chry_shell_t *csh, const char *name)
- {
- CHRY_SHELL_PARAM_CHECK(NULL != csh, NULL);
- char *env = NULL;
- for (const chry_sysvar_t *var = csh->var_tbl_beg; var < csh->var_tbl_end; var++) {
- if (strcmp(name, var->name) == 0) {
- env = var->var;
- break;
- }
- }
- return env;
- }
- /*****************************************************************************
- * @brief print from shell
- *
- * @param[in] csh shell instance
- * @param[in] fmt string format
- *
- * @retval size that has printed
- *****************************************************************************/
- int csh_printf(chry_shell_t *csh, const char *fmt, ...)
- {
- int n;
- char shell_printf_buffer[CONFIG_CSH_PRINT_BUFFER_SIZE];
- va_list args;
- va_start (args, fmt);
- n = vsnprintf(shell_printf_buffer, sizeof(shell_printf_buffer), fmt, args);
- if (n > (int)sizeof(shell_printf_buffer)) {
- csh->rl.sput(&csh->rl, shell_printf_buffer, sizeof(shell_printf_buffer));
- } else if (n > 0) {
- csh->rl.sput(&csh->rl, shell_printf_buffer, n);
- }
- va_end(args);
- return n;
- }
|