This sets the shell to LIL when CONFIG_LIL is enabled. Repeated commands are not supporteed. Neither are partial commands a la Hush's secondary prompt. Setting and getting environmental variables is done through callbacks to assist with testing.
Signed-off-by: Sean Anderson <sean...@gmail.com> --- cmd/Kconfig | 12 +++++-- common/cli.c | 84 +++++++++++++++++++++++++++++++++++++++--------- common/cli_lil.c | 32 ++++++++++++++++++ 3 files changed, 111 insertions(+), 17 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 0a7b73cb6d..b61a7557a9 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -11,9 +11,14 @@ config CMDLINE Depending on the number of commands enabled, this can add substantially to the size of U-Boot. +if CMDLINE + +choice + prompt "Shell" + default HUSH_PARSER + config HUSH_PARSER bool "Use hush shell" - depends on CMDLINE help This option enables the "hush" shell (from Busybox) as command line interpreter, thus enabling powerful command line syntax like @@ -25,13 +30,14 @@ config HUSH_PARSER config LIL bool "Use LIL shell" - depends on CMDLINE help This options enables the "Little Interpreted Language" (LIL) shell as command line interpreter, thus enabling powerful command line syntax like `proc name {args} {body}' functions or `echo [some command]` command substitution ("tcl scripts"). +endchoice + if LIL config LIL_FULL @@ -42,6 +48,8 @@ config LIL_FULL endif +endif + config CMDLINE_EDITING bool "Enable command line editing" depends on CMDLINE diff --git a/common/cli.c b/common/cli.c index 048eacb9ef..ad5d76d563 100644 --- a/common/cli.c +++ b/common/cli.c @@ -12,6 +12,7 @@ #include <bootstage.h> #include <cli.h> #include <cli_hush.h> +#include <cli_lil.h> #include <command.h> #include <console.h> #include <env.h> @@ -22,6 +23,53 @@ DECLARE_GLOBAL_DATA_PTR; +#ifdef CONFIG_LIL +static struct lil *lil; + +static int env_setvar(struct lil *lil, const char *name, + struct lil_value **value) +{ + if (env_set(name, lil_to_string(*value))) + return -1; + return 0; +} + +static int env_getvar(struct lil *lil, const char *name, + struct lil_value **value) +{ + *value = lil_alloc_string(env_get(name)); + return 1; +} + +static const struct lil_callbacks env_callbacks = { + .setvar = env_setvar, + .getvar = env_getvar, +}; + +static int lil_run(const char *cmd) +{ + int err; + struct lil_value *result = lil_parse(lil, cmd, 0, 0); + const char *err_msg, *strres = lil_to_string(result); + + /* The result may be very big, so use puts */ + if (strres && strres[0]) { + puts(strres); + putc('\n'); + } + lil_free_value(result); + + err = lil_error(lil, &err_msg); + if (err) { + if (err_msg) + printf("error: %s\n", err_msg); + else + printf("error: %d\n", err); + } + return !!err; +} +#endif + #ifdef CONFIG_CMDLINE /* * Run a command using the selected parser. @@ -32,7 +80,15 @@ DECLARE_GLOBAL_DATA_PTR; */ int run_command(const char *cmd, int flag) { -#if !CONFIG_IS_ENABLED(HUSH_PARSER) +#ifdef CONFIG_HUSH_PARSER + int hush_flags = FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP; + + if (flag & CMD_FLAG_ENV) + hush_flags |= FLAG_CONT_ON_NEWLINE; + return parse_string_outer(cmd, hush_flags); +#elif defined(CONFIG_LIL) + return lil_run(cmd); +#else /* * cli_run_command can return 0 or 1 for success, so clean up * its result. @@ -41,12 +97,6 @@ int run_command(const char *cmd, int flag) return 1; return 0; -#else - int hush_flags = FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP; - - if (flag & CMD_FLAG_ENV) - hush_flags |= FLAG_CONT_ON_NEWLINE; - return parse_string_outer(cmd, hush_flags); #endif } @@ -59,9 +109,7 @@ int run_command(const char *cmd, int flag) */ int run_command_repeatable(const char *cmd, int flag) { -#ifndef CONFIG_HUSH_PARSER - return cli_simple_run_command(cmd, flag); -#else +#ifdef CONFIG_HUSH_PARSER /* * parse_string_outer() returns 1 for failure, so clean up * its result. @@ -71,6 +119,10 @@ int run_command_repeatable(const char *cmd, int flag) return -1; return 0; +#elif defined(CONFIG_LIL) + return run_command(cmd, flag); +#else + return cli_simple_run_command(cmd, flag); #endif } #else @@ -90,7 +142,7 @@ int run_command_list(const char *cmd, int len, int flag) if (len == -1) { len = strlen(cmd); -#ifdef CONFIG_HUSH_PARSER +#if defined(CONFIG_HUSH_PARSER) || defined(CONFIG_LIL) /* hush will never change our string */ need_buff = 0; #else @@ -107,7 +159,9 @@ int run_command_list(const char *cmd, int len, int flag) } #ifdef CONFIG_HUSH_PARSER rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON); -#else +#elif defined(CONFIG_LIL) + rcode = lil_run(buff); +#elif defined(CONFIG_CMDLINE) /* * This function will overwrite any \n it sees with a \0, which * is why it can't work with a const char *. Here we are making @@ -115,11 +169,9 @@ int run_command_list(const char *cmd, int len, int flag) * doing a malloc() which is actually required only in a case that * is pretty rare. */ -#ifdef CONFIG_CMDLINE rcode = cli_simple_run_command_list(buff, flag); #else rcode = board_run_command(buff); -#endif #endif if (need_buff) free(buff); @@ -241,9 +293,11 @@ void cli_init(void) { #ifdef CONFIG_HUSH_PARSER u_boot_hush_start(); +#elif defined(CONFIG_LIL) + lil = lil_new(&env_callbacks); #endif -#if defined(CONFIG_HUSH_INIT_VAR) +#ifdef CONFIG_HUSH_INIT_VAR hush_init_var(); #endif } diff --git a/common/cli_lil.c b/common/cli_lil.c index 50e314a643..66ee62bf33 100644 --- a/common/cli_lil.c +++ b/common/cli_lil.c @@ -11,6 +11,7 @@ #include <common.h> #include <cli_lil.h> #include <console.h> +#include <command.h> #include <ctype.h> #include <stdlib.h> #include <stdio.h> @@ -59,6 +60,7 @@ struct lil_var { struct lil_env { struct lil_env *parent; struct lil_func *func; + const char *proc; struct lil_var **var; size_t vars; struct hashmap varmap; @@ -1045,7 +1047,9 @@ static struct lil_value *run_cmd(struct lil *lil, struct lil_func *cmd, struct lil_value *r; if (cmd->proc) { + lil->env->proc = words->v[0]->d; r = cmd->proc(lil, words->c - 1, words->v + 1); + lil->env->proc = NULL; } else { lil_push_env(lil); lil->env->func = cmd; @@ -2967,8 +2971,33 @@ static struct lil_value *fnc_lmap(struct lil *lil, size_t argc, return NULL; } +static struct lil_value *fnc_builtin(struct lil *lil, size_t argc, + struct lil_value **lil_argv) +{ + int err, repeatable; + size_t i; + /* + * We need space for the function name, and the last argv must be NULL + */ + char **argv = calloc(sizeof(char *), argc + 2); + + argv[0] = (char *)lil->env->proc; + for (i = 0; i < argc; i++) + argv[i + 1] = (char *)lil_to_string(lil_argv[i]); + + err = cmd_process(0, argc + 1, argv, &repeatable, NULL); + if (err) + lil_set_errorf(lil, LIL_ERR_USER, "%s failed", argv[0]); + free(argv); + + return 0; +} + static void register_stdcmds(struct lil *lil) { + struct cmd_tbl *cmdtp, *start = ll_entry_start(struct cmd_tbl, cmd); + const int len = ll_entry_count(struct cmd_tbl, cmd); + lil_register(lil, "decr", fnc_decr); lil_register(lil, "eval", fnc_eval); lil_register(lil, "expr", fnc_expr); @@ -2984,6 +3013,9 @@ static void register_stdcmds(struct lil *lil) lil_register(lil, "try", fnc_try); lil_register(lil, "while", fnc_while); + for (cmdtp = start; cmdtp != start + len; cmdtp++) + lil_register(lil, cmdtp->name, fnc_builtin); + if (IS_ENABLED(CONFIG_LIL_FULL)) { lil_register(lil, "append", fnc_append); lil_register(lil, "char", fnc_char); -- 2.32.0