Received: by 10.192.165.156 with SMTP id m28csp351969imm; Thu, 12 Apr 2018 23:49:51 -0700 (PDT) X-Google-Smtp-Source: AIpwx49QmFrVqmSDd1+X4fwiZ1QMYFJOpfa2gNNA9W2znthQ9qjaVfBtFGA5XDu9BJM2YAaAW/KE X-Received: by 10.99.111.140 with SMTP id k134mr3167782pgc.11.1523602191136; Thu, 12 Apr 2018 23:49:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523602191; cv=none; d=google.com; s=arc-20160816; b=v+5tB3xRbkXC87ORbRNHu64Nq0iayNWMVMbdrDW+X86PgickGVuaDQzUTJHUTWpTZZ zvgt4b5SXDe6RUFccKl8M1fjm8JWHy12RDNkNG8FfUShzy6c+rJA8VKdsldDaK14ukWr 3hywfxksexWEo/C3jZUUNUsZnqMZiiR/nFtzFCgz7UpLrqplcAFPN1OtL2554tx57Oa+ OEQpNTck71gJtIkXDqq60JLRakMdbvF/4pspZSNDHMrgGe62Kxw5tvE3Lqu8+gKPUe63 AHryq888/PZcmCKjKofp6mqwcAg7UWW6m9wVjLK0o27ZVl8X40/uNe2FBuwsQth7MygC YCgA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature:dkim-filter :arc-authentication-results; bh=Io8rT58VQidBIz9nRObZK9YiXAQVFl1h6UYrjF2M1ww=; b=fxPVVg9vVTQA4dQeaYrjSAZpZTMaD1azv5s0aZnvsq+RjCH6Kiy/iNwbAWhU68LJIj ylCx7Ur227GU85g/uxxq3UAvPrfoPMlZuk3pCACwgA97z74rjX2JZOM2/MxEUaDTfWIz Ngha0AcwA0jc0WzEzeufJ8sxk0CnPgMYAmS3ksaltfaV6+Mrn66KqPakzoyqJs1q5VUe aAYkwwBJaXbbuBI8tQ//JBdhi8qFyHuMb1EEnNM87567njceKbwbsuBpiwo84vBVKJq/ RHf1nbVnVXIi0XtVJtXEdsqBc4l8R7STSA5GRuOACihq5GE6b396TonlTy3uLHTcnvHl qzYA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nifty.com header.s=dec2015msa header.b=vxi6nzey; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s19-v6si4932587plp.558.2018.04.12.23.49.35; Thu, 12 Apr 2018 23:49:51 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nifty.com header.s=dec2015msa header.b=vxi6nzey; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753136AbeDMFi2 (ORCPT + 99 others); Fri, 13 Apr 2018 01:38:28 -0400 Received: from conssluserg-01.nifty.com ([210.131.2.80]:54810 "EHLO conssluserg-01.nifty.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752996AbeDMFi1 (ORCPT ); Fri, 13 Apr 2018 01:38:27 -0400 Received: from mail-vk0-f46.google.com (mail-vk0-f46.google.com [209.85.213.46]) (authenticated) by conssluserg-01.nifty.com with ESMTP id w3D5c3aR026820; Fri, 13 Apr 2018 14:38:04 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conssluserg-01.nifty.com w3D5c3aR026820 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1523597884; bh=Io8rT58VQidBIz9nRObZK9YiXAQVFl1h6UYrjF2M1ww=; h=In-Reply-To:References:From:Date:Subject:To:Cc:From; b=vxi6nzeyQyQsgY31aDU2EB7LLog+/ElU39z4WTwANTqNmzP+faCkIncCTDw+z+Rmf SDEPGyHPKdJMs3XzcPGQKKVbdWd82Y5uaee44DD2C9EL/VppnYDs9J9fdtEe8LEipH 6iEWZFbytAW5rQAaLeJpf4LQM/E5RbPlLiYXRc9khqWc7ywhzTpQ1UHUAY8WnAV6bI aSE0oAoVsHB4esOixyf8juDL7DWpK72RCju+8J1jIk8717Rz7FgVkFs/YnpRldqj4Z yvkLJjBWZV7kjdQDz7P12rUDATDItVAluxxUQslMCQlO0CHaKzW/sPxWAEor88L2bB 5mVykLdIPJbXA== X-Nifty-SrcIP: [209.85.213.46] Received: by mail-vk0-f46.google.com with SMTP id r184so4677225vke.11; Thu, 12 Apr 2018 22:38:04 -0700 (PDT) X-Gm-Message-State: ALQs6tBoatAe0kGdO7wm7B1f8EW8aOYFstzMN7An4KaQZlKNos5PJpcc A0iZ1QW2vq4B07t1u4N1LaD9W1IGSwrpL8J7x/s= X-Received: by 10.31.127.6 with SMTP id o6mr2715356vki.34.1523597882780; Thu, 12 Apr 2018 22:38:02 -0700 (PDT) MIME-Version: 1.0 Received: by 10.176.29.150 with HTTP; Thu, 12 Apr 2018 22:37:22 -0700 (PDT) In-Reply-To: References: <1522128575-5326-1-git-send-email-yamada.masahiro@socionext.com> <1522128575-5326-8-git-send-email-yamada.masahiro@socionext.com> From: Masahiro Yamada Date: Fri, 13 Apr 2018 14:37:22 +0900 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [PATCH v2 07/21] kconfig: add function support and implement 'shell' function To: Ulf Magnusson Cc: Linux Kbuild mailing list , Sam Ravnborg , Linus Torvalds , Arnd Bergmann , Kees Cook , Thomas Gleixner , Greg Kroah-Hartman , Randy Dunlap , "Luis R . Rodriguez" , Nicolas Pitre , Linux Kernel Mailing List Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 2018-04-01 13:19 GMT+09:00 Ulf Magnusson : > On Tue, Mar 27, 2018 at 7:29 AM, Masahiro Yamada > wrote: >> This commit adds a new concept 'function' to do more text processing >> in Kconfig. >> >> A function call looks like this: >> >> $(function arg1, arg2, arg3, ...) >> >> (Actually, this syntax was inspired by make.) >> >> Real examples will look like this: >> >> $(shell echo hello world) >> $(cc-option -fstackprotector) >> >> This commit adds the basic infrastructure to add, delete, evaluate >> functions, and also the first built-in function $(shell ...). This >> accepts a single command to execute. It returns the standard output >> from it. >> >> [Example code] >> >> config HELLO >> string >> default "$(shell echo hello world)" >> >> config Y >> def_bool $(shell echo y) >> >> [Result] >> >> $ make -s alldefconfig && tail -n 2 .config >> CONFIG_HELLO="hello world" >> CONFIG_Y=y >> >> Caveat: >> Like environments, functions are expanded in the lexer. You cannot >> pass symbols to function arguments. This is a limitation to simplify >> the implementation. I want to avoid the dynamic function evaluation, >> which would introduce much more complexity. >> >> Signed-off-by: Masahiro Yamada >> --- >> >> Reminder for myself: >> Update Documentation/kbuild/kconfig-language.txt >> >> >> Changes in v2: >> - Use 'shell' for getting stdout from the comment. >> It was 'shell-stdout' in the previous version. >> - Symplify the implementation since the expansion has been moved to >> lexer. >> >> scripts/kconfig/function.c | 170 ++++++++++++++++++++++++++++++++++++++++++++ >> scripts/kconfig/lkc_proto.h | 5 ++ >> scripts/kconfig/util.c | 46 +++++++++--- >> scripts/kconfig/zconf.y | 9 +++ >> 4 files changed, 222 insertions(+), 8 deletions(-) >> create mode 100644 scripts/kconfig/function.c >> >> diff --git a/scripts/kconfig/function.c b/scripts/kconfig/function.c >> new file mode 100644 >> index 0000000..913685f >> --- /dev/null >> +++ b/scripts/kconfig/function.c >> @@ -0,0 +1,170 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +// >> +// Copyright (C) 2018 Masahiro Yamada >> + >> +#include >> +#include >> +#include >> + >> +#include "list.h" >> + >> +#define FUNCTION_MAX_ARGS 10 >> + >> +static LIST_HEAD(function_list); >> + >> +struct function { >> + char *name; >> + char *(*func)(struct function *f, int argc, char *argv[]); >> + struct list_head node; >> +}; >> + >> +static struct function *func_lookup(const char *name) >> +{ >> + struct function *f; >> + >> + list_for_each_entry(f, &function_list, node) { >> + if (!strcmp(name, f->name)) >> + return f; >> + } >> + >> + return NULL; >> +} >> + >> +static void func_add(const char *name, >> + char *(*func)(struct function *f, int argc, char *argv[])) >> +{ >> + struct function *f; >> + >> + f = func_lookup(name); >> + if (f) { >> + fprintf(stderr, "%s: function already exists. ignored.\n", name); >> + return; >> + } >> + >> + f = xmalloc(sizeof(*f)); >> + f->name = xstrdup(name); >> + f->func = func; >> + >> + list_add_tail(&f->node, &function_list); >> +} >> + >> +static void func_del(struct function *f) >> +{ >> + list_del(&f->node); >> + free(f->name); >> + free(f); >> +} >> + >> +static char *func_call(int argc, char *argv[]) >> +{ >> + struct function *f; >> + >> + f = func_lookup(argv[0]); >> + if (!f) { >> + fprintf(stderr, "%s: function not found\n", argv[0]); >> + return NULL; >> + } >> + >> + return f->func(f, argc, argv); >> +} >> + >> +static char *func_eval(const char *func) >> +{ >> + char *expanded, *saveptr, *str, *token, *res; >> + const char *delim; >> + int argc = 0; >> + char *argv[FUNCTION_MAX_ARGS]; >> + >> + expanded = expand_string_value(func); >> + >> + str = expanded; >> + delim = " "; >> + >> + while ((token = strtok_r(str, delim, &saveptr))) { >> + argv[argc++] = token; > > Would be nice to error out if the array is overstepped. In V3, I made this a feature. >> + str = NULL; >> + delim = ","; >> + } >> + >> + res = func_call(argc, argv); >> + >> + free(expanded); >> + >> + return res ?: xstrdup(""); >> +} > > Since only 'macro' will take multiple parameters, I wonder if it might > be better to implement the argument parsing there, and simply pass the > string (minus the function name) as-is to functions. I may add more built-in functions in the future. For example, I want to add 'if' function, which takes two or three arguments. > You would then be able to have ',' in shell commands, which might be > required -- think gcc -Wl,option and the like. I fixed 'shell' function in v3. >> + >> +char *func_eval_n(const char *func, size_t n) >> +{ >> + char *tmp, *res; >> + >> + tmp = xmalloc(n + 1); >> + memcpy(tmp, func, n); >> + *(tmp + n) = '\0'; >> + >> + res = func_eval(tmp); >> + >> + free(tmp); >> + >> + return res; >> +} >> + >> +/* built-in functions */ >> +static char *do_shell(struct function *f, int argc, char *argv[]) >> +{ >> + static const char *pre = "("; >> + static const char *post = ") 2>/dev/null"; > > Arrays seem neater, since the pointers aren't needed. > >> + FILE *p; >> + char buf[256]; >> + char *cmd; >> + int ret; > > Could get rid of 'ret' and just do > > if (pclose(p) == -1) > perror(cmd); Done. >> + >> + if (argc != 2) >> + return NULL; >> + >> + /* >> + * Surround the command with ( ) in case it is piped commands. >> + * Also, redirect stderr to /dev/null. >> + */ >> + cmd = xmalloc(strlen(pre) + strlen(argv[1]) + strlen(post) + 1); >> + strcpy(cmd, pre); >> + strcat(cmd, argv[1]); >> + strcat(cmd, post); >> + >> + p = popen(cmd, "r"); >> + if (!p) { >> + perror(cmd); >> + goto free; >> + } >> + if (fgets(buf, sizeof(buf), p)) { >> + size_t len = strlen(buf); >> + >> + if (buf[len - 1] == '\n') >> + buf[len - 1] = '\0'; >> + } else { >> + buf[0] = '\0'; >> + } >> + >> + ret = pclose(p); >> + if (ret == -1) >> + perror(cmd); >> + >> +free: >> + free(cmd); >> + >> + return xstrdup(buf); >> +} >> + >> +void func_init(void) >> +{ >> + /* register built-in functions */ >> + func_add("shell", do_shell); >> +} >> + >> +void func_exit(void) >> +{ >> + struct function *f, *tmp; >> + >> + /* unregister all functions */ >> + list_for_each_entry_safe(f, tmp, &function_list, node) >> + func_del(f); >> +} >> diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h >> index 9884adc..09a4f53 100644 >> --- a/scripts/kconfig/lkc_proto.h >> +++ b/scripts/kconfig/lkc_proto.h >> @@ -48,5 +48,10 @@ const char * sym_get_string_value(struct symbol *sym); >> >> const char * prop_get_type_name(enum prop_type type); >> >> +/* function.c */ >> +char *func_eval_n(const char *func, size_t n); >> +void func_init(void); >> +void func_exit(void); >> + >> /* expr.c */ >> void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); >> diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c >> index 3d27c49..218b051 100644 >> --- a/scripts/kconfig/util.c >> +++ b/scripts/kconfig/util.c >> @@ -13,9 +13,10 @@ >> #include "lkc.h" >> >> /* >> - * Expand environments embedded in the string given in argument. Environments >> - * to be expanded shall be prefixed by a '$'. Unknown environment expands to >> - * the empty string. >> + * Expand environments and functions embedded in the string given in argument. >> + * Environments to be expanded shall be prefixed by a '$'. Functions to be >> + * evaluated shall be surrounded by $(). Unknown environment/function expands >> + * to the empty string. >> */ >> char *expand_string_value(const char *in) >> { >> @@ -33,11 +34,40 @@ char *expand_string_value(const char *in) >> while ((p = strchr(in, '$'))) { >> char *new; >> >> - q = p + 1; >> - while (isalnum(*q) || *q == '_') >> - q++; >> - >> - new = env_expand_n(p + 1, q - p - 1); >> + /* >> + * If the next character is '(', it is a function. >> + * Otherwise, environment. >> + */ >> + if (*(p + 1) == '(') { >> + int nest = 0; >> + >> + q = p + 2; >> + while (1) { >> + if (*q == '\0') { >> + fprintf(stderr, >> + "unterminated function: %s\n", >> + p); >> + new = xstrdup(""); >> + break; >> + } else if (*q == '(') { >> + nest++; >> + } else if (*q == ')') { >> + if (nest-- == 0) { >> + new = func_eval_n(p + 2, >> + q - p - 2); >> + q++; >> + break; >> + } >> + } >> + q++; >> + } > > A loop like this might work too: > > q = p + 1; > do { > if (*q == '\0') { > *error* > val = ... > goto error; > } > > if (*q == '(') > nest++; > if (*q == ')') > nest--; > q++; > } while (nest > 0); > > val = func_eval_n(...) > error: > >> + } else { >> + q = p + 1; >> + while (isalnum(*q) || *q == '_') >> + q++; >> + >> + new = env_expand_n(p + 1, q - p - 1); >> + } >> >> reslen = strlen(res) + (p - in) + strlen(new) + 1; >> res = xrealloc(res, reslen); >> diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y >> index d8120c7..feaea18 100644 >> --- a/scripts/kconfig/zconf.y >> +++ b/scripts/kconfig/zconf.y >> @@ -520,11 +520,19 @@ void conf_parse(const char *name) >> >> zconf_initscan(name); >> >> + func_init(); >> _menu_init(); >> >> if (getenv("ZCONF_DEBUG")) >> yydebug = 1; >> yyparse(); >> + >> + /* >> + * Currently, functions are evaluated only when Kconfig files are >> + * parsed. We can free functions here. >> + */ >> + func_exit(); >> + >> if (yynerrs) >> exit(1); >> if (!modules_sym) >> @@ -765,4 +773,5 @@ void zconfdump(FILE *out) >> #include "confdata.c" >> #include "expr.c" >> #include "symbol.c" >> +#include "function.c" >> #include "menu.c" >> -- >> 2.7.4 >> > > Cheers, > Ulf > -- > To unsubscribe from this list: send the line "unsubscribe linux-kbuild" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Best Regards Masahiro Yamada