diff options
Diffstat (limited to 'scripts/kconfig')
-rw-r--r-- | scripts/kconfig/confdata.c | 33 | ||||
-rw-r--r-- | scripts/kconfig/kconf_id.c | 1 | ||||
-rw-r--r-- | scripts/kconfig/lkc.h | 5 | ||||
-rw-r--r-- | scripts/kconfig/lkc_proto.h | 6 | ||||
-rw-r--r-- | scripts/kconfig/menu.c | 3 | ||||
-rw-r--r-- | scripts/kconfig/preprocess.c | 238 | ||||
-rw-r--r-- | scripts/kconfig/symbol.c | 56 | ||||
-rw-r--r-- | scripts/kconfig/util.c | 29 | ||||
-rw-r--r-- | scripts/kconfig/zconf.l | 67 | ||||
-rw-r--r-- | scripts/kconfig/zconf.y | 2 |
10 files changed, 326 insertions, 114 deletions
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 569217168e96..5f87ad561b08 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -30,7 +30,7 @@ static void conf_message(const char *fmt, ...) static const char *conf_filename; static int conf_lineno, conf_warnings; -const char conf_defname[] = "arch/$ARCH/defconfig"; +const char conf_defname[] = "arch/$(ARCH)/defconfig"; static void conf_warning(const char *fmt, ...) { @@ -81,39 +81,13 @@ const char *conf_get_autoconfig_name(void) return name ? name : "include/config/auto.conf"; } -static char *conf_expand_value(const char *in) -{ - struct symbol *sym; - const char *src; - static char res_value[SYMBOL_MAXLENGTH]; - char *dst, name[SYMBOL_MAXLENGTH]; - - res_value[0] = 0; - dst = name; - while ((src = strchr(in, '$'))) { - strncat(res_value, in, src - in); - src++; - dst = name; - while (isalnum(*src) || *src == '_') - *dst++ = *src++; - *dst = 0; - sym = sym_lookup(name, 0); - sym_calc_value(sym); - strcat(res_value, sym_get_string_value(sym)); - in = src; - } - strcat(res_value, in); - - return res_value; -} - char *conf_get_default_confname(void) { struct stat buf; static char fullname[PATH_MAX+1]; char *env, *name; - name = conf_expand_value(conf_defname); + name = expand_string(conf_defname); env = getenv(SRCTREE); if (env) { sprintf(fullname, "%s/%s", env, name); @@ -274,7 +248,8 @@ int conf_read_simple(const char *name, int def) if (expr_calc_value(prop->visible.expr) == no || prop->expr->type != E_SYMBOL) continue; - name = conf_expand_value(prop->expr->left.sym->name); + sym_calc_value(prop->expr->left.sym); + name = sym_get_string_value(prop->expr->left.sym); in = zconf_fopen(name); if (in) { conf_message("using defaults found in %s", diff --git a/scripts/kconfig/kconf_id.c b/scripts/kconfig/kconf_id.c index 3ea9c5f9f730..b3e0ea0ac732 100644 --- a/scripts/kconfig/kconf_id.c +++ b/scripts/kconfig/kconf_id.c @@ -32,7 +32,6 @@ static struct kconf_id kconf_id_array[] = { { "on", T_ON, TF_PARAM }, { "modules", T_OPT_MODULES, TF_OPTION }, { "defconfig_list", T_OPT_DEFCONFIG_LIST, TF_OPTION }, - { "env", T_OPT_ENV, TF_OPTION }, { "allnoconfig_y", T_OPT_ALLNOCONFIG_Y, TF_OPTION }, }; diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 2628bc6a2141..ed3ff88e60ba 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -44,7 +44,6 @@ enum conf_def_mode { #define T_OPT_MODULES 1 #define T_OPT_DEFCONFIG_LIST 2 -#define T_OPT_ENV 3 #define T_OPT_ALLNOCONFIG_Y 4 struct kconf_id { @@ -103,6 +102,7 @@ void *xmalloc(size_t size); void *xcalloc(size_t nmemb, size_t size); void *xrealloc(void *p, size_t size); char *xstrdup(const char *s); +char *xstrndup(const char *s, size_t n); struct gstr { size_t len; @@ -120,9 +120,6 @@ void str_printf(struct gstr *gs, const char *fmt, ...); const char *str_get(struct gstr *gs); /* symbol.c */ -extern struct expr *sym_env_list; - -void sym_init(void); void sym_clear_all_valid(void); struct symbol *sym_choice_default(struct symbol *sym); const char *sym_get_string_default(struct symbol *sym); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 9dc8abfb1dc3..9f465fe1ca85 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -49,5 +49,11 @@ const char * sym_get_string_value(struct symbol *sym); const char * prop_get_type_name(enum prop_type type); +/* preprocess.c */ +void env_write_dep(FILE *f, const char *auto_conf_name); +char *expand_string(const char *in); +char *expand_dollar(const char **str); +char *expand_one_token(const char **str); + /* expr.c */ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 068a4e4db20a..379a119dcd1e 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -214,9 +214,6 @@ void menu_add_option(int token, char *arg) zconf_error("trying to redefine defconfig symbol"); sym_defconfig_list->flags |= SYMBOL_AUTO; break; - case T_OPT_ENV: - prop_add_env(arg); - break; case T_OPT_ALLNOCONFIG_Y: current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; break; diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c new file mode 100644 index 000000000000..a2eb2eb02929 --- /dev/null +++ b/scripts/kconfig/preprocess.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@socionext.com> + +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "list.h" + +static void __attribute__((noreturn)) pperror(const char *format, ...) +{ + va_list ap; + + fprintf(stderr, "%s:%d: ", current_file->name, yylineno); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "\n"); + + exit(1); +} + +/* + * Environment variables + */ +static LIST_HEAD(env_list); + +struct env { + char *name; + char *value; + struct list_head node; +}; + +static void env_add(const char *name, const char *value) +{ + struct env *e; + + e = xmalloc(sizeof(*e)); + e->name = xstrdup(name); + e->value = xstrdup(value); + + list_add_tail(&e->node, &env_list); +} + +static void env_del(struct env *e) +{ + list_del(&e->node); + free(e->name); + free(e->value); + free(e); +} + +/* The returned pointer must be freed when done */ +static char *env_expand(const char *name) +{ + struct env *e; + const char *value; + + if (!*name) + return NULL; + + list_for_each_entry(e, &env_list, node) { + if (!strcmp(name, e->name)) + return xstrdup(e->value); + } + + value = getenv(name); + if (!value) + return NULL; + + /* + * We need to remember all referenced environment variables. + * They will be written out to include/config/auto.conf.cmd + */ + env_add(name, value); + + return xstrdup(value); +} + +void env_write_dep(FILE *f, const char *autoconfig_name) +{ + struct env *e, *tmp; + + list_for_each_entry_safe(e, tmp, &env_list, node) { + fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value); + fprintf(f, "%s: FORCE\n", autoconfig_name); + fprintf(f, "endif\n"); + env_del(e); + } +} + +static char *eval_clause(const char *str, size_t len) +{ + char *tmp, *name, *res; + + tmp = xstrndup(str, len); + + name = expand_string(tmp); + + res = env_expand(name); + if (res) + goto free; + + res = xstrdup(""); +free: + free(name); + free(tmp); + + return res; +} + +/* + * Expand a string that follows '$' + * + * For example, if the input string is + * ($(FOO)$($(BAR)))$(BAZ) + * this helper evaluates + * $($(FOO)$($(BAR))) + * and returns a new string containing the expansion (note that the string is + * recursively expanded), also advancing 'str' to point to the next character + * after the corresponding closing parenthesis, in this case, *str will be + * $(BAR) + */ +char *expand_dollar(const char **str) +{ + const char *p = *str; + const char *q; + int nest = 0; + + /* + * In Kconfig, variable references always start with "$(". + * Neither single-letter variables as in $A nor curly braces as in ${CC} + * are supported. '$' not followed by '(' loses its special meaning. + */ + if (*p != '(') { + *str = p; + return xstrdup("$"); + } + + p++; + q = p; + while (*q) { + if (*q == '(') { + nest++; + } else if (*q == ')') { + if (nest-- == 0) + break; + } + q++; + } + + if (!*q) + pperror("unterminated reference to '%s': missing ')'", p); + + /* Advance 'str' to after the expanded initial portion of the string */ + *str = q + 1; + + return eval_clause(p, q - p); +} + +static char *__expand_string(const char **str, bool (*is_end)(char c)) +{ + const char *in, *p; + char *expansion, *out; + size_t in_len, out_len; + + out = xmalloc(1); + *out = 0; + out_len = 1; + + p = in = *str; + + while (1) { + if (*p == '$') { + in_len = p - in; + p++; + expansion = expand_dollar(&p); + out_len += in_len + strlen(expansion); + out = xrealloc(out, out_len); + strncat(out, in, in_len); + strcat(out, expansion); + free(expansion); + in = p; + continue; + } + + if (is_end(*p)) + break; + + p++; + } + + in_len = p - in; + out_len += in_len; + out = xrealloc(out, out_len); + strncat(out, in, in_len); + + /* Advance 'str' to the end character */ + *str = p; + + return out; +} + +static bool is_end_of_str(char c) +{ + return !c; +} + +/* + * Expand variables in the given string. Undefined variables + * expand to an empty string. + * The returned string must be freed when done. + */ +char *expand_string(const char *in) +{ + return __expand_string(&in, is_end_of_str); +} + +static bool is_end_of_token(char c) +{ + /* Why are '.' and '/' valid characters for symbols? */ + return !(isalnum(c) || c == '_' || c == '-' || c == '.' || c == '/'); +} + +/* + * Expand variables in a token. The parsing stops when a token separater + * (in most cases, it is a whitespace) is encountered. 'str' is updated to + * point to the next character. + * + * The returned string must be freed when done. + */ +char *expand_one_token(const char **str) +{ + return __expand_string(str, is_end_of_token); +} diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index f0b2e3b3102d..2460648a581a 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -33,33 +33,6 @@ struct symbol *sym_defconfig_list; struct symbol *modules_sym; tristate modules_val; -struct expr *sym_env_list; - -static void sym_add_default(struct symbol *sym, const char *def) -{ - struct property *prop = prop_alloc(P_DEFAULT, sym); - - prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); -} - -void sym_init(void) -{ - struct symbol *sym; - struct utsname uts; - static bool inited = false; - - if (inited) - return; - inited = true; - - uname(&uts); - - sym = sym_lookup("UNAME_RELEASE", 0); - sym->type = S_STRING; - sym->flags |= SYMBOL_AUTO; - sym_add_default(sym, uts.release); -} - enum symbol_type sym_get_type(struct symbol *sym) { enum symbol_type type = sym->type; @@ -1401,32 +1374,3 @@ const char *prop_get_type_name(enum prop_type type) } return "unknown"; } - -static void prop_add_env(const char *env) -{ - struct symbol *sym, *sym2; - struct property *prop; - char *p; - - sym = current_entry->sym; - sym->flags |= SYMBOL_AUTO; - for_all_properties(sym, prop, P_ENV) { - sym2 = prop_get_symbol(prop); - if (strcmp(sym2->name, env)) - menu_warn(current_entry, "redefining environment symbol from %s", - sym2->name); - return; - } - - prop = prop_alloc(P_ENV, sym); - prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); - - sym_env_list = expr_alloc_one(E_LIST, sym_env_list); - sym_env_list->right.sym = sym; - - p = getenv(env); - if (p) - sym_add_default(sym, p); - else - menu_warn(current_entry, "environment variable %s undefined", env); -} diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index c6f6e21b809f..703ee4904613 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -34,8 +34,6 @@ struct file *file_lookup(const char *name) /* write a dependency file as used by kbuild to track dependencies */ int file_write_dep(const char *name) { - struct symbol *sym, *env_sym; - struct expr *e; struct file *file; FILE *out; @@ -54,21 +52,7 @@ int file_write_dep(const char *name) fprintf(out, "\n%s: \\\n" "\t$(deps_config)\n\n", conf_get_autoconfig_name()); - expr_list_for_each_sym(sym_env_list, e, sym) { - struct property *prop; - const char *value; - - prop = sym_get_env_prop(sym); - env_sym = prop_get_symbol(prop); - if (!env_sym) - continue; - value = getenv(env_sym->name); - if (!value) - value = ""; - fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); - fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); - fprintf(out, "endif\n"); - } + env_write_dep(out, conf_get_autoconfig_name()); fprintf(out, "\n$(deps_config): ;\n"); fclose(out); @@ -165,3 +149,14 @@ char *xstrdup(const char *s) fprintf(stderr, "Out of memory.\n"); exit(1); } + +char *xstrndup(const char *s, size_t n) +{ + char *p; + + p = strndup(s, n); + if (p) + return p; + fprintf(stderr, "Out of memory.\n"); + exit(1); +} diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l index 045093d827e1..b3855909913c 100644 --- a/scripts/kconfig/zconf.l +++ b/scripts/kconfig/zconf.l @@ -1,6 +1,5 @@ %option nostdinit noyywrap never-interactive full ecs %option 8bit nodefault yylineno -%option noinput %x COMMAND HELP STRING PARAM %{ /* @@ -35,6 +34,8 @@ struct buffer *current_buf; static int last_ts, first_ts; +static char *expand_token(const char *in, size_t n); +static void append_expanded_string(const char *in); static void zconf_endhelp(void); static void zconf_endfile(void); @@ -147,6 +148,13 @@ n [A-Za-z0-9_-] yylval.string = text; return T_WORD; } + ({n}|[/.$])+ { + /* this token includes at least one '$' */ + yylval.string = expand_token(yytext, yyleng); + if (strlen(yylval.string)) + return T_WORD; + free(yylval.string); + } #.* /* comment */ \\\n ; [[:blank:]]+ @@ -157,12 +165,13 @@ n [A-Za-z0-9_-] } <STRING>{ - [^'"\\\n]+/\n { + "$".* append_expanded_string(yytext); + [^$'"\\\n]+/\n { append_string(yytext, yyleng); yylval.string = text; return T_WORD_QUOTE; } - [^'"\\\n]+ { + [^$'"\\\n]+ { append_string(yytext, yyleng); } \\.?/\n { @@ -249,6 +258,58 @@ n [A-Za-z0-9_-] } %% +static char *expand_token(const char *in, size_t n) +{ + char *out; + int c; + char c2; + const char *rest, *end; + + new_string(); + append_string(in, n); + + /* get the whole line because we do not know the end of token. */ + while ((c = input()) != EOF) { + if (c == '\n') { + unput(c); + break; + } + c2 = c; + append_string(&c2, 1); + } + + rest = text; + out = expand_one_token(&rest); + + /* push back unused characters to the input stream */ + end = rest + strlen(rest); + while (end > rest) + unput(*--end); + + free(text); + + return out; +} + +static void append_expanded_string(const char *str) +{ + const char *end; + char *res; + + str++; + + res = expand_dollar(&str); + + /* push back unused characters to the input stream */ + end = str + strlen(str); + while (end > str) + unput(*--end); + + append_string(res, strlen(res)); + + free(res); +} + void zconf_starthelp(void) { new_string(); diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 8bfaaf853d23..031b2e24ae00 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -534,7 +534,6 @@ void conf_parse(const char *name) zconf_initscan(name); - sym_init(); _menu_init(); if (getenv("ZCONF_DEBUG")) @@ -780,3 +779,4 @@ void zconfdump(FILE *out) #include "expr.c" #include "symbol.c" #include "menu.c" +#include "preprocess.c" |