From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_NONE,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5E79DC11F64 for ; Thu, 1 Jul 2021 06:18:40 +0000 (UTC) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D97AA61461 for ; Thu, 1 Jul 2021 06:18:39 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D97AA61461 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 72F098326E; Thu, 1 Jul 2021 08:17:01 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="qjcKCvez"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 7E2538322D; Thu, 1 Jul 2021 08:16:45 +0200 (CEST) Received: from mail-qk1-x72e.google.com (mail-qk1-x72e.google.com [IPv6:2607:f8b0:4864:20::72e]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id D74BE83248 for ; Thu, 1 Jul 2021 08:16:25 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=seanga2@gmail.com Received: by mail-qk1-x72e.google.com with SMTP id q16so4983054qke.10 for ; Wed, 30 Jun 2021 23:16:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tY7JkSxvyEnw3VdjCcU8l09ax3Xy/FeDeT8k/f8HH4g=; b=qjcKCvezjtThdcWYaeLnN331cRnHyio1GDzpjKTyejGZ0SkpgnXaMH0laozw9+jHPn g215Zvvuw5Fip0K1vrlk/EOltLTYCssfobBTDl4eGdu4Sp1atRf96WEt3F+kPUzY0cgQ OcOJb5ld6eTX+3rrWQNMo7qUWN1GrKDcxsFmT5GG9h4CFoRF1AhtgwklMkTqQ0gOmzG6 ovAiAElQVtSkVakz2byZzZjilsOg5yg4C0jrZggaFQSn31iu+pzSDhPVDQlqJ6zn1Kwt ZmLgQMIm0Xz59F9BYLv1WTTYyLu2fGwHyCYCVnk7Z58BVjia/azQeq+FhHANz+aueuS2 Zr7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tY7JkSxvyEnw3VdjCcU8l09ax3Xy/FeDeT8k/f8HH4g=; b=MiRppp8jxwztnHQrnJ9kynC4RzL9xaYuPdtgxZNzgCO+m4emnTieedxQi1z2bfnS3N y//wCzKLf9JBZYuQZb0JC6RW6WDxIlnCkli/9WryTYV1YykU/IwnaMwyelQ1bjzKeEXd gk+zKHHTzPe+NPU+Jp4j6529TV88/zWPyoMPts/PfBBAdjGEvFcYpCwnElYQV5tblwzz 5Rp93Ltxc7jYPlSJ3AZhHGHTnnMtN2GlQgwX3h2/oYuTstM0w0MyXA5M7U3IA3ijscJV CMcKXAovUjGwjOpzZLHHVad29j888gtNj5kITP2dDRcrQxCuIgilDk9eD1b4SHKJYbwu 8Xww== X-Gm-Message-State: AOAM531IDZ6QvRRXrjIeqm0erAe7v/hUaReCT1bWGM9MedngsazV41Ca ge5GMoo4pD1FZjlHADhXzHtKVQo+3sA= X-Google-Smtp-Source: ABdhPJyP+sVXvQ8rFy/TrP4ph80ZYTUuekjAU1sTMZUoNV8Qpaad/bxBHwiSqpOcFM54GkaGwcFlVA== X-Received: by 2002:a37:2e81:: with SMTP id u123mr20026373qkh.24.1625120184389; Wed, 30 Jun 2021 23:16:24 -0700 (PDT) Received: from godwin.fios-router.home (pool-74-96-87-9.washdc.fios.verizon.net. [74.96.87.9]) by smtp.gmail.com with ESMTPSA id g21sm1684673qts.90.2021.06.30.23.16.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jun 2021 23:16:24 -0700 (PDT) From: Sean Anderson To: u-boot@lists.denx.de, Tom Rini Cc: =?UTF-8?q?Marek=20Beh=C3=BAn?= , Wolfgang Denk , Simon Glass , Roland Gaudig , Heinrich Schuchardt , Kostas Michalopoulos , Sean Anderson Subject: [RFC PATCH 13/28] cli: lil: Wire up LIL to the rest of U-Boot Date: Thu, 1 Jul 2021 02:15:56 -0400 Message-Id: <20210701061611.957918-14-seanga2@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210701061611.957918-1-seanga2@gmail.com> References: <20210701061611.957918-1-seanga2@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean 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 --- 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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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