summaryrefslogtreecommitdiff
path: root/scripts/kconfig
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/kconfig')
-rw-r--r--scripts/kconfig/Makefile12
-rw-r--r--scripts/kconfig/conf.c256
-rw-r--r--scripts/kconfig/confdata.c275
-rw-r--r--scripts/kconfig/expr.c614
-rw-r--r--scripts/kconfig/expr.h91
-rwxr-xr-xscripts/kconfig/gconf-cfg.sh2
-rw-r--r--scripts/kconfig/gconf.c101
-rw-r--r--scripts/kconfig/internal.h18
-rw-r--r--scripts/kconfig/lexer.l132
-rw-r--r--scripts/kconfig/list.h132
-rw-r--r--scripts/kconfig/lkc.h59
-rw-r--r--scripts/kconfig/lkc_proto.h31
-rw-r--r--scripts/kconfig/lxdialog/checklist.c7
-rw-r--r--scripts/kconfig/lxdialog/dialog.h16
-rw-r--r--scripts/kconfig/lxdialog/inputbox.c2
-rw-r--r--scripts/kconfig/lxdialog/menubox.c2
-rw-r--r--scripts/kconfig/lxdialog/textbox.c2
-rw-r--r--scripts/kconfig/lxdialog/util.c31
-rw-r--r--scripts/kconfig/lxdialog/yesno.c2
-rwxr-xr-xscripts/kconfig/mconf-cfg.sh2
-rw-r--r--scripts/kconfig/mconf.c132
-rw-r--r--scripts/kconfig/menu.c225
-rwxr-xr-xscripts/kconfig/merge_config.sh2
-rw-r--r--scripts/kconfig/mnconf-common.c2
-rw-r--r--scripts/kconfig/mnconf-common.h2
-rwxr-xr-xscripts/kconfig/nconf-cfg.sh2
-rw-r--r--scripts/kconfig/nconf.c136
-rw-r--r--scripts/kconfig/nconf.gui.c10
-rw-r--r--scripts/kconfig/parser.y233
-rw-r--r--scripts/kconfig/preprocess.c26
-rw-r--r--scripts/kconfig/preprocess.h19
-rwxr-xr-xscripts/kconfig/qconf-cfg.sh2
-rw-r--r--scripts/kconfig/qconf.cc236
-rw-r--r--scripts/kconfig/qconf.h21
-rwxr-xr-xscripts/kconfig/streamline_config.pl18
-rw-r--r--scripts/kconfig/symbol.c485
-rw-r--r--scripts/kconfig/tests/choice/Kconfig43
-rw-r--r--scripts/kconfig/tests/choice/__init__.py12
-rw-r--r--scripts/kconfig/tests/choice/alldef_expected_config3
-rw-r--r--scripts/kconfig/tests/choice/allmod_expected_config7
-rw-r--r--scripts/kconfig/tests/choice/allno_expected_config3
-rw-r--r--scripts/kconfig/tests/choice/allyes_expected_config7
-rw-r--r--scripts/kconfig/tests/choice/oldask0_expected_stdout6
-rw-r--r--scripts/kconfig/tests/choice/oldask1_config2
-rw-r--r--scripts/kconfig/tests/choice/oldask1_expected_stdout15
-rw-r--r--scripts/kconfig/tests/choice_randomize/Kconfig22
-rw-r--r--scripts/kconfig/tests/choice_randomize/__init__.py34
-rw-r--r--scripts/kconfig/tests/choice_randomize/expected_config06
-rw-r--r--scripts/kconfig/tests/choice_randomize/expected_config18
-rw-r--r--scripts/kconfig/tests/choice_randomize/expected_config28
-rw-r--r--scripts/kconfig/tests/choice_randomize2/Kconfig32
-rw-r--r--scripts/kconfig/tests/choice_randomize2/__init__.py18
-rw-r--r--scripts/kconfig/tests/choice_randomize2/expected_config08
-rw-r--r--scripts/kconfig/tests/choice_randomize2/expected_config17
-rw-r--r--scripts/kconfig/tests/choice_randomize2/expected_config26
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/Kconfig21
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/__init__.py16
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/config2
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/expected_config3
-rw-r--r--scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout4
-rw-r--r--scripts/kconfig/tests/conftest.py16
-rw-r--r--scripts/kconfig/tests/err_recursive_dep/expected_stderr36
-rw-r--r--scripts/kconfig/tests/inter_choice/Kconfig25
-rw-r--r--scripts/kconfig/tests/inter_choice/__init__.py15
-rw-r--r--scripts/kconfig/tests/inter_choice/defconfig1
-rw-r--r--scripts/kconfig/tests/inter_choice/expected_config4
-rw-r--r--scripts/kconfig/util.c90
67 files changed, 1548 insertions, 2270 deletions
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index ea1bf3b3dbde..fb50bd4f4103 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -57,7 +57,7 @@ $(foreach c, config menuconfig nconfig gconfig xconfig, $(eval $(call config_rul
PHONY += localmodconfig localyesconfig
localyesconfig localmodconfig: $(obj)/conf
- $(Q)$(PERL) $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
+ $(Q)$(PERL) $(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config
$(Q)if [ -f .config ]; then \
cmp -s .tmp.config .config || \
(mv -f .config .config.old.1; \
@@ -105,9 +105,11 @@ configfiles = $(wildcard $(srctree)/kernel/configs/$(1) $(srctree)/arch/$(SRCARC
all-config-fragments = $(call configfiles,*.config)
config-fragments = $(call configfiles,$@)
+cmd_merge_fragments = $(srctree)/scripts/kconfig/merge_config.sh -m $(KCONFIG_CONFIG) $(config-fragments)
+
%.config: $(obj)/conf
$(if $(config-fragments),, $(error $@ fragment does not exists on this architecture))
- $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m $(KCONFIG_CONFIG) $(config-fragments)
+ $(call cmd,merge_fragments)
$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
PHONY += tinyconfig
@@ -118,7 +120,7 @@ tinyconfig:
# CHECK: -o cache_dir=<path> working?
PHONY += testconfig
testconfig: $(obj)/conf
- $(Q)$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
+ $(Q)$(PYTHON3) -B -m pytest $(src)/tests \
-o cache_dir=$(abspath $(obj)/tests/.cache) \
$(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
clean-files += tests/.cache
@@ -165,8 +167,8 @@ common-objs := confdata.o expr.o lexer.lex.o menu.o parser.tab.o \
preprocess.o symbol.o util.o
$(obj)/lexer.lex.o: $(obj)/parser.tab.h
-HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src)
-HOSTCFLAGS_parser.tab.o := -I $(srctree)/$(src)
+HOSTCFLAGS_lexer.lex.o := -I $(src)
+HOSTCFLAGS_parser.tab.o := -I $(src)
# conf: Used for defconfig, oldconfig and related targets
hostprogs += conf
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 662a5e7c37c2..8abe57041955 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -14,6 +14,7 @@
#include <sys/time.h>
#include <errno.h>
+#include "internal.h"
#include "lkc.h"
static void conf(struct menu *menu);
@@ -113,51 +114,54 @@ static void set_randconfig_seed(void)
srand(seed);
}
-static bool randomize_choice_values(struct symbol *csym)
+/**
+ * randomize_choice_values - randomize choice block
+ *
+ * @choice: menu entry for the choice
+ */
+static void randomize_choice_values(struct menu *choice)
{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
- int cnt, def;
+ struct menu *menu;
+ int x;
+ int cnt = 0;
/*
- * If choice is mod then we may have more items selected
- * and if no then no-one.
- * In both cases stop.
+ * First, count the number of symbols to randomize. If sym_has_value()
+ * is true, it was specified by KCONFIG_ALLCONFIG. It needs to be
+ * respected.
*/
- if (csym->curr.tri != yes)
- return false;
+ menu_for_each_sub_entry(menu, choice) {
+ struct symbol *sym = menu->sym;
+
+ if (sym && !sym_has_value(sym))
+ cnt++;
+ }
- prop = sym_get_choice_prop(csym);
+ while (cnt > 0) {
+ x = rand() % cnt;
- /* count entries in choice block */
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym)
- cnt++;
+ menu_for_each_sub_entry(menu, choice) {
+ struct symbol *sym = menu->sym;
- /*
- * find a random value and set it to yes,
- * set the rest to no so we have only one set
- */
- def = rand() % cnt;
-
- cnt = 0;
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (def == cnt++) {
- sym->def[S_DEF_USER].tri = yes;
- csym->def[S_DEF_USER].val = sym;
- } else {
- sym->def[S_DEF_USER].tri = no;
+ if (sym && !sym_has_value(sym))
+ x--;
+
+ if (x < 0) {
+ sym->def[S_DEF_USER].tri = yes;
+ sym->flags |= SYMBOL_DEF_USER;
+ /*
+ * Move the selected item to the _tail_ because
+ * this needs to have a lower priority than the
+ * user input from KCONFIG_ALLCONFIG.
+ */
+ list_move_tail(&sym->choice_link,
+ &choice->choice_members);
+
+ break;
+ }
}
- sym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- sym->flags &= ~SYMBOL_VALID;
+ cnt--;
}
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~SYMBOL_VALID;
-
- return true;
}
enum conf_def_mode {
@@ -168,10 +172,10 @@ enum conf_def_mode {
def_random
};
-static bool conf_set_all_new_symbols(enum conf_def_mode mode)
+static void conf_set_all_new_symbols(enum conf_def_mode mode)
{
- struct symbol *sym, *csym;
- int i, cnt;
+ struct menu *menu;
+ int cnt;
/*
* can't go as the default in switch-case below, otherwise gcc whines
* about -Wmaybe-uninitialized
@@ -179,7 +183,6 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
int pby = 50; /* probability of bool = y */
int pty = 33; /* probability of tristate = y */
int ptm = 33; /* probability of tristate = m */
- bool has_changed = false;
if (mode == def_random) {
int n, p[3];
@@ -226,87 +229,58 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
}
}
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) || sym->flags & SYMBOL_VALID)
- continue;
- switch (sym_get_type(sym)) {
- case S_BOOLEAN:
- case S_TRISTATE:
- has_changed = true;
- switch (mode) {
- case def_yes:
- sym->def[S_DEF_USER].tri = yes;
- break;
- case def_mod:
- sym->def[S_DEF_USER].tri = mod;
- break;
- case def_no:
- sym->def[S_DEF_USER].tri = no;
- break;
- case def_random:
- sym->def[S_DEF_USER].tri = no;
- cnt = rand() % 100;
- if (sym->type == S_TRISTATE) {
- if (cnt < pty)
- sym->def[S_DEF_USER].tri = yes;
- else if (cnt < pty + ptm)
- sym->def[S_DEF_USER].tri = mod;
- } else if (cnt < pby)
- sym->def[S_DEF_USER].tri = yes;
- break;
- default:
- continue;
- }
- if (!(sym_is_choice(sym) && mode == def_random))
- sym->flags |= SYMBOL_DEF_USER;
- break;
- default:
- break;
- }
+ menu_for_each_entry(menu) {
+ struct symbol *sym = menu->sym;
+ tristate val;
- }
-
- sym_clear_all_valid();
+ if (!sym || !menu->prompt || sym_has_value(sym) ||
+ (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
+ sym_is_choice_value(sym))
+ continue;
- /*
- * We have different type of choice blocks.
- * If curr.tri equals to mod then we can select several
- * choice symbols in one block.
- * In this case we do nothing.
- * If curr.tri equals yes then only one symbol can be
- * selected in a choice block and we set it to yes,
- * and the rest to no.
- */
- if (mode != def_random) {
- for_all_symbols(i, csym) {
- if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
- sym_is_choice_value(csym))
- csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
+ if (sym_is_choice(sym)) {
+ if (mode == def_random)
+ randomize_choice_values(menu);
+ continue;
}
- }
- for_all_symbols(i, csym) {
- if (sym_has_value(csym) || !sym_is_choice(csym))
+ switch (mode) {
+ case def_yes:
+ val = yes;
+ break;
+ case def_mod:
+ val = mod;
+ break;
+ case def_no:
+ val = no;
+ break;
+ case def_random:
+ val = no;
+ cnt = rand() % 100;
+ if (sym->type == S_TRISTATE) {
+ if (cnt < pty)
+ val = yes;
+ else if (cnt < pty + ptm)
+ val = mod;
+ } else if (cnt < pby) {
+ val = yes;
+ }
+ break;
+ default:
continue;
-
- sym_calc_value(csym);
- if (mode == def_random)
- has_changed |= randomize_choice_values(csym);
- else {
- set_all_choice_values(csym);
- has_changed = true;
}
+ sym->def[S_DEF_USER].tri = val;
+ sym->flags |= SYMBOL_DEF_USER;
}
- return has_changed;
+ sym_clear_all_valid();
}
static void conf_rewrite_tristates(tristate old_val, tristate new_val)
{
struct symbol *sym;
- int i;
- for_all_symbols(i, sym) {
+ for_all_symbols(sym) {
if (sym_get_type(sym) == S_TRISTATE &&
sym->def[S_DEF_USER].tri == old_val)
sym->def[S_DEF_USER].tri = new_val;
@@ -446,42 +420,17 @@ help:
}
}
-static int conf_choice(struct menu *menu)
+static void conf_choice(struct menu *menu)
{
- struct symbol *sym, *def_sym;
+ struct symbol *def_sym;
struct menu *child;
- bool is_new;
-
- sym = menu->sym;
- is_new = !sym_has_value(sym);
- if (sym_is_changeable(sym)) {
- conf_sym(menu);
- sym_calc_value(sym);
- switch (sym_get_tristate_value(sym)) {
- case no:
- return 1;
- case mod:
- return 0;
- case yes:
- break;
- }
- } else {
- switch (sym_get_tristate_value(sym)) {
- case no:
- return 1;
- case mod:
- printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
- return 0;
- case yes:
- break;
- }
- }
+ bool is_new = false;
while (1) {
int cnt, def;
printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
- def_sym = sym_get_choice_value(sym);
+ def_sym = sym_calc_choice(menu);
cnt = def = 0;
line[0] = 0;
for (child = menu->list; child; child = child->next) {
@@ -497,11 +446,12 @@ static int conf_choice(struct menu *menu)
printf("%*c", indent, '>');
} else
printf("%*c", indent, ' ');
- printf(" %d. %s", cnt, menu_get_prompt(child));
- if (child->sym->name)
- printf(" (%s)", child->sym->name);
- if (!sym_has_value(child->sym))
+ printf(" %d. %s (%s)", cnt, menu_get_prompt(child),
+ child->sym->name);
+ if (!sym_has_value(child->sym)) {
+ is_new = true;
printf(" (NEW)");
+ }
printf("\n");
}
printf("%*schoice", indent - 1, "");
@@ -551,13 +501,8 @@ static int conf_choice(struct menu *menu)
print_help(child);
continue;
}
- sym_set_tristate_value(child->sym, yes);
- for (child = child->list; child; child = child->next) {
- indent += 2;
- conf(child);
- indent -= 2;
- }
- return 1;
+ choice_set_value(menu, child->sym);
+ return;
}
}
@@ -603,9 +548,7 @@ static void conf(struct menu *menu)
if (sym_is_choice(sym)) {
conf_choice(menu);
- if (sym->curr.tri != mod)
- return;
- goto conf_childs;
+ return;
}
switch (sym->type) {
@@ -637,10 +580,7 @@ static void check_conf(struct menu *menu)
return;
sym = menu->sym;
- if (sym && !sym_has_value(sym) &&
- (sym_is_changeable(sym) ||
- (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) {
-
+ if (sym && !sym_has_value(sym) && sym_is_changeable(sym)) {
switch (input_mode) {
case listnewconfig:
if (sym->name)
@@ -688,7 +628,7 @@ static const struct option long_opts[] = {
static void conf_usage(const char *progname)
{
- printf("Usage: %s [options] <kconfig-file>\n", progname);
+ printf("Usage: %s [options] kconfig_file\n", progname);
printf("\n");
printf("Generic options:\n");
printf(" -h, --help Print this message and exit.\n");
@@ -713,6 +653,9 @@ static void conf_usage(const char *progname)
printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
printf(" --mod2noconfig Change answers from mod to no if possible\n");
printf(" (If none of the above is given, --oldaskconfig is the default)\n");
+ printf("\n");
+ printf("Arguments:\n");
+ printf(" kconfig_file Top-level Kconfig file.\n");
}
int main(int ac, char **av)
@@ -856,8 +799,7 @@ int main(int ac, char **av)
conf_set_all_new_symbols(def_default);
break;
case randconfig:
- /* Really nothing to do in this loop */
- while (conf_set_all_new_symbols(def_random)) ;
+ conf_set_all_new_symbols(def_random);
break;
case defconfig:
conf_set_all_new_symbols(def_default);
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index f53dcdd44597..3b55e7a4131d 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -18,8 +18,12 @@
#include <time.h>
#include <unistd.h>
+#include <xalloc.h>
+#include "internal.h"
#include "lkc.h"
+struct gstr autoconf_cmd;
+
/* return true if 'path' exists, false otherwise */
static bool is_present(const char *path)
{
@@ -293,63 +297,12 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
return 0;
}
-#define LINE_GROWTH 16
-static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
-{
- size_t new_size = slen + 1;
-
- if (new_size > *n) {
- new_size += LINE_GROWTH - 1;
- new_size *= 2;
- *lineptr = xrealloc(*lineptr, new_size);
- *n = new_size;
- }
-
- (*lineptr)[slen] = c;
-
- return 0;
-}
-
-static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
-{
- char *line = *lineptr;
- size_t slen = 0;
-
- for (;;) {
- int c = getc(stream);
-
- switch (c) {
- case '\n':
- if (add_byte(c, &line, slen, n) < 0)
- goto e_out;
- slen++;
- /* fall through */
- case EOF:
- if (add_byte('\0', &line, slen, n) < 0)
- goto e_out;
- *lineptr = line;
- if (slen == 0)
- return -1;
- return slen;
- default:
- if (add_byte(c, &line, slen, n) < 0)
- goto e_out;
- slen++;
- }
- }
-
-e_out:
- line[slen-1] = '\0';
- *lineptr = line;
- return -1;
-}
-
/* like getline(), but the newline character is stripped away */
static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream)
{
ssize_t len;
- len = compat_getline(lineptr, n, stream);
+ len = getline(lineptr, n, stream);
if (len > 0 && (*lineptr)[len - 1] == '\n') {
len--;
@@ -371,7 +324,7 @@ int conf_read_simple(const char *name, int def)
size_t line_asize = 0;
char *p, *val;
struct symbol *sym;
- int i, def_flags;
+ int def_flags;
const char *warn_unknown, *sym_name;
warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS");
@@ -407,10 +360,12 @@ int conf_read_simple(const char *name, int def)
*p = '\0';
- in = zconf_fopen(env);
+ name = env;
+
+ in = zconf_fopen(name);
if (in) {
conf_message("using defaults found in %s",
- env);
+ name);
goto load;
}
@@ -429,11 +384,8 @@ load:
conf_warnings = 0;
def_flags = SYMBOL_DEF << def;
- for_all_symbols(i, sym) {
- sym->flags |= SYMBOL_CHANGED;
+ for_all_symbols(sym) {
sym->flags &= ~(def_flags|SYMBOL_VALID);
- if (sym_is_choice(sym))
- sym->flags |= def_flags;
switch (sym->type) {
case S_INT:
case S_HEX:
@@ -446,7 +398,11 @@ load:
}
}
+ expr_invalidate_all();
+
while (getline_stripped(&line, &line_asize, in) != -1) {
+ struct menu *choice;
+
conf_lineno++;
if (!line[0]) /* blank line */
@@ -508,25 +464,14 @@ load:
if (conf_set_sym_val(sym, def, def_flags, val))
continue;
- if (sym && sym_is_choice_value(sym)) {
- struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
- switch (sym->def[def].tri) {
- case no:
- break;
- case mod:
- if (cs->def[def].tri == yes) {
- conf_warning("%s creates inconsistent choice state", sym->name);
- cs->flags &= ~def_flags;
- }
- break;
- case yes:
- if (cs->def[def].tri != no)
- conf_warning("override: %s changes choice state", sym->name);
- cs->def[def].val = sym;
- break;
- }
- cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
- }
+ /*
+ * If this is a choice member, give it the highest priority.
+ * If conflicting CONFIG options are given from an input file,
+ * the last one wins.
+ */
+ choice = sym_get_choice_menu(sym);
+ if (choice)
+ list_move(&sym->choice_link, &choice->choice_members);
}
free(line);
fclose(in);
@@ -537,8 +482,6 @@ load:
int conf_read(const char *name)
{
struct symbol *sym;
- int conf_unsaved = 0;
- int i;
conf_set_changed(false);
@@ -549,9 +492,9 @@ int conf_read(const char *name)
sym_calc_value(modules_sym);
- for_all_symbols(i, sym) {
+ for_all_symbols(sym) {
sym_calc_value(sym);
- if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
+ if (sym_is_choice(sym))
continue;
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
/* check that calculated value agrees with saved value */
@@ -569,36 +512,11 @@ int conf_read(const char *name)
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
/* no previous value and not saved */
continue;
- conf_unsaved++;
+ conf_set_changed(true);
/* maybe print value in verbose mode... */
}
- for_all_symbols(i, sym) {
- if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
- /* Reset values of generates values, so they'll appear
- * as new, if they should become visible, but that
- * doesn't quite work if the Kconfig and the saved
- * configuration disagree.
- */
- if (sym->visible == no && !conf_unsaved)
- sym->flags &= ~SYMBOL_DEF_USER;
- switch (sym->type) {
- case S_STRING:
- case S_INT:
- case S_HEX:
- /* Reset a string value if it's out of range */
- if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
- break;
- sym->flags &= ~SYMBOL_VALID;
- conf_unsaved++;
- break;
- default:
- break;
- }
- }
- }
-
- if (conf_warnings || conf_unsaved)
+ if (conf_warnings)
conf_set_changed(true);
return 0;
@@ -842,62 +760,35 @@ int conf_write_defconfig(const char *filename)
sym_clear_all_valid();
- /* Traverse all menus to find all relevant symbols */
- menu = rootmenu.list;
+ menu_for_each_entry(menu) {
+ struct menu *choice;
- while (menu != NULL)
- {
sym = menu->sym;
- if (sym == NULL) {
- if (!menu_is_visible(menu))
- goto next_menu;
- } else if (!sym_is_choice(sym)) {
- sym_calc_value(sym);
- if (!(sym->flags & SYMBOL_WRITE))
- goto next_menu;
- sym->flags &= ~SYMBOL_WRITE;
- /* If we cannot change the symbol - skip */
- if (!sym_is_changeable(sym))
- goto next_menu;
- /* If symbol equals to default value - skip */
- if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
- goto next_menu;
-
- /*
- * If symbol is a choice value and equals to the
- * default for a choice - skip.
- * But only if value is bool and equal to "y" and
- * choice is not "optional".
- * (If choice is "optional" then all values can be "n")
- */
- if (sym_is_choice_value(sym)) {
- struct symbol *cs;
- struct symbol *ds;
-
- cs = prop_get_symbol(sym_get_choice_prop(sym));
- ds = sym_choice_default(cs);
- if (!sym_is_optional(cs) && sym == ds) {
- if ((sym->type == S_BOOLEAN) &&
- sym_get_tristate_value(sym) == yes)
- goto next_menu;
- }
- }
- print_symbol_for_dotconfig(out, sym);
- }
-next_menu:
- if (menu->list != NULL) {
- menu = menu->list;
- }
- else if (menu->next != NULL) {
- menu = menu->next;
- } else {
- while ((menu = menu->parent)) {
- if (menu->next != NULL) {
- menu = menu->next;
- break;
- }
- }
+
+ if (!sym || sym_is_choice(sym))
+ continue;
+
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ continue;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* Skip unchangeable symbols */
+ if (!sym_is_changeable(sym))
+ continue;
+ /* Skip symbols that are equal to the default */
+ if (!strcmp(sym_get_string_value(sym), sym_get_string_default(sym)))
+ continue;
+
+ /* Skip choice values that are equal to the default */
+ choice = sym_get_choice_menu(sym);
+ if (choice) {
+ struct symbol *ds;
+
+ ds = sym_choice_default(choice);
+ if (sym == ds && sym_get_tristate_value(sym) == yes)
+ continue;
}
+ print_symbol_for_dotconfig(out, sym);
}
fclose(out);
return 0;
@@ -911,7 +802,6 @@ int conf_write(const char *name)
const char *str;
char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
char *env;
- int i;
bool need_newline = false;
if (!name)
@@ -959,7 +849,7 @@ int conf_write(const char *name)
"# %s\n"
"#\n", str);
need_newline = false;
- } else if (!(sym->flags & SYMBOL_CHOICE) &&
+ } else if (!sym_is_choice(sym) &&
!(sym->flags & SYMBOL_WRITTEN)) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE))
@@ -995,7 +885,7 @@ end_check:
}
fclose(out);
- for_all_symbols(i, sym)
+ for_all_symbols(sym)
sym->flags &= ~SYMBOL_WRITTEN;
if (*tmpname) {
@@ -1023,7 +913,6 @@ end_check:
static int conf_write_autoconf_cmd(const char *autoconf_name)
{
char name[PATH_MAX], tmp[PATH_MAX];
- struct file *file;
FILE *out;
int ret;
@@ -1044,15 +933,9 @@ static int conf_write_autoconf_cmd(const char *autoconf_name)
return -1;
}
- fprintf(out, "deps_config := \\\n");
- for (file = file_list; file; file = file->next)
- fprintf(out, "\t%s \\\n", file->name);
+ fprintf(out, "autoconfig := %s\n", autoconf_name);
- fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name);
-
- env_write_dep(out, autoconf_name);
-
- fprintf(out, "\n$(deps_config): ;\n");
+ fputs(str_get(&autoconf_cmd), out);
fflush(out);
ret = ferror(out); /* error check for all fprintf() calls */
@@ -1072,7 +955,7 @@ static int conf_touch_deps(void)
{
const char *name, *tmp;
struct symbol *sym;
- int res, i;
+ int res;
name = conf_get_autoconfig_name();
tmp = strrchr(name, '/');
@@ -1086,9 +969,9 @@ static int conf_touch_deps(void)
conf_read_simple(name, S_DEF_AUTO);
sym_calc_value(modules_sym);
- for_all_symbols(i, sym) {
+ for_all_symbols(sym) {
sym_calc_value(sym);
- if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
+ if (sym_is_choice(sym))
continue;
if (sym->flags & SYMBOL_WRITE) {
if (sym->flags & SYMBOL_DEF_AUTO) {
@@ -1152,7 +1035,7 @@ static int __conf_write_autoconf(const char *filename,
char tmp[PATH_MAX];
FILE *file;
struct symbol *sym;
- int ret, i;
+ int ret;
if (make_parent_dir(filename))
return -1;
@@ -1169,7 +1052,7 @@ static int __conf_write_autoconf(const char *filename,
conf_write_heading(file, comment_style);
- for_all_symbols(i, sym)
+ for_all_symbols(sym)
if ((sym->flags & SYMBOL_WRITE) && sym->name)
print_symbol(file, sym);
@@ -1192,7 +1075,7 @@ int conf_write_autoconf(int overwrite)
{
struct symbol *sym;
const char *autoconf_name = conf_get_autoconfig_name();
- int ret, i;
+ int ret;
if (!overwrite && is_present(autoconf_name))
return 0;
@@ -1204,7 +1087,7 @@ int conf_write_autoconf(int overwrite)
if (conf_touch_deps())
return 1;
- for_all_symbols(i, sym)
+ for_all_symbols(sym)
sym_calc_value(sym);
ret = __conf_write_autoconf(conf_get_autoheader_name(),
@@ -1234,16 +1117,14 @@ int conf_write_autoconf(int overwrite)
}
static bool conf_changed;
-static void (*conf_changed_callback)(void);
+static void (*conf_changed_callback)(bool);
void conf_set_changed(bool val)
{
- bool changed = conf_changed != val;
+ if (conf_changed_callback && conf_changed != val)
+ conf_changed_callback(val);
conf_changed = val;
-
- if (conf_changed_callback && changed)
- conf_changed_callback();
}
bool conf_get_changed(void)
@@ -1251,27 +1132,7 @@ bool conf_get_changed(void)
return conf_changed;
}
-void conf_set_changed_callback(void (*fn)(void))
+void conf_set_changed_callback(void (*fn)(bool))
{
conf_changed_callback = fn;
}
-
-void set_all_choice_values(struct symbol *csym)
-{
- struct property *prop;
- struct symbol *sym;
- struct expr *e;
-
- prop = sym_get_choice_prop(csym);
-
- /*
- * Set all non-assinged choice values to no
- */
- expr_list_for_each_sym(prop->expr, e, sym) {
- if (!sym_has_value(sym))
- sym->def[S_DEF_USER].tri = no;
- }
- csym->flags |= SYMBOL_DEF_USER;
- /* clear VALID to get value calculated */
- csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
-}
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index a290de36307b..16f92c4a775a 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -9,44 +9,69 @@
#include <stdlib.h>
#include <string.h>
+#include <hash.h>
+#include <xalloc.h>
+#include "internal.h"
#include "lkc.h"
#define DEBUG_EXPR 0
+HASHTABLE_DEFINE(expr_hashtable, EXPR_HASHSIZE);
+
static struct expr *expr_eliminate_yn(struct expr *e);
-struct expr *expr_alloc_symbol(struct symbol *sym)
+/**
+ * expr_lookup - return the expression with the given type and sub-nodes
+ * This looks up an expression with the specified type and sub-nodes. If such
+ * an expression is found in the hash table, it is returned. Otherwise, a new
+ * expression node is allocated and added to the hash table.
+ * @type: expression type
+ * @l: left node
+ * @r: right node
+ * return: expression
+ */
+static struct expr *expr_lookup(enum expr_type type, void *l, void *r)
{
- struct expr *e = xcalloc(1, sizeof(*e));
- e->type = E_SYMBOL;
- e->left.sym = sym;
+ struct expr *e;
+ int hash;
+
+ hash = hash_32((unsigned int)type ^ hash_ptr(l) ^ hash_ptr(r));
+
+ hash_for_each_possible(expr_hashtable, e, node, hash) {
+ if (e->type == type && e->left._initdata == l &&
+ e->right._initdata == r)
+ return e;
+ }
+
+ e = xmalloc(sizeof(*e));
+ e->type = type;
+ e->left._initdata = l;
+ e->right._initdata = r;
+ e->val_is_valid = false;
+
+ hash_add(expr_hashtable, &e->node, hash);
+
return e;
}
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+ return expr_lookup(E_SYMBOL, sym, NULL);
+}
+
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
{
- struct expr *e = xcalloc(1, sizeof(*e));
- e->type = type;
- e->left.expr = ce;
- return e;
+ return expr_lookup(type, ce, NULL);
}
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
{
- struct expr *e = xcalloc(1, sizeof(*e));
- e->type = type;
- e->left.expr = e1;
- e->right.expr = e2;
- return e;
+ return expr_lookup(type, e1, e2);
}
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
{
- struct expr *e = xcalloc(1, sizeof(*e));
- e->type = type;
- e->left.sym = s1;
- e->right.sym = s2;
- return e;
+ return expr_lookup(type, s1, s2);
}
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
@@ -63,82 +88,8 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
}
-struct expr *expr_copy(const struct expr *org)
-{
- struct expr *e;
-
- if (!org)
- return NULL;
-
- e = xmalloc(sizeof(*org));
- memcpy(e, org, sizeof(*org));
- switch (org->type) {
- case E_SYMBOL:
- e->left = org->left;
- break;
- case E_NOT:
- e->left.expr = expr_copy(org->left.expr);
- break;
- case E_EQUAL:
- case E_GEQ:
- case E_GTH:
- case E_LEQ:
- case E_LTH:
- case E_UNEQUAL:
- e->left.sym = org->left.sym;
- e->right.sym = org->right.sym;
- break;
- case E_AND:
- case E_OR:
- case E_LIST:
- e->left.expr = expr_copy(org->left.expr);
- e->right.expr = expr_copy(org->right.expr);
- break;
- default:
- fprintf(stderr, "can't copy type %d\n", e->type);
- free(e);
- e = NULL;
- break;
- }
-
- return e;
-}
-
-void expr_free(struct expr *e)
-{
- if (!e)
- return;
-
- switch (e->type) {
- case E_SYMBOL:
- break;
- case E_NOT:
- expr_free(e->left.expr);
- break;
- case E_EQUAL:
- case E_GEQ:
- case E_GTH:
- case E_LEQ:
- case E_LTH:
- case E_UNEQUAL:
- break;
- case E_OR:
- case E_AND:
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- break;
- default:
- fprintf(stderr, "how to free type %d?\n", e->type);
- break;
- }
- free(e);
-}
-
static int trans_count;
-#define e1 (*ep1)
-#define e2 (*ep2)
-
/*
* expr_eliminate_eq() helper.
*
@@ -149,40 +100,47 @@ static int trans_count;
*/
static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
{
+ struct expr *l, *r;
+
/* Recurse down to leaves */
- if (e1->type == type) {
- __expr_eliminate_eq(type, &e1->left.expr, &e2);
- __expr_eliminate_eq(type, &e1->right.expr, &e2);
+ if ((*ep1)->type == type) {
+ l = (*ep1)->left.expr;
+ r = (*ep1)->right.expr;
+ __expr_eliminate_eq(type, &l, ep2);
+ __expr_eliminate_eq(type, &r, ep2);
+ *ep1 = expr_alloc_two(type, l, r);
return;
}
- if (e2->type == type) {
- __expr_eliminate_eq(type, &e1, &e2->left.expr);
- __expr_eliminate_eq(type, &e1, &e2->right.expr);
+ if ((*ep2)->type == type) {
+ l = (*ep2)->left.expr;
+ r = (*ep2)->right.expr;
+ __expr_eliminate_eq(type, ep1, &l);
+ __expr_eliminate_eq(type, ep1, &r);
+ *ep2 = expr_alloc_two(type, l, r);
return;
}
- /* e1 and e2 are leaves. Compare them. */
+ /* *ep1 and *ep2 are leaves. Compare them. */
- if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
- e1->left.sym == e2->left.sym &&
- (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+ if ((*ep1)->type == E_SYMBOL && (*ep2)->type == E_SYMBOL &&
+ (*ep1)->left.sym == (*ep2)->left.sym &&
+ ((*ep1)->left.sym == &symbol_yes || (*ep1)->left.sym == &symbol_no))
return;
- if (!expr_eq(e1, e2))
+ if (!expr_eq(*ep1, *ep2))
return;
- /* e1 and e2 are equal leaves. Prepare them for elimination. */
+ /* *ep1 and *ep2 are equal leaves. Prepare them for elimination. */
trans_count++;
- expr_free(e1); expr_free(e2);
switch (type) {
case E_OR:
- e1 = expr_alloc_symbol(&symbol_no);
- e2 = expr_alloc_symbol(&symbol_no);
+ *ep1 = expr_alloc_symbol(&symbol_no);
+ *ep2 = expr_alloc_symbol(&symbol_no);
break;
case E_AND:
- e1 = expr_alloc_symbol(&symbol_yes);
- e2 = expr_alloc_symbol(&symbol_yes);
+ *ep1 = expr_alloc_symbol(&symbol_yes);
+ *ep2 = expr_alloc_symbol(&symbol_yes);
break;
default:
;
@@ -220,38 +178,36 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
*/
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{
- if (!e1 || !e2)
+ if (!*ep1 || !*ep2)
return;
- switch (e1->type) {
+ switch ((*ep1)->type) {
case E_OR:
case E_AND:
- __expr_eliminate_eq(e1->type, ep1, ep2);
+ __expr_eliminate_eq((*ep1)->type, ep1, ep2);
default:
;
}
- if (e1->type != e2->type) switch (e2->type) {
+ if ((*ep1)->type != (*ep2)->type) switch ((*ep2)->type) {
case E_OR:
case E_AND:
- __expr_eliminate_eq(e2->type, ep1, ep2);
+ __expr_eliminate_eq((*ep2)->type, ep1, ep2);
default:
;
}
- e1 = expr_eliminate_yn(e1);
- e2 = expr_eliminate_yn(e2);
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
}
-#undef e1
-#undef e2
-
/*
* Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
* &&/|| expressions are considered equal if every operand in one expression
* equals some operand in the other (operands do not need to appear in the same
* order), recursively.
*/
-int expr_eq(struct expr *e1, struct expr *e2)
+bool expr_eq(struct expr *e1, struct expr *e2)
{
- int res, old_count;
+ int old_count;
+ bool res;
/*
* A NULL expr is taken to be yes, but there's also a different way to
@@ -261,7 +217,7 @@ int expr_eq(struct expr *e1, struct expr *e2)
return expr_is_yes(e1) && expr_is_yes(e2);
if (e1->type != e2->type)
- return 0;
+ return false;
switch (e1->type) {
case E_EQUAL:
case E_GEQ:
@@ -276,17 +232,12 @@ int expr_eq(struct expr *e1, struct expr *e2)
return expr_eq(e1->left.expr, e2->left.expr);
case E_AND:
case E_OR:
- e1 = expr_copy(e1);
- e2 = expr_copy(e2);
old_count = trans_count;
expr_eliminate_eq(&e1, &e2);
res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
e1->left.sym == e2->left.sym);
- expr_free(e1);
- expr_free(e2);
trans_count = old_count;
return res;
- case E_LIST:
case E_RANGE:
case E_NONE:
/* panic */;
@@ -299,11 +250,11 @@ int expr_eq(struct expr *e1, struct expr *e2)
printf(" ?\n");
}
- return 0;
+ return false;
}
/*
- * Recursively performs the following simplifications in-place (as well as the
+ * Recursively performs the following simplifications (as well as the
* corresponding simplifications with swapped operands):
*
* expr && n -> n
@@ -315,108 +266,39 @@ int expr_eq(struct expr *e1, struct expr *e2)
*/
static struct expr *expr_eliminate_yn(struct expr *e)
{
- struct expr *tmp;
+ struct expr *l, *r;
if (e) switch (e->type) {
case E_AND:
- e->left.expr = expr_eliminate_yn(e->left.expr);
- e->right.expr = expr_eliminate_yn(e->right.expr);
- if (e->left.expr->type == E_SYMBOL) {
- if (e->left.expr->left.sym == &symbol_no) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- e->right.expr = NULL;
- return e;
- } else if (e->left.expr->left.sym == &symbol_yes) {
- free(e->left.expr);
- tmp = e->right.expr;
- *e = *(e->right.expr);
- free(tmp);
- return e;
- }
+ l = expr_eliminate_yn(e->left.expr);
+ r = expr_eliminate_yn(e->right.expr);
+ if (l->type == E_SYMBOL) {
+ if (l->left.sym == &symbol_no)
+ return l;
+ else if (l->left.sym == &symbol_yes)
+ return r;
}
- if (e->right.expr->type == E_SYMBOL) {
- if (e->right.expr->left.sym == &symbol_no) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- e->right.expr = NULL;
- return e;
- } else if (e->right.expr->left.sym == &symbol_yes) {
- free(e->right.expr);
- tmp = e->left.expr;
- *e = *(e->left.expr);
- free(tmp);
- return e;
- }
+ if (r->type == E_SYMBOL) {
+ if (r->left.sym == &symbol_no)
+ return r;
+ else if (r->left.sym == &symbol_yes)
+ return l;
}
break;
case E_OR:
- e->left.expr = expr_eliminate_yn(e->left.expr);
- e->right.expr = expr_eliminate_yn(e->right.expr);
- if (e->left.expr->type == E_SYMBOL) {
- if (e->left.expr->left.sym == &symbol_no) {
- free(e->left.expr);
- tmp = e->right.expr;
- *e = *(e->right.expr);
- free(tmp);
- return e;
- } else if (e->left.expr->left.sym == &symbol_yes) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- e->right.expr = NULL;
- return e;
- }
+ l = expr_eliminate_yn(e->left.expr);
+ r = expr_eliminate_yn(e->right.expr);
+ if (l->type == E_SYMBOL) {
+ if (l->left.sym == &symbol_no)
+ return r;
+ else if (l->left.sym == &symbol_yes)
+ return l;
}
- if (e->right.expr->type == E_SYMBOL) {
- if (e->right.expr->left.sym == &symbol_no) {
- free(e->right.expr);
- tmp = e->left.expr;
- *e = *(e->left.expr);
- free(tmp);
- return e;
- } else if (e->right.expr->left.sym == &symbol_yes) {
- expr_free(e->left.expr);
- expr_free(e->right.expr);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- e->right.expr = NULL;
- return e;
- }
- }
- break;
- default:
- ;
- }
- return e;
-}
-
-/*
- * bool FOO!=n => FOO
- */
-struct expr *expr_trans_bool(struct expr *e)
-{
- if (!e)
- return NULL;
- switch (e->type) {
- case E_AND:
- case E_OR:
- case E_NOT:
- e->left.expr = expr_trans_bool(e->left.expr);
- e->right.expr = expr_trans_bool(e->right.expr);
- break;
- case E_UNEQUAL:
- // FOO!=n -> FOO
- if (e->left.sym->type == S_TRISTATE) {
- if (e->right.sym == &symbol_no) {
- e->type = E_SYMBOL;
- e->right.sym = NULL;
- }
+ if (r->type == E_SYMBOL) {
+ if (r->left.sym == &symbol_no)
+ return l;
+ else if (r->left.sym == &symbol_yes)
+ return r;
}
break;
default:
@@ -434,7 +316,7 @@ static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
struct symbol *sym1, *sym2;
if (expr_eq(e1, e2))
- return expr_copy(e1);
+ return e1;
if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
return NULL;
if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
@@ -476,7 +358,8 @@ static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
}
}
- if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+ if (sym1->type == S_BOOLEAN) {
+ // a || !a -> y
if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
(e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
return expr_alloc_symbol(&symbol_yes);
@@ -498,7 +381,7 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
struct symbol *sym1, *sym2;
if (expr_eq(e1, e2))
- return expr_copy(e1);
+ return e1;
if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
return NULL;
if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
@@ -595,59 +478,49 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
*/
static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
{
-#define e1 (*ep1)
-#define e2 (*ep2)
- struct expr *tmp;
+ struct expr *tmp, *l, *r;
/* Recurse down to leaves */
- if (e1->type == type) {
- expr_eliminate_dups1(type, &e1->left.expr, &e2);
- expr_eliminate_dups1(type, &e1->right.expr, &e2);
+ if ((*ep1)->type == type) {
+ l = (*ep1)->left.expr;
+ r = (*ep1)->right.expr;
+ expr_eliminate_dups1(type, &l, ep2);
+ expr_eliminate_dups1(type, &r, ep2);
+ *ep1 = expr_alloc_two(type, l, r);
return;
}
- if (e2->type == type) {
- expr_eliminate_dups1(type, &e1, &e2->left.expr);
- expr_eliminate_dups1(type, &e1, &e2->right.expr);
+ if ((*ep2)->type == type) {
+ l = (*ep2)->left.expr;
+ r = (*ep2)->right.expr;
+ expr_eliminate_dups1(type, ep1, &l);
+ expr_eliminate_dups1(type, ep1, &r);
+ *ep2 = expr_alloc_two(type, l, r);
return;
}
- /* e1 and e2 are leaves. Compare and process them. */
-
- if (e1 == e2)
- return;
-
- switch (e1->type) {
- case E_OR: case E_AND:
- expr_eliminate_dups1(e1->type, &e1, &e1);
- default:
- ;
- }
+ /* *ep1 and *ep2 are leaves. Compare and process them. */
switch (type) {
case E_OR:
- tmp = expr_join_or(e1, e2);
+ tmp = expr_join_or(*ep1, *ep2);
if (tmp) {
- expr_free(e1); expr_free(e2);
- e1 = expr_alloc_symbol(&symbol_no);
- e2 = tmp;
+ *ep1 = expr_alloc_symbol(&symbol_no);
+ *ep2 = tmp;
trans_count++;
}
break;
case E_AND:
- tmp = expr_join_and(e1, e2);
+ tmp = expr_join_and(*ep1, *ep2);
if (tmp) {
- expr_free(e1); expr_free(e2);
- e1 = expr_alloc_symbol(&symbol_yes);
- e2 = tmp;
+ *ep1 = expr_alloc_symbol(&symbol_yes);
+ *ep2 = tmp;
trans_count++;
}
break;
default:
;
}
-#undef e1
-#undef e2
}
/*
@@ -668,19 +541,21 @@ struct expr *expr_eliminate_dups(struct expr *e)
return e;
oldcount = trans_count;
- while (1) {
+ do {
+ struct expr *l, *r;
+
trans_count = 0;
switch (e->type) {
case E_OR: case E_AND:
- expr_eliminate_dups1(e->type, &e, &e);
+ l = expr_eliminate_dups(e->left.expr);
+ r = expr_eliminate_dups(e->right.expr);
+ expr_eliminate_dups1(e->type, &l, &r);
+ e = expr_alloc_two(e->type, l, r);
default:
;
}
- if (!trans_count)
- /* No simplifications done in this pass. We're done */
- break;
e = expr_eliminate_yn(e);
- }
+ } while (trans_count); /* repeat until we get no more simplifications */
trans_count = oldcount;
return e;
}
@@ -689,12 +564,34 @@ struct expr *expr_eliminate_dups(struct expr *e)
* Performs various simplifications involving logical operators and
* comparisons.
*
+ * For bool type:
+ * A=n -> !A
+ * A=m -> n
+ * A=y -> A
+ * A!=n -> A
+ * A!=m -> y
+ * A!=y -> !A
+ *
+ * For any type:
+ * !!A -> A
+ * !(A=B) -> A!=B
+ * !(A!=B) -> A=B
+ * !(A<=B) -> A>B
+ * !(A>=B) -> A<B
+ * !(A<B) -> A>=B
+ * !(A>B) -> A<=B
+ * !(A || B) -> !A && !B
+ * !(A && B) -> !A || !B
+ *
+ * For constant:
+ * !y -> n
+ * !m -> m
+ * !n -> y
+ *
* Allocates and returns a new expression.
*/
struct expr *expr_transform(struct expr *e)
{
- struct expr *tmp;
-
if (!e)
return NULL;
switch (e->type) {
@@ -705,11 +602,11 @@ struct expr *expr_transform(struct expr *e)
case E_LTH:
case E_UNEQUAL:
case E_SYMBOL:
- case E_LIST:
break;
default:
- e->left.expr = expr_transform(e->left.expr);
- e->right.expr = expr_transform(e->right.expr);
+ e = expr_alloc_two(e->type,
+ expr_transform(e->left.expr),
+ expr_transform(e->right.expr));
}
switch (e->type) {
@@ -717,21 +614,19 @@ struct expr *expr_transform(struct expr *e)
if (e->left.sym->type != S_BOOLEAN)
break;
if (e->right.sym == &symbol_no) {
- e->type = E_NOT;
- e->left.expr = expr_alloc_symbol(e->left.sym);
- e->right.sym = NULL;
+ // A=n -> !A
+ e = expr_alloc_one(E_NOT, expr_alloc_symbol(e->left.sym));
break;
}
if (e->right.sym == &symbol_mod) {
+ // A=m -> n
printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- e->right.sym = NULL;
+ e = expr_alloc_symbol(&symbol_no);
break;
}
if (e->right.sym == &symbol_yes) {
- e->type = E_SYMBOL;
- e->right.sym = NULL;
+ // A=y -> A
+ e = expr_alloc_symbol(e->left.sym);
break;
}
break;
@@ -739,104 +634,71 @@ struct expr *expr_transform(struct expr *e)
if (e->left.sym->type != S_BOOLEAN)
break;
if (e->right.sym == &symbol_no) {
- e->type = E_SYMBOL;
- e->right.sym = NULL;
+ // A!=n -> A
+ e = expr_alloc_symbol(e->left.sym);
break;
}
if (e->right.sym == &symbol_mod) {
+ // A!=m -> y
printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- e->right.sym = NULL;
+ e = expr_alloc_symbol(&symbol_yes);
break;
}
if (e->right.sym == &symbol_yes) {
- e->type = E_NOT;
- e->left.expr = expr_alloc_symbol(e->left.sym);
- e->right.sym = NULL;
+ // A!=y -> !A
+ e = expr_alloc_one(E_NOT, e->left.expr);
break;
}
break;
case E_NOT:
switch (e->left.expr->type) {
case E_NOT:
- // !!a -> a
- tmp = e->left.expr->left.expr;
- free(e->left.expr);
- free(e);
- e = tmp;
- e = expr_transform(e);
+ // !!A -> A
+ e = e->left.expr->left.expr;
break;
case E_EQUAL:
case E_UNEQUAL:
- // !a='x' -> a!='x'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+ // !(A=B) -> A!=B
+ e = expr_alloc_comp(e->left.expr->type == E_EQUAL ? E_UNEQUAL : E_EQUAL,
+ e->left.expr->left.sym,
+ e->left.expr->right.sym);
break;
case E_LEQ:
case E_GEQ:
- // !a<='x' -> a>'x'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = e->type == E_LEQ ? E_GTH : E_LTH;
+ // !(A<=B) -> A>B
+ e = expr_alloc_comp(e->left.expr->type == E_LEQ ? E_GTH : E_LTH,
+ e->left.expr->left.sym,
+ e->left.expr->right.sym);
break;
case E_LTH:
case E_GTH:
- // !a<'x' -> a>='x'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = e->type == E_LTH ? E_GEQ : E_LEQ;
+ // !(A<B) -> A>=B
+ e = expr_alloc_comp(e->left.expr->type == E_LTH ? E_GEQ : E_LEQ,
+ e->left.expr->left.sym,
+ e->left.expr->right.sym);
break;
case E_OR:
- // !(a || b) -> !a && !b
- tmp = e->left.expr;
- e->type = E_AND;
- e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
- tmp->type = E_NOT;
- tmp->right.expr = NULL;
+ // !(A || B) -> !A && !B
+ e = expr_alloc_and(expr_alloc_one(E_NOT, e->left.expr->left.expr),
+ expr_alloc_one(E_NOT, e->left.expr->right.expr));
e = expr_transform(e);
break;
case E_AND:
- // !(a && b) -> !a || !b
- tmp = e->left.expr;
- e->type = E_OR;
- e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
- tmp->type = E_NOT;
- tmp->right.expr = NULL;
+ // !(A && B) -> !A || !B
+ e = expr_alloc_or(expr_alloc_one(E_NOT, e->left.expr->left.expr),
+ expr_alloc_one(E_NOT, e->left.expr->right.expr));
e = expr_transform(e);
break;
case E_SYMBOL:
- if (e->left.expr->left.sym == &symbol_yes) {
+ if (e->left.expr->left.sym == &symbol_yes)
// !'y' -> 'n'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = E_SYMBOL;
- e->left.sym = &symbol_no;
- break;
- }
- if (e->left.expr->left.sym == &symbol_mod) {
+ e = expr_alloc_symbol(&symbol_no);
+ else if (e->left.expr->left.sym == &symbol_mod)
// !'m' -> 'm'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = E_SYMBOL;
- e->left.sym = &symbol_mod;
- break;
- }
- if (e->left.expr->left.sym == &symbol_no) {
+ e = expr_alloc_symbol(&symbol_mod);
+ else if (e->left.expr->left.sym == &symbol_no)
// !'n' -> 'y'
- tmp = e->left.expr;
- free(e);
- e = tmp;
- e->type = E_SYMBOL;
- e->left.sym = &symbol_yes;
- break;
- }
+ e = expr_alloc_symbol(&symbol_yes);
break;
default:
;
@@ -848,10 +710,10 @@ struct expr *expr_transform(struct expr *e)
return e;
}
-int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+bool expr_contains_symbol(struct expr *dep, struct symbol *sym)
{
if (!dep)
- return 0;
+ return false;
switch (dep->type) {
case E_AND:
@@ -873,7 +735,7 @@ int expr_contains_symbol(struct expr *dep, struct symbol *sym)
default:
;
}
- return 0;
+ return false;
}
bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
@@ -960,23 +822,22 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
case E_EQUAL:
if (type == E_EQUAL) {
if (sym == &symbol_yes)
- return expr_copy(e);
+ return e;
if (sym == &symbol_mod)
return expr_alloc_symbol(&symbol_no);
if (sym == &symbol_no)
- return expr_alloc_one(E_NOT, expr_copy(e));
+ return expr_alloc_one(E_NOT, e);
} else {
if (sym == &symbol_yes)
- return expr_alloc_one(E_NOT, expr_copy(e));
+ return expr_alloc_one(E_NOT, e);
if (sym == &symbol_mod)
return expr_alloc_symbol(&symbol_yes);
if (sym == &symbol_no)
- return expr_copy(e);
+ return e;
}
break;
case E_SYMBOL:
return expr_alloc_comp(type, e->left.sym, sym);
- case E_LIST:
case E_RANGE:
case E_NONE:
/* panic */;
@@ -1027,7 +888,7 @@ static enum string_value_kind expr_parse_string(const char *str,
? kind : k_string;
}
-tristate expr_calc_value(struct expr *e)
+static tristate __expr_calc_value(struct expr *e)
{
tristate val1, val2;
const char *str1, *str2;
@@ -1035,9 +896,6 @@ tristate expr_calc_value(struct expr *e)
union string_value lval = {}, rval = {};
int res;
- if (!e)
- return yes;
-
switch (e->type) {
case E_SYMBOL:
sym_calc_value(e->left.sym);
@@ -1101,6 +959,35 @@ tristate expr_calc_value(struct expr *e)
}
}
+/**
+ * expr_calc_value - return the tristate value of the given expression
+ * @e: expression
+ * return: tristate value of the expression
+ */
+tristate expr_calc_value(struct expr *e)
+{
+ if (!e)
+ return yes;
+
+ if (!e->val_is_valid) {
+ e->val = __expr_calc_value(e);
+ e->val_is_valid = true;
+ }
+
+ return e->val;
+}
+
+/**
+ * expr_invalidate_all - invalidate all cached expression values
+ */
+void expr_invalidate_all(void)
+{
+ struct expr *e;
+
+ hash_for_each(expr_hashtable, e, node)
+ e->val_is_valid = false;
+}
+
static int expr_compare_type(enum expr_type t1, enum expr_type t2)
{
if (t1 == t2)
@@ -1112,29 +999,27 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
case E_GTH:
if (t2 == E_EQUAL || t2 == E_UNEQUAL)
return 1;
+ /* fallthrough */
case E_EQUAL:
case E_UNEQUAL:
if (t2 == E_NOT)
return 1;
+ /* fallthrough */
case E_NOT:
if (t2 == E_AND)
return 1;
+ /* fallthrough */
case E_AND:
if (t2 == E_OR)
return 1;
- case E_OR:
- if (t2 == E_LIST)
- return 1;
- case E_LIST:
- if (t2 == 0)
- return 1;
+ /* fallthrough */
default:
- return -1;
+ break;
}
return 0;
}
-void expr_print(struct expr *e,
+void expr_print(const struct expr *e,
void (*fn)(void *, struct symbol *, const char *),
void *data, int prevtoken)
{
@@ -1200,13 +1085,6 @@ void expr_print(struct expr *e,
fn(data, NULL, " && ");
expr_print(e->right.expr, fn, data, E_AND);
break;
- case E_LIST:
- fn(data, e->right.sym, e->right.sym->name);
- if (e->left.expr) {
- fn(data, NULL, " ^ ");
- expr_print(e->left.expr, fn, data, E_LIST);
- }
- break;
case E_RANGE:
fn(data, NULL, "[");
fn(data, e->left.sym, e->left.sym->name);
@@ -1266,7 +1144,7 @@ static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *s
str_printf(gs, " [=%s]", sym_str);
}
-void expr_gstr_print(struct expr *e, struct gstr *gs)
+void expr_gstr_print(const struct expr *e, struct gstr *gs)
{
expr_print(e, expr_print_gstr_helper, gs, E_NONE);
}
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 4a9a23b1b7e1..21578dcd4292 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -12,17 +12,11 @@ extern "C" {
#include <assert.h>
#include <stdio.h>
-#include "list.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
-struct file {
- struct file *next;
- struct file *parent;
- const char *name;
- int lineno;
-};
+#include <list_types.h>
typedef enum tristate {
no, mod, yes
@@ -31,16 +25,30 @@ typedef enum tristate {
enum expr_type {
E_NONE, E_OR, E_AND, E_NOT,
E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ,
- E_LIST, E_SYMBOL, E_RANGE
+ E_SYMBOL, E_RANGE
};
union expr_data {
- struct expr *expr;
- struct symbol *sym;
+ struct expr * const expr;
+ struct symbol * const sym;
+ void *_initdata;
};
+/**
+ * struct expr - expression
+ *
+ * @node: link node for the hash table
+ * @type: expressoin type
+ * @val: calculated tristate value
+ * @val_is_valid: indicate whether the value is valid
+ * @left: left node
+ * @right: right node
+ */
struct expr {
+ struct hlist_node node;
enum expr_type type;
+ tristate val;
+ bool val_is_valid;
union expr_data left, right;
};
@@ -48,9 +56,6 @@ struct expr {
#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
#define EXPR_NOT(dep) (2-(dep))
-#define expr_list_for_each_sym(l, e, s) \
- for (e = (l); e && (s = e->right.sym); e = e->left.expr)
-
struct expr_value {
struct expr *expr;
tristate tri;
@@ -77,12 +82,13 @@ enum {
/*
* Represents a configuration symbol.
*
- * Choices are represented as a special kind of symbol and have the
- * SYMBOL_CHOICE bit set in 'flags'.
+ * Choices are represented as a special kind of symbol with null name.
+ *
+ * @choice_link: linked to menu::choice_members
*/
struct symbol {
- /* The next symbol in the same bucket in the symbol hash table */
- struct symbol *next;
+ /* link node for the hash table */
+ struct hlist_node node;
/* The name of the symbol, e.g. "FOO" for 'config FOO' */
char *name;
@@ -113,6 +119,11 @@ struct symbol {
*/
tristate visible;
+ /* config entries associated with this symbol */
+ struct list_head menus;
+
+ struct list_head choice_link;
+
/* SYMBOL_* flags */
int flags;
@@ -131,18 +142,11 @@ struct symbol {
struct expr_value implied;
};
-#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next)
-
#define SYMBOL_CONST 0x0001 /* symbol is const */
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
-#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
-#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
-#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
-#define SYMBOL_CHANGED 0x0400 /* ? */
#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */
-#define SYMBOL_NO_WRITE 0x1000 /* Symbol for internal use only; it will not be written */
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
#define SYMBOL_WARNED 0x8000 /* warning has been issued */
@@ -153,11 +157,7 @@ struct symbol {
#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
-/* choice values need to be set before calculating this symbol value */
-#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
-
#define SYMBOL_MAXLENGTH 256
-#define SYMBOL_HASHSIZE 9973
/* A property represent the config options that can be associated
* with a config "symbol".
@@ -179,11 +179,9 @@ enum prop_type {
P_COMMENT, /* text associated with a comment */
P_MENU, /* prompt associated with a menu or menuconfig symbol */
P_DEFAULT, /* default y */
- P_CHOICE, /* choice value */
P_SELECT, /* select BAR */
P_IMPLY, /* imply BAR */
P_RANGE, /* range 7..100 (for a symbol) */
- P_SYMBOL, /* where a symbol is defined */
};
struct property {
@@ -193,9 +191,9 @@ struct property {
struct expr_value visible;
struct expr *expr; /* the optional conditional part of the property */
struct menu *menu; /* the menu the property are associated with
- * valid for: P_SELECT, P_RANGE, P_CHOICE,
+ * valid for: P_SELECT, P_RANGE,
* P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
- struct file *file; /* what file was this property defined */
+ const char *filename; /* what file was this property defined */
int lineno; /* what lineno was this property defined */
};
@@ -203,7 +201,6 @@ struct property {
for (st = sym->prop; st; st = st->next) \
if (st->type == (tok))
#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
-#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
#define for_all_prompts(sym, st) \
for (st = sym->prop; st; st = st->next) \
if (st->text)
@@ -213,6 +210,8 @@ struct property {
* for all front ends). Each symbol, menu, etc. defined in the Kconfig files
* gets a node. A symbol defined in multiple locations gets one node at each
* location.
+ *
+ * @choice_members: list of choice members with priority.
*/
struct menu {
/* The next menu node at the same level */
@@ -230,6 +229,10 @@ struct menu {
*/
struct symbol *sym;
+ struct list_head link; /* link to symbol::menus */
+
+ struct list_head choice_members;
+
/*
* The prompt associated with the node. This holds the prompt for a
* symbol as well as the text for a menu or comment, along with the
@@ -256,7 +259,7 @@ struct menu {
char *help;
/* The location where the menu node appears in the Kconfig files */
- struct file *file;
+ const char *filename;
int lineno;
/* For use by front ends that need to store auxiliary data */
@@ -277,10 +280,6 @@ struct jump_key {
struct menu *target;
};
-extern struct file *file_list;
-extern struct file *current_file;
-struct file *lookup_file(const char *name);
-
extern struct symbol symbol_yes, symbol_no, symbol_mod;
extern struct symbol *modules_sym;
extern int cdebug;
@@ -290,34 +289,26 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
-struct expr *expr_copy(const struct expr *org);
-void expr_free(struct expr *e);
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
-int expr_eq(struct expr *e1, struct expr *e2);
+bool expr_eq(struct expr *e1, struct expr *e2);
tristate expr_calc_value(struct expr *e);
-struct expr *expr_trans_bool(struct expr *e);
struct expr *expr_eliminate_dups(struct expr *e);
struct expr *expr_transform(struct expr *e);
-int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_contains_symbol(struct expr *dep, struct symbol *sym);
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
void expr_fprint(struct expr *e, FILE *out);
struct gstr; /* forward */
-void expr_gstr_print(struct expr *e, struct gstr *gs);
+void expr_gstr_print(const struct expr *e, struct gstr *gs);
void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
tristate pr_type, const char *title);
-static inline int expr_is_yes(struct expr *e)
+static inline bool expr_is_yes(const struct expr *e)
{
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
}
-static inline int expr_is_no(struct expr *e)
-{
- return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/scripts/kconfig/gconf-cfg.sh b/scripts/kconfig/gconf-cfg.sh
index 040d8f338820..fc954c0538fa 100755
--- a/scripts/kconfig/gconf-cfg.sh
+++ b/scripts/kconfig/gconf-cfg.sh
@@ -1,6 +1,8 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+set -eu
+
cflags=$1
libs=$2
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index 9709aca3a30f..c0f46f189060 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -18,8 +18,6 @@
#include <unistd.h>
#include <time.h>
-//#define DEBUG
-
enum {
SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
};
@@ -67,42 +65,6 @@ static void display_list(void);
static void display_tree(struct menu *menu);
static void display_tree_part(void);
static void update_tree(struct menu *src, GtkTreeIter * dst);
-static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
-static gchar **fill_row(struct menu *menu);
-static void conf_changed(void);
-
-/* Helping/Debugging Functions */
-#ifdef DEBUG
-static const char *dbg_sym_flags(int val)
-{
- static char buf[256];
-
- bzero(buf, 256);
-
- if (val & SYMBOL_CONST)
- strcat(buf, "const/");
- if (val & SYMBOL_CHECK)
- strcat(buf, "check/");
- if (val & SYMBOL_CHOICE)
- strcat(buf, "choice/");
- if (val & SYMBOL_CHOICEVAL)
- strcat(buf, "choiceval/");
- if (val & SYMBOL_VALID)
- strcat(buf, "valid/");
- if (val & SYMBOL_OPTIONAL)
- strcat(buf, "optional/");
- if (val & SYMBOL_WRITE)
- strcat(buf, "write/");
- if (val & SYMBOL_CHANGED)
- strcat(buf, "changed/");
- if (val & SYMBOL_NO_WRITE)
- strcat(buf, "no_write/");
-
- buf[strlen(buf) - 1] = '\0';
-
- return buf;
-}
-#endif
static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
GtkStyle *style, gchar *btn_name, gchar **xpm)
@@ -122,6 +84,12 @@ static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
gtk_tool_button_set_icon_widget(button, image);
}
+static void conf_changed(bool dirty)
+{
+ gtk_widget_set_sensitive(save_btn, dirty);
+ gtk_widget_set_sensitive(save_menu_item, dirty);
+}
+
/* Main Window Initialization */
static void init_main_window(const gchar *glade_file)
{
@@ -493,7 +461,7 @@ load_filename(GtkFileSelection * file_selector, gpointer user_data)
if (conf_read(fn))
text_insert_msg("Error", "Unable to load configuration !");
else
- display_tree(&rootmenu);
+ display_tree_part();
}
void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
@@ -1082,15 +1050,13 @@ static gchar **fill_row(struct menu *menu)
row[COL_NAME] = g_strdup(sym->name);
sym_calc_value(sym);
- sym->flags &= ~SYMBOL_CHANGED;
+ menu->flags &= ~MENU_CHANGED;
if (sym_is_choice(sym)) { // parse childs for getting final value
struct menu *child;
- struct symbol *def_sym = sym_get_choice_value(sym);
+ struct symbol *def_sym = sym_calc_choice(menu);
struct menu *def_menu = NULL;
- row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
-
for (child = menu->list; child; child = child->next) {
if (menu_is_visible(child)
&& child->sym == def_sym)
@@ -1100,18 +1066,16 @@ static gchar **fill_row(struct menu *menu)
if (def_menu)
row[COL_VALUE] =
g_strdup(menu_get_prompt(def_menu));
+
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+ return row;
}
- if (sym->flags & SYMBOL_CHOICEVAL)
+ if (sym_is_choice_value(sym))
row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
stype = sym_get_type(sym);
switch (stype) {
case S_BOOLEAN:
- if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
- row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
- if (sym_is_choice(sym))
- break;
- /* fall through */
case S_TRISTATE:
val = sym_get_tristate_value(sym);
switch (val) {
@@ -1268,12 +1232,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
else
menu2 = NULL; // force adding of a first child
-#ifdef DEBUG
- printf("%*c%s | %s\n", indent, ' ',
- menu1 ? menu_get_prompt(menu1) : "nil",
- menu2 ? menu_get_prompt(menu2) : "nil");
-#endif
-
if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
(opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
(opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
@@ -1314,7 +1272,7 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
else
goto reparse; // next child
}
- } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+ } else if (sym && (child1->flags & MENU_CHANGED)) {
set_node(child2, menu1, fill_row(menu1));
}
@@ -1330,7 +1288,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
/* Display the whole tree (single/split/full view) */
static void display_tree(struct menu *menu)
{
- struct symbol *sym;
struct property *prop;
struct menu *child;
enum prop_type ptype;
@@ -1342,11 +1299,9 @@ static void display_tree(struct menu *menu)
for (child = menu->list; child; child = child->next) {
prop = child->prompt;
- sym = child->sym;
ptype = prop ? prop->type : P_UNKNOWN;
- if (sym)
- sym->flags &= ~SYMBOL_CHANGED;
+ menu->flags &= ~MENU_CHANGED;
if ((view_mode == SPLIT_VIEW)
&& !(child->flags & MENU_ROOT) && (tree == tree1))
@@ -1360,19 +1315,7 @@ static void display_tree(struct menu *menu)
(opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
(opt_mode == OPT_ALL && menu_get_prompt(child)))
place_node(child, fill_row(child));
-#ifdef DEBUG
- printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
- printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
- printf("%s", prop_get_type_name(ptype));
- printf(" | ");
- if (sym) {
- printf("%s", sym_type_name(sym->type));
- printf(" | ");
- printf("%s", dbg_sym_flags(sym->flags));
- printf("\n");
- } else
- printf("\n");
-#endif
+
if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
&& (tree == tree2))
continue;
@@ -1405,6 +1348,8 @@ static void display_tree_part(void)
display_tree(current);
else if (view_mode == SPLIT_VIEW)
display_tree(browsed);
+ else if (view_mode == FULL_VIEW)
+ display_tree(&rootmenu);
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
}
@@ -1478,7 +1423,6 @@ int main(int ac, char *av[])
conf_parse(name);
fixup_rootmenu(&rootmenu);
- conf_read(NULL);
/* Load the interface and connect signals */
init_main_window(glade_file);
@@ -1486,6 +1430,8 @@ int main(int ac, char *av[])
init_left_tree();
init_right_tree();
+ conf_read(NULL);
+
switch (view_mode) {
case SINGLE_VIEW:
display_tree_part();
@@ -1502,10 +1448,3 @@ int main(int ac, char *av[])
return 0;
}
-
-static void conf_changed(void)
-{
- bool changed = conf_get_changed();
- gtk_widget_set_sensitive(save_btn, changed);
- gtk_widget_set_sensitive(save_menu_item, changed);
-}
diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h
index 2f7298c21b64..d0ffce2dfbba 100644
--- a/scripts/kconfig/internal.h
+++ b/scripts/kconfig/internal.h
@@ -2,8 +2,26 @@
#ifndef INTERNAL_H
#define INTERNAL_H
+#include <hashtable.h>
+
+#define SYMBOL_HASHSIZE (1U << 14)
+
+extern HASHTABLE_DECLARE(sym_hashtable, SYMBOL_HASHSIZE);
+
+#define for_all_symbols(sym) \
+ hash_for_each(sym_hashtable, sym, node)
+
+#define EXPR_HASHSIZE (1U << 14)
+
+extern HASHTABLE_DECLARE(expr_hashtable, EXPR_HASHSIZE);
+
+void expr_invalidate_all(void);
+
struct menu;
extern struct menu *current_menu, *current_entry;
+extern const char *cur_filename;
+extern int cur_lineno;
+
#endif /* INTERNAL_H */
diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l
index cc386e443683..9c2cdfc33c6f 100644
--- a/scripts/kconfig/lexer.l
+++ b/scripts/kconfig/lexer.l
@@ -13,17 +13,24 @@
#include <stdlib.h>
#include <string.h>
+#include <xalloc.h>
#include "lkc.h"
+#include "preprocess.h"
+
#include "parser.tab.h"
#define YY_DECL static int yylex1(void)
#define START_STRSIZE 16
-static struct {
- struct file *file;
- int lineno;
-} current_pos;
+/* The Kconfig file currently being parsed. */
+const char *cur_filename;
+
+/*
+ * The line number of the current statement. This does not match yylineno.
+ * yylineno is used by the lexer, while cur_lineno is used by the parser.
+ */
+int cur_lineno;
static int prev_prev_token = T_EOL;
static int prev_token = T_EOL;
@@ -33,6 +40,9 @@ static int text_size, text_asize;
struct buffer {
struct buffer *parent;
YY_BUFFER_STATE state;
+ int yylineno;
+ const char *filename;
+ int source_lineno;
};
static struct buffer *current_buf;
@@ -77,7 +87,7 @@ static void warn_ignored_character(char chr)
{
fprintf(stderr,
"%s:%d:warning: ignoring unsupported character '%c'\n",
- current_file->name, yylineno, chr);
+ cur_filename, yylineno, chr);
}
%}
@@ -111,7 +121,6 @@ n [A-Za-z0-9_-]
"menuconfig" return T_MENUCONFIG;
"modules" return T_MODULES;
"on" return T_ON;
-"optional" return T_OPTIONAL;
"prompt" return T_PROMPT;
"range" return T_RANGE;
"select" return T_SELECT;
@@ -180,7 +189,7 @@ n [A-Za-z0-9_-]
\n {
fprintf(stderr,
"%s:%d:warning: multi-line strings not supported\n",
- zconf_curname(), zconf_lineno());
+ cur_filename, cur_lineno);
unput('\n');
BEGIN(INITIAL);
yylval.string = text;
@@ -246,9 +255,9 @@ n [A-Za-z0-9_-]
if (prev_token != T_EOL && prev_token != T_HELPTEXT)
fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
- current_file->name, yylineno);
+ cur_filename, yylineno);
- if (current_file) {
+ if (current_buf) {
zconf_endfile();
return T_EOL;
}
@@ -267,19 +276,17 @@ repeat:
token = yylex1();
if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
- if (token == T_EOL) {
+ if (token == T_EOL)
/* Do not pass unneeded T_EOL to the parser. */
goto repeat;
- } else {
+ else
/*
- * For the parser, update file/lineno at the first token
+ * For the parser, update lineno at the first token
* of each statement. Generally, \n is a statement
* terminator in Kconfig, but it is not always true
* because \n could be escaped by a backslash.
*/
- current_pos.file = current_file;
- current_pos.lineno = yylineno;
- }
+ cur_lineno = yylineno;
}
if (prev_prev_token == T_EOL && prev_token == T_WORD &&
@@ -302,8 +309,11 @@ static char *expand_token(const char *in, size_t n)
new_string();
append_string(in, n);
- /* get the whole line because we do not know the end of token. */
- while ((c = input()) != EOF) {
+ /*
+ * get the whole line because we do not know the end of token.
+ * input() returns 0 (not EOF!) when it reachs the end of file.
+ */
+ while ((c = input()) != 0) {
if (c == '\n') {
unput(c);
break;
@@ -391,78 +401,60 @@ void zconf_initscan(const char *name)
exit(1);
}
- current_buf = xmalloc(sizeof(*current_buf));
- memset(current_buf, 0, sizeof(*current_buf));
-
- current_file = file_lookup(name);
+ cur_filename = file_lookup(name);
yylineno = 1;
}
void zconf_nextfile(const char *name)
{
- struct file *iter;
- struct file *file = file_lookup(name);
struct buffer *buf = xmalloc(sizeof(*buf));
- memset(buf, 0, sizeof(*buf));
+ bool recur_include = false;
- current_buf->state = YY_CURRENT_BUFFER;
- yyin = zconf_fopen(file->name);
+ buf->state = YY_CURRENT_BUFFER;
+ buf->yylineno = yylineno;
+ buf->filename = cur_filename;
+ buf->source_lineno = cur_lineno;
+ buf->parent = current_buf;
+ current_buf = buf;
+ yyin = zconf_fopen(name);
if (!yyin) {
fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
- zconf_curname(), zconf_lineno(), file->name);
+ cur_filename, cur_lineno, name);
exit(1);
}
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
- buf->parent = current_buf;
- current_buf = buf;
- current_file->lineno = yylineno;
- file->parent = current_file;
-
- for (iter = current_file; iter; iter = iter->parent) {
- if (!strcmp(iter->name, file->name)) {
- fprintf(stderr,
- "Recursive inclusion detected.\n"
- "Inclusion path:\n"
- " current file : %s\n", file->name);
- iter = file;
- do {
- iter = iter->parent;
- fprintf(stderr, " included from: %s:%d\n",
- iter->name, iter->lineno - 1);
- } while (strcmp(iter->name, file->name));
- exit(1);
- }
+ for (buf = current_buf; buf; buf = buf->parent) {
+ if (!strcmp(buf->filename, name))
+ recur_include = true;
}
- yylineno = 1;
- current_file = file;
-}
-
-static void zconf_endfile(void)
-{
- struct buffer *parent;
-
- current_file = current_file->parent;
- if (current_file)
- yylineno = current_file->lineno;
+ if (recur_include) {
+ fprintf(stderr,
+ "Recursive inclusion detected.\n"
+ "Inclusion path:\n"
+ " current file : %s\n", name);
- parent = current_buf->parent;
- if (parent) {
- fclose(yyin);
- yy_delete_buffer(YY_CURRENT_BUFFER);
- yy_switch_to_buffer(parent->state);
+ for (buf = current_buf; buf; buf = buf->parent)
+ fprintf(stderr, " included from: %s:%d\n",
+ buf->filename, buf->source_lineno);
+ exit(1);
}
- free(current_buf);
- current_buf = parent;
-}
-int zconf_lineno(void)
-{
- return current_pos.lineno;
+ yylineno = 1;
+ cur_filename = file_lookup(name);
}
-const char *zconf_curname(void)
+static void zconf_endfile(void)
{
- return current_pos.file ? current_pos.file->name : "<none>";
+ struct buffer *tmp;
+
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(current_buf->state);
+ yylineno = current_buf->yylineno;
+ cur_filename = current_buf->filename;
+ tmp = current_buf;
+ current_buf = current_buf->parent;
+ free(tmp);
}
diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h
deleted file mode 100644
index 45cb237ab7ef..000000000000
--- a/scripts/kconfig/list.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef LIST_H
-#define LIST_H
-
-/*
- * Copied from include/linux/...
- */
-
-#undef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-
-struct list_head {
- struct list_head *next, *prev;
-};
-
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-/**
- * list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_head within the struct.
- */
-#define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-/**
- * list_for_each_entry - iterate over list of given type
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_head within the struct.
- */
-#define list_for_each_entry(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_head within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(const struct list_head *head)
-{
- return head->next == head;
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *_new,
- struct list_head *prev,
- struct list_head *next)
-{
- next->prev = _new;
- _new->next = next;
- _new->prev = prev;
- prev->next = _new;
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *_new, struct list_head *head)
-{
- __list_add(_new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head *prev, struct list_head *next)
-{
- next->prev = prev;
- prev->next = next;
-}
-
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty() on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- entry->next = (struct list_head*)LIST_POISON1;
- entry->prev = (struct list_head*)LIST_POISON2;
-}
-#endif
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 5cdc8f5e6446..b8ebc3094a23 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -36,12 +36,10 @@ void zconf_starthelp(void);
FILE *zconf_fopen(const char *name);
void zconf_initscan(const char *name);
void zconf_nextfile(const char *name);
-int zconf_lineno(void);
-const char *zconf_curname(void);
/* confdata.c */
+extern struct gstr autoconf_cmd;
const char *conf_get_configname(void);
-void set_all_choice_values(struct symbol *csym);
/* confdata.c and expr.c */
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
@@ -53,12 +51,7 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
}
/* util.c */
-struct file *file_lookup(const char *name);
-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);
+const char *file_lookup(const char *name);
/* lexer.l */
int yylex(void);
@@ -76,28 +69,34 @@ struct gstr str_new(void);
void str_free(struct gstr *gs);
void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...);
-char *str_get(struct gstr *gs);
+char *str_get(const struct gstr *gs);
/* menu.c */
+struct menu *menu_next(struct menu *menu, struct menu *root);
+#define menu_for_each_sub_entry(menu, root) \
+ for (menu = menu_next(root, root); menu; menu = menu_next(menu, root))
+#define menu_for_each_entry(menu) \
+ menu_for_each_sub_entry(menu, &rootmenu)
void _menu_init(void);
-void menu_warn(struct menu *menu, const char *fmt, ...);
+void menu_warn(const struct menu *menu, const char *fmt, ...);
struct menu *menu_add_menu(void);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym);
void menu_add_dep(struct expr *dep);
void menu_add_visibility(struct expr *dep);
-struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, const char *prompt,
+ struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
-void menu_finalize(struct menu *parent);
+void menu_finalize(void);
void menu_set_type(int type);
extern struct menu rootmenu;
bool menu_is_empty(struct menu *menu);
bool menu_is_visible(struct menu *menu);
-bool menu_has_prompt(struct menu *menu);
-const char *menu_get_prompt(struct menu *menu);
+bool menu_has_prompt(const struct menu *menu);
+const char *menu_get_prompt(const struct menu *menu);
struct menu *menu_get_parent_menu(struct menu *menu);
int get_jump_key_char(void);
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
@@ -105,39 +104,27 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help);
/* symbol.c */
void sym_clear_all_valid(void);
-struct symbol *sym_choice_default(struct symbol *sym);
+struct symbol *sym_choice_default(struct menu *choice);
+struct symbol *sym_calc_choice(struct menu *choice);
struct property *sym_get_range_prop(struct symbol *sym);
const char *sym_get_string_default(struct symbol *sym);
struct symbol *sym_check_deps(struct symbol *sym);
-struct symbol *prop_get_symbol(struct property *prop);
+struct symbol *prop_get_symbol(const struct property *prop);
-static inline tristate sym_get_tristate_value(struct symbol *sym)
+static inline tristate sym_get_tristate_value(const struct symbol *sym)
{
return sym->curr.tri;
}
-
-static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+static inline bool sym_is_choice(const struct symbol *sym)
{
- return (struct symbol *)sym->curr.val;
+ /* A choice is a symbol with no name */
+ return sym->name == NULL;
}
-static inline bool sym_is_choice(struct symbol *sym)
-{
- return sym->flags & SYMBOL_CHOICE ? true : false;
-}
-
-static inline bool sym_is_choice_value(struct symbol *sym)
-{
- return sym->flags & SYMBOL_CHOICEVAL ? true : false;
-}
-
-static inline bool sym_is_optional(struct symbol *sym)
-{
- return sym->flags & SYMBOL_OPTIONAL ? true : false;
-}
+bool sym_is_choice_value(const struct symbol *sym);
-static inline bool sym_has_value(struct symbol *sym)
+static inline bool sym_has_value(const struct symbol *sym)
{
return sym->flags & SYMBOL_DEF_USER ? true : false;
}
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index a4ae5e9eadad..8914b4e8f2a8 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -13,13 +13,11 @@ int conf_write(const char *name);
int conf_write_autoconf(int overwrite);
void conf_set_changed(bool val);
bool conf_get_changed(void);
-void conf_set_changed_callback(void (*fn)(void));
+void conf_set_changed_callback(void (*fn)(bool));
void conf_set_message_callback(void (*fn)(const char *s));
bool conf_errors(void);
/* symbol.c */
-extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
-
struct symbol * sym_lookup(const char *name, int flags);
struct symbol * sym_find(const char *name);
void print_symbol_for_listconfig(struct symbol *sym);
@@ -27,33 +25,24 @@ struct symbol ** sym_re_search(const char *pattern);
const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym);
bool sym_dep_errors(void);
-enum symbol_type sym_get_type(struct symbol *sym);
-bool sym_tristate_within_range(struct symbol *sym,tristate tri);
+enum symbol_type sym_get_type(const struct symbol *sym);
+bool sym_tristate_within_range(const struct symbol *sym, tristate tri);
bool sym_set_tristate_value(struct symbol *sym,tristate tri);
+void choice_set_value(struct menu *choice, struct symbol *sym);
tristate sym_toggle_tristate_value(struct symbol *sym);
bool sym_string_valid(struct symbol *sym, const char *newval);
bool sym_string_within_range(struct symbol *sym, const char *str);
bool sym_set_string_value(struct symbol *sym, const char *newval);
-bool sym_is_changeable(struct symbol *sym);
-struct property * sym_get_choice_prop(struct symbol *sym);
+bool sym_is_changeable(const struct symbol *sym);
+struct menu *sym_get_prompt_menu(const struct symbol *sym);
+struct menu *sym_get_choice_menu(const struct symbol *sym);
const char * sym_get_string_value(struct symbol *sym);
const char * prop_get_type_name(enum prop_type type);
-/* preprocess.c */
-enum variable_flavor {
- VAR_SIMPLE,
- VAR_RECURSIVE,
- VAR_APPEND,
-};
-void env_write_dep(FILE *f, const char *auto_conf_name);
-void variable_add(const char *name, const char *value,
- enum variable_flavor flavor);
-void variable_all_del(void);
-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);
+void expr_print(const struct expr *e,
+ void (*fn)(void *, struct symbol *, const char *),
+ void *data, int prevtoken);
#endif /* LKC_PROTO_H */
diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c
index fd161cfff121..75493302fb85 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -119,7 +119,7 @@ int dialog_checklist(const char *title, const char *prompt, int height,
}
do_resize:
- if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
+ if (getmaxy(stdscr) < (height + CHECKLIST_HEIGHT_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
@@ -188,9 +188,8 @@ do_resize:
print_buttons(dialog, height, width, 0);
- wnoutrefresh(dialog);
- wnoutrefresh(list);
- doupdate();
+ wmove(list, choice, check_x + 1);
+ wrefresh(list);
while (key != KEY_ESC) {
key = wgetch(dialog);
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index a501abf9fa31..f6c2ebe6d1f9 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -91,10 +91,6 @@ struct dialog_info {
struct dialog_color button_label_active;
struct dialog_color button_label_inactive;
struct dialog_color inputbox;
- struct dialog_color inputbox_border;
- struct dialog_color searchbox;
- struct dialog_color searchbox_title;
- struct dialog_color searchbox_border;
struct dialog_color position_indicator;
struct dialog_color menubox;
struct dialog_color menubox_border;
@@ -166,17 +162,17 @@ int on_key_esc(WINDOW *win);
int on_key_resize(void);
/* minimum (re)size values */
-#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */
+#define CHECKLIST_HEIGHT_MIN 6 /* For dialog_checklist() */
#define CHECKLIST_WIDTH_MIN 6
-#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */
+#define INPUTBOX_HEIGHT_MIN 2 /* For dialog_inputbox() */
#define INPUTBOX_WIDTH_MIN 2
-#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */
+#define MENUBOX_HEIGHT_MIN 15 /* For dialog_menu() */
#define MENUBOX_WIDTH_MIN 65
-#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */
+#define TEXTBOX_HEIGHT_MIN 8 /* For dialog_textbox() */
#define TEXTBOX_WIDTH_MIN 8
-#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */
+#define YESNO_HEIGHT_MIN 4 /* For dialog_yesno() */
#define YESNO_WIDTH_MIN 4
-#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */
+#define WINDOW_HEIGHT_MIN 19 /* For init_dialog() */
#define WINDOW_WIDTH_MIN 80
int init_dialog(const char *backtitle);
diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c
index 1dcfb288ee63..3c6e24b20f5b 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -43,7 +43,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
strcpy(instr, init);
do_resize:
- if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
+ if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGHT_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c
index 0e333284e947..6e6244df0c56 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -172,7 +172,7 @@ int dialog_menu(const char *title, const char *prompt,
do_resize:
height = getmaxy(stdscr);
width = getmaxx(stdscr);
- if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
+ if (height < MENUBOX_HEIGHT_MIN || width < MENUBOX_WIDTH_MIN)
return -ERRDISPLAYTOOSMALL;
height -= 4;
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
index 058ed0e5bbd5..0abaf635978f 100644
--- a/scripts/kconfig/lxdialog/textbox.c
+++ b/scripts/kconfig/lxdialog/textbox.c
@@ -175,7 +175,7 @@ int dialog_textbox(const char *title, const char *tbuf, int initial_height,
do_resize:
getmaxyx(stdscr, height, width);
- if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
+ if (height < TEXTBOX_HEIGHT_MIN || width < TEXTBOX_WIDTH_MIN)
return -ERRDISPLAYTOOSMALL;
if (initial_height != 0)
height = initial_height;
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index 3f78fb265136..964139c87fcb 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -17,26 +17,13 @@ struct dialog_info dlg;
static void set_mono_theme(void)
{
- dlg.screen.atr = A_NORMAL;
- dlg.shadow.atr = A_NORMAL;
- dlg.dialog.atr = A_NORMAL;
dlg.title.atr = A_BOLD;
- dlg.border.atr = A_NORMAL;
dlg.button_active.atr = A_REVERSE;
dlg.button_inactive.atr = A_DIM;
dlg.button_key_active.atr = A_REVERSE;
dlg.button_key_inactive.atr = A_BOLD;
dlg.button_label_active.atr = A_REVERSE;
- dlg.button_label_inactive.atr = A_NORMAL;
- dlg.inputbox.atr = A_NORMAL;
- dlg.inputbox_border.atr = A_NORMAL;
- dlg.searchbox.atr = A_NORMAL;
- dlg.searchbox_title.atr = A_BOLD;
- dlg.searchbox_border.atr = A_NORMAL;
dlg.position_indicator.atr = A_BOLD;
- dlg.menubox.atr = A_NORMAL;
- dlg.menubox_border.atr = A_NORMAL;
- dlg.item.atr = A_NORMAL;
dlg.item_selected.atr = A_REVERSE;
dlg.tag.atr = A_BOLD;
dlg.tag_selected.atr = A_REVERSE;
@@ -69,10 +56,6 @@ static void set_classic_theme(void)
DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
- DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
- DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
- DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
- DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
@@ -101,14 +84,9 @@ static void set_blackbg_theme(void)
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
- DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
+ DLG_COLOR(button_label_inactive, COLOR_WHITE, COLOR_BLACK, false);
DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
- DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
-
- DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
- DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
- DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
@@ -136,7 +114,6 @@ static void set_bluetitle_theme(void)
DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
- DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
@@ -189,10 +166,6 @@ static void init_dialog_colors(void)
init_one_color(&dlg.button_label_active);
init_one_color(&dlg.button_label_inactive);
init_one_color(&dlg.inputbox);
- init_one_color(&dlg.inputbox_border);
- init_one_color(&dlg.searchbox);
- init_one_color(&dlg.searchbox_title);
- init_one_color(&dlg.searchbox_border);
init_one_color(&dlg.position_indicator);
init_one_color(&dlg.menubox);
init_one_color(&dlg.menubox_border);
@@ -309,7 +282,7 @@ int init_dialog(const char *backtitle)
getyx(stdscr, saved_y, saved_x);
getmaxyx(stdscr, height, width);
- if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
+ if (height < WINDOW_HEIGHT_MIN || width < WINDOW_WIDTH_MIN) {
endwin();
return -ERRDISPLAYTOOSMALL;
}
diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c
index bcaac9b7bab2..b57d25e1549f 100644
--- a/scripts/kconfig/lxdialog/yesno.c
+++ b/scripts/kconfig/lxdialog/yesno.c
@@ -32,7 +32,7 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
WINDOW *dialog;
do_resize:
- if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
+ if (getmaxy(stdscr) < (height + YESNO_HEIGHT_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
diff --git a/scripts/kconfig/mconf-cfg.sh b/scripts/kconfig/mconf-cfg.sh
index 1e61f50a5905..1bc304dc2f7d 100755
--- a/scripts/kconfig/mconf-cfg.sh
+++ b/scripts/kconfig/mconf-cfg.sh
@@ -1,6 +1,8 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+set -eu
+
cflags=$1
libs=$2
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 5df32148a869..84ea9215c0a7 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -19,6 +19,8 @@
#include <signal.h>
#include <unistd.h>
+#include <list.h>
+#include <xalloc.h>
#include "lkc.h"
#include "lxdialog/dialog.h"
#include "mnconf-common.h"
@@ -513,7 +515,7 @@ static void build_conf(struct menu *menu)
type = sym_get_type(sym);
if (sym_is_choice(sym)) {
- struct symbol *def_sym = sym_get_choice_value(sym);
+ struct symbol *def_sym = sym_calc_choice(menu);
struct menu *def_menu = NULL;
child_count++;
@@ -522,42 +524,14 @@ static void build_conf(struct menu *menu)
def_menu = child;
}
- val = sym_get_tristate_value(sym);
- if (sym_is_changeable(sym)) {
- switch (type) {
- case S_BOOLEAN:
- item_make("[%c]", val == no ? ' ' : '*');
- break;
- case S_TRISTATE:
- switch (val) {
- case yes: ch = '*'; break;
- case mod: ch = 'M'; break;
- default: ch = ' '; break;
- }
- item_make("<%c>", ch);
- break;
- }
- item_set_tag('t');
- item_set_data(menu);
- } else {
- item_make(" ");
- item_set_tag(def_menu ? 't' : ':');
- item_set_data(menu);
- }
+ item_make(" ");
+ item_set_tag(def_menu ? 't' : ':');
+ item_set_data(menu);
item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
- if (val == yes) {
- if (def_menu) {
- item_add_str(" (%s)", menu_get_prompt(def_menu));
- item_add_str(" --->");
- if (def_menu->list) {
- indent += 2;
- build_conf(def_menu);
- indent -= 2;
- }
- }
- return;
- }
+ if (def_menu)
+ item_add_str(" (%s) --->", menu_get_prompt(def_menu));
+ return;
} else {
if (menu == current_menu) {
item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
@@ -567,49 +541,43 @@ static void build_conf(struct menu *menu)
}
child_count++;
val = sym_get_tristate_value(sym);
- if (sym_is_choice_value(sym) && val == yes) {
- item_make(" ");
- item_set_tag(':');
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changeable(sym))
+ item_make("[%c]", val == no ? ' ' : '*');
+ else
+ item_make("-%c-", val == no ? ' ' : '*');
+ item_set_tag('t');
item_set_data(menu);
- } else {
- switch (type) {
- case S_BOOLEAN:
- if (sym_is_changeable(sym))
- item_make("[%c]", val == no ? ' ' : '*');
- else
- item_make("-%c-", val == no ? ' ' : '*');
- item_set_tag('t');
- item_set_data(menu);
- break;
- case S_TRISTATE:
- switch (val) {
- case yes: ch = '*'; break;
- case mod: ch = 'M'; break;
- default: ch = ' '; break;
- }
- if (sym_is_changeable(sym)) {
- if (sym->rev_dep.tri == mod)
- item_make("{%c}", ch);
- else
- item_make("<%c>", ch);
- } else
- item_make("-%c-", ch);
- item_set_tag('t');
- item_set_data(menu);
- break;
- default:
- tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
- item_make("(%s)", sym_get_string_value(sym));
- tmp = indent - tmp + 4;
- if (tmp < 0)
- tmp = 0;
- item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
- (sym_has_value(sym) || !sym_is_changeable(sym)) ?
- "" : " (NEW)");
- item_set_tag('s');
- item_set_data(menu);
- goto conf_childs;
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
}
+ if (sym_is_changeable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make("{%c}", ch);
+ else
+ item_make("<%c>", ch);
+ } else
+ item_make("-%c-", ch);
+ item_set_tag('t');
+ item_set_data(menu);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+ item_make("(%s)", sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) || !sym_is_changeable(sym)) ?
+ "" : " (NEW)");
+ item_set_tag('s');
+ item_set_data(menu);
+ goto conf_childs;
}
item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
(sym_has_value(sym) || !sym_is_changeable(sym)) ?
@@ -633,7 +601,7 @@ static void conf_choice(struct menu *menu)
struct menu *child;
struct symbol *active;
- active = sym_get_choice_value(menu->sym);
+ active = sym_calc_choice(menu);
while (1) {
int res;
int selected;
@@ -652,15 +620,15 @@ static void conf_choice(struct menu *menu)
item_set_data(child);
if (child->sym == active)
item_set_selected(1);
- if (child->sym == sym_get_choice_value(menu->sym))
+ if (child->sym == sym_calc_choice(menu))
item_set_tag('X');
}
dialog_clear();
res = dialog_checklist(prompt ? prompt : "Main Menu",
radiolist_instructions,
- MENUBOX_HEIGTH_MIN,
+ MENUBOX_HEIGHT_MIN,
MENUBOX_WIDTH_MIN,
- CHECKLIST_HEIGTH_MIN);
+ CHECKLIST_HEIGHT_MIN);
selected = item_activate_selected();
switch (res) {
case 0:
@@ -669,7 +637,7 @@ static void conf_choice(struct menu *menu)
if (!child->sym)
break;
- sym_set_tristate_value(child->sym, yes);
+ choice_set_value(menu, child->sym);
}
return;
case 1:
@@ -833,7 +801,7 @@ static void conf(struct menu *menu, struct menu *active_menu)
conf(submenu, NULL);
break;
case 't':
- if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+ if (sym_is_choice(sym))
conf_choice(submenu);
else if (submenu->prompt->type == P_MENU)
conf(submenu, NULL);
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 2cce8b651f61..6587ac86d0d5 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -8,6 +8,8 @@
#include <stdlib.h>
#include <string.h>
+#include <list.h>
+#include <xalloc.h>
#include "lkc.h"
#include "internal.h"
@@ -16,24 +18,42 @@ static const char nohelp_text[] = "There is no help available for this option.";
struct menu rootmenu;
static struct menu **last_entry_ptr;
-struct file *file_list;
-struct file *current_file;
+/**
+ * menu_next - return the next menu entry with depth-first traversal
+ * @menu: pointer to the current menu
+ * @root: root of the sub-tree to traverse. If NULL is given, the traveral
+ * continues until it reaches the end of the entire menu tree.
+ * return: the menu to visit next, or NULL when it reaches the end.
+ */
+struct menu *menu_next(struct menu *menu, struct menu *root)
+{
+ if (menu->list)
+ return menu->list;
+
+ while (menu != root && !menu->next)
+ menu = menu->parent;
-void menu_warn(struct menu *menu, const char *fmt, ...)
+ if (menu == root)
+ return NULL;
+
+ return menu->next;
+}
+
+void menu_warn(const struct menu *menu, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+ fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
}
-static void prop_warn(struct property *prop, const char *fmt, ...)
+static void prop_warn(const struct property *prop, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+ fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
@@ -53,14 +73,14 @@ void menu_add_entry(struct symbol *sym)
memset(menu, 0, sizeof(*menu));
menu->sym = sym;
menu->parent = current_menu;
- menu->file = current_file;
- menu->lineno = zconf_lineno();
+ menu->filename = cur_filename;
+ menu->lineno = cur_lineno;
*last_entry_ptr = menu;
last_entry_ptr = &menu->next;
current_entry = menu;
if (sym)
- menu_add_symbol(P_SYMBOL, sym, NULL);
+ list_add_tail(&menu->link, &sym->menus);
}
struct menu *menu_add_menu(void)
@@ -87,12 +107,13 @@ static struct expr *rewrite_m(struct expr *e)
switch (e->type) {
case E_NOT:
- e->left.expr = rewrite_m(e->left.expr);
+ e = expr_alloc_one(E_NOT, rewrite_m(e->left.expr));
break;
case E_OR:
case E_AND:
- e->left.expr = rewrite_m(e->left.expr);
- e->right.expr = rewrite_m(e->right.expr);
+ e = expr_alloc_two(e->type,
+ rewrite_m(e->left.expr),
+ rewrite_m(e->right.expr));
break;
case E_SYMBOL:
/* change 'm' into 'm' && MODULES */
@@ -134,8 +155,8 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
prop = xmalloc(sizeof(*prop));
memset(prop, 0, sizeof(*prop));
prop->type = type;
- prop->file = current_file;
- prop->lineno = zconf_lineno();
+ prop->filename = cur_filename;
+ prop->lineno = cur_lineno;
prop->menu = current_entry;
prop->expr = expr;
prop->visible.expr = dep;
@@ -154,7 +175,7 @@ static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
return prop;
}
-struct property *menu_add_prompt(enum prop_type type, char *prompt,
+struct property *menu_add_prompt(enum prop_type type, const char *prompt,
struct expr *dep)
{
struct property *prop = menu_add_prop(type, NULL, dep);
@@ -172,21 +193,11 @@ struct property *menu_add_prompt(enum prop_type type, char *prompt,
struct menu *menu = current_entry;
while ((menu = menu->parent) != NULL) {
- struct expr *dup_expr;
if (!menu->visibility)
continue;
- /*
- * Do not add a reference to the menu's visibility
- * expression but use a copy of it. Otherwise the
- * expression reduction functions will modify
- * expressions that have multiple references which
- * can cause unwanted side effects.
- */
- dup_expr = expr_copy(menu->visibility);
-
prop->visible.expr = expr_alloc_and(prop->visible.expr,
- dup_expr);
+ menu->visibility);
}
}
@@ -242,11 +253,9 @@ static void sym_check_prop(struct symbol *sym)
sym->name);
}
if (sym_is_choice(sym)) {
- struct property *choice_prop =
- sym_get_choice_prop(sym2);
+ struct menu *choice = sym_get_choice_menu(sym2);
- if (!choice_prop ||
- prop_get_symbol(choice_prop) != sym)
+ if (!choice || choice->sym != sym)
prop_warn(prop,
"choice default symbol '%s' is not contained in the choice",
sym2->name);
@@ -282,12 +291,12 @@ static void sym_check_prop(struct symbol *sym)
}
}
-void menu_finalize(struct menu *parent)
+static void _menu_finalize(struct menu *parent, bool inside_choice)
{
struct menu *menu, *last_menu;
struct symbol *sym;
struct property *prop;
- struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+ struct expr *basedep, *dep, *dep2;
sym = parent->sym;
if (parent->list) {
@@ -296,36 +305,6 @@ void menu_finalize(struct menu *parent)
* and propagate parent dependencies before moving on.
*/
- if (sym && sym_is_choice(sym)) {
- if (sym->type == S_UNKNOWN) {
- /* find the first choice value to find out choice type */
- current_entry = parent;
- for (menu = parent->list; menu; menu = menu->next) {
- if (menu->sym && menu->sym->type != S_UNKNOWN) {
- menu_set_type(menu->sym->type);
- break;
- }
- }
- }
- /* set the type of the remaining choice values */
- for (menu = parent->list; menu; menu = menu->next) {
- current_entry = menu;
- if (menu->sym && menu->sym->type == S_UNKNOWN)
- menu_set_type(sym->type);
- }
-
- /*
- * Use the choice itself as the parent dependency of
- * the contained items. This turns the mode of the
- * choice into an upper bound on the visibility of the
- * choice value symbols.
- */
- parentdep = expr_alloc_symbol(sym);
- } else {
- /* Menu node for 'menu', 'if' */
- parentdep = parent->dep;
- }
-
/* For each child menu node... */
for (menu = parent->list; menu; menu = menu->next) {
/*
@@ -334,7 +313,7 @@ void menu_finalize(struct menu *parent)
*/
basedep = rewrite_m(menu->dep);
basedep = expr_transform(basedep);
- basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+ basedep = expr_alloc_and(parent->dep, basedep);
basedep = expr_eliminate_dups(basedep);
menu->dep = basedep;
@@ -378,10 +357,8 @@ void menu_finalize(struct menu *parent)
*/
dep = rewrite_m(prop->visible.expr);
dep = expr_transform(dep);
- dep = expr_alloc_and(expr_copy(basedep), dep);
+ dep = expr_alloc_and(basedep, dep);
dep = expr_eliminate_dups(dep);
- if (menu->sym && menu->sym->type != S_TRISTATE)
- dep = expr_trans_bool(dep);
prop->visible.expr = dep;
/*
@@ -391,25 +368,22 @@ void menu_finalize(struct menu *parent)
if (prop->type == P_SELECT) {
struct symbol *es = prop_get_symbol(prop);
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
- expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+ expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
} else if (prop->type == P_IMPLY) {
struct symbol *es = prop_get_symbol(prop);
es->implied.expr = expr_alloc_or(es->implied.expr,
- expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+ expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
}
}
}
- if (sym && sym_is_choice(sym))
- expr_free(parentdep);
-
/*
* Recursively process children in the same fashion before
* moving on
*/
for (menu = parent->list; menu; menu = menu->next)
- menu_finalize(menu);
- } else if (sym) {
+ _menu_finalize(menu, sym && sym_is_choice(sym));
+ } else if (!inside_choice && sym) {
/*
* Automatic submenu creation. If sym is a symbol and A, B, C,
* ... are consecutive items (symbols, menus, ifs, etc.) that
@@ -458,22 +432,18 @@ void menu_finalize(struct menu *parent)
*/
dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
dep = expr_eliminate_dups(expr_transform(dep));
- dep2 = expr_copy(basedep);
+ dep2 = basedep;
expr_eliminate_eq(&dep, &dep2);
- expr_free(dep);
if (!expr_is_yes(dep2)) {
/* Not superset, quit */
- expr_free(dep2);
break;
}
/* Superset, put in submenu */
- expr_free(dep2);
next:
- menu_finalize(menu);
+ _menu_finalize(menu, false);
menu->parent = parent;
last_menu = menu;
}
- expr_free(basedep);
if (last_menu) {
parent->list = parent->next;
parent->next = last_menu->next;
@@ -483,46 +453,6 @@ void menu_finalize(struct menu *parent)
sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
}
for (menu = parent->list; menu; menu = menu->next) {
- if (sym && sym_is_choice(sym) &&
- menu->sym && !sym_is_choice_value(menu->sym)) {
- current_entry = menu;
- menu->sym->flags |= SYMBOL_CHOICEVAL;
- if (!menu->prompt)
- menu_warn(menu, "choice value must have a prompt");
- for (prop = menu->sym->prop; prop; prop = prop->next) {
- if (prop->type == P_DEFAULT)
- prop_warn(prop, "defaults for choice "
- "values not supported");
- if (prop->menu == menu)
- continue;
- if (prop->type == P_PROMPT &&
- prop->menu->parent->sym != sym)
- prop_warn(prop, "choice value used outside its choice group");
- }
- /* Non-tristate choice values of tristate choices must
- * depend on the choice being set to Y. The choice
- * values' dependencies were propagated to their
- * properties above, so the change here must be re-
- * propagated.
- */
- if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
- basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
- menu->dep = expr_alloc_and(basedep, menu->dep);
- for (prop = menu->sym->prop; prop; prop = prop->next) {
- if (prop->menu != menu)
- continue;
- prop->visible.expr = expr_alloc_and(expr_copy(basedep),
- prop->visible.expr);
- }
- }
- menu_add_symbol(P_CHOICE, sym, NULL);
- prop = sym_get_choice_prop(sym);
- for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
- ;
- *ep = expr_alloc_one(E_LIST, NULL);
- (*ep)->right.sym = menu->sym;
- }
-
/*
* This code serves two purposes:
*
@@ -567,31 +497,18 @@ void menu_finalize(struct menu *parent)
if (sym->type == S_UNKNOWN)
menu_warn(parent, "config symbol defined without type");
- if (sym_is_choice(sym) && !parent->prompt)
- menu_warn(parent, "choice must have a prompt");
-
/* Check properties connected to this symbol */
sym_check_prop(sym);
sym->flags |= SYMBOL_WARNED;
}
+}
- /*
- * For non-optional choices, add a reverse dependency (corresponding to
- * a select) of '<visibility> && m'. This prevents the user from
- * setting the choice mode to 'n' when the choice is visible.
- *
- * This would also work for non-choice symbols, but only non-optional
- * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented
- * as a type of symbol.
- */
- if (sym && !sym_is_optional(sym) && parent->prompt) {
- sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
- expr_alloc_and(parent->prompt->visible.expr,
- expr_alloc_symbol(&symbol_mod)));
- }
+void menu_finalize(void)
+{
+ _menu_finalize(&rootmenu, false);
}
-bool menu_has_prompt(struct menu *menu)
+bool menu_has_prompt(const struct menu *menu)
{
if (!menu->prompt)
return false;
@@ -641,18 +558,14 @@ bool menu_is_visible(struct menu *menu)
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
- for (child = menu->list; child; child = child->next) {
- if (menu_is_visible(child)) {
- if (sym)
- sym->flags |= SYMBOL_DEF_USER;
+ for (child = menu->list; child; child = child->next)
+ if (menu_is_visible(child))
return true;
- }
- }
return false;
}
-const char *menu_get_prompt(struct menu *menu)
+const char *menu_get_prompt(const struct menu *menu)
{
if (menu->prompt)
return menu->prompt->text;
@@ -673,13 +586,14 @@ struct menu *menu_get_parent_menu(struct menu *menu)
return menu;
}
-static void get_def_str(struct gstr *r, struct menu *menu)
+static void get_def_str(struct gstr *r, const struct menu *menu)
{
str_printf(r, "Defined at %s:%d\n",
- menu->file->name, menu->lineno);
+ menu->filename, menu->lineno);
}
-static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
+static void get_dep_str(struct gstr *r, const struct expr *expr,
+ const char *prefix)
{
if (!expr_is_yes(expr)) {
str_append(r, prefix);
@@ -777,6 +691,7 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
struct list_head *head)
{
struct property *prop;
+ struct menu *menu;
if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
@@ -793,17 +708,17 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym,
}
/* Print the definitions with prompts before the ones without */
- for_all_properties(sym, prop, P_SYMBOL) {
- if (prop->menu->prompt) {
- get_def_str(r, prop->menu);
- get_prompt_str(r, prop->menu->prompt, head);
+ list_for_each_entry(menu, &sym->menus, link) {
+ if (menu->prompt) {
+ get_def_str(r, menu);
+ get_prompt_str(r, menu->prompt, head);
}
}
- for_all_properties(sym, prop, P_SYMBOL) {
- if (!prop->menu->prompt) {
- get_def_str(r, prop->menu);
- get_dep_str(r, prop->menu->dep, " Depends on: ");
+ list_for_each_entry(menu, &sym->menus, link) {
+ if (!menu->prompt) {
+ get_def_str(r, menu);
+ get_dep_str(r, menu->dep, " Depends on: ");
}
}
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 902eb429b9db..0b7952471c18 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -167,6 +167,8 @@ for ORIG_MERGE_FILE in $MERGE_LIST ; do
sed -i "/$CFG[ =]/d" $MERGE_FILE
fi
done
+ # In case the previous file lacks a new line at the end
+ echo >> $TMP_FILE
cat $MERGE_FILE >> $TMP_FILE
done
diff --git a/scripts/kconfig/mnconf-common.c b/scripts/kconfig/mnconf-common.c
index 18cb9a6c5aaa..8e24b07121df 100644
--- a/scripts/kconfig/mnconf-common.c
+++ b/scripts/kconfig/mnconf-common.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <list.h>
#include "expr.h"
-#include "list.h"
#include "mnconf-common.h"
int jump_key_char;
diff --git a/scripts/kconfig/mnconf-common.h b/scripts/kconfig/mnconf-common.h
index ab6292cc4bf2..53bd7292e931 100644
--- a/scripts/kconfig/mnconf-common.h
+++ b/scripts/kconfig/mnconf-common.h
@@ -4,6 +4,8 @@
#include <stddef.h>
+#include <list_types.h>
+
struct search_data {
struct list_head *head;
struct menu *target;
diff --git a/scripts/kconfig/nconf-cfg.sh b/scripts/kconfig/nconf-cfg.sh
index f871a2160e36..a20290b1a37d 100755
--- a/scripts/kconfig/nconf-cfg.sh
+++ b/scripts/kconfig/nconf-cfg.sh
@@ -1,6 +1,8 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+set -eu
+
cflags=$1
libs=$2
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index 1148163cfa7e..c0b2dabf6c89 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -11,6 +11,8 @@
#include <strings.h>
#include <stdlib.h>
+#include <list.h>
+#include <xalloc.h>
#include "lkc.h"
#include "mnconf-common.h"
#include "nconf.h"
@@ -465,7 +467,7 @@ static void handle_f9(int *key, struct menu *current_item)
return;
}
-/* return != 0 to indicate the key was handles */
+/* return != 0 to indicate the key was handled */
static int process_special_keys(int *key, struct menu *menu)
{
int i;
@@ -814,7 +816,7 @@ static void build_conf(struct menu *menu)
type = sym_get_type(sym);
if (sym_is_choice(sym)) {
- struct symbol *def_sym = sym_get_choice_value(sym);
+ struct symbol *def_sym = sym_calc_choice(menu);
struct menu *def_menu = NULL;
child_count++;
@@ -824,46 +826,13 @@ static void build_conf(struct menu *menu)
}
val = sym_get_tristate_value(sym);
- if (sym_is_changeable(sym)) {
- switch (type) {
- case S_BOOLEAN:
- item_make(menu, 't', "[%c]",
- val == no ? ' ' : '*');
- break;
- case S_TRISTATE:
- switch (val) {
- case yes:
- ch = '*';
- break;
- case mod:
- ch = 'M';
- break;
- default:
- ch = ' ';
- break;
- }
- item_make(menu, 't', "<%c>", ch);
- break;
- }
- } else {
- item_make(menu, def_menu ? 't' : ':', " ");
- }
+ item_make(menu, def_menu ? 't' : ':', " ");
item_add_str("%*c%s", indent + 1,
' ', menu_get_prompt(menu));
- if (val == yes) {
- if (def_menu) {
- item_add_str(" (%s)",
- menu_get_prompt(def_menu));
- item_add_str(" --->");
- if (def_menu->list) {
- indent += 2;
- build_conf(def_menu);
- indent -= 2;
- }
- }
- return;
- }
+ if (def_menu)
+ item_add_str(" (%s) --->", menu_get_prompt(def_menu));
+ return;
} else {
if (menu == current_menu) {
item_make(menu, ':',
@@ -873,54 +842,46 @@ static void build_conf(struct menu *menu)
}
child_count++;
val = sym_get_tristate_value(sym);
- if (sym_is_choice_value(sym) && val == yes) {
- item_make(menu, ':', " ");
- } else {
- switch (type) {
- case S_BOOLEAN:
- if (sym_is_changeable(sym))
- item_make(menu, 't', "[%c]",
- val == no ? ' ' : '*');
- else
- item_make(menu, 't', "-%c-",
- val == no ? ' ' : '*');
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changeable(sym))
+ item_make(menu, 't', "[%c]",
+ val == no ? ' ' : '*');
+ else
+ item_make(menu, 't', "-%c-",
+ val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
break;
- case S_TRISTATE:
- switch (val) {
- case yes:
- ch = '*';
- break;
- case mod:
- ch = 'M';
- break;
- default:
- ch = ' ';
- break;
- }
- if (sym_is_changeable(sym)) {
- if (sym->rev_dep.tri == mod)
- item_make(menu,
- 't', "{%c}", ch);
- else
- item_make(menu,
- 't', "<%c>", ch);
- } else
- item_make(menu, 't', "-%c-", ch);
+ case mod:
+ ch = 'M';
break;
default:
- tmp = 2 + strlen(sym_get_string_value(sym));
- item_make(menu, 's', " (%s)",
- sym_get_string_value(sym));
- tmp = indent - tmp + 4;
- if (tmp < 0)
- tmp = 0;
- item_add_str("%*c%s%s", tmp, ' ',
- menu_get_prompt(menu),
- (sym_has_value(sym) ||
- !sym_is_changeable(sym)) ? "" :
- " (NEW)");
- goto conf_childs;
+ ch = ' ';
+ break;
}
+ if (sym_is_changeable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make(menu, 't', "{%c}", ch);
+ else
+ item_make(menu, 't', "<%c>", ch);
+ } else
+ item_make(menu, 't', "-%c-", ch);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym));
+ item_make(menu, 's', " (%s)",
+ sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) ||
+ !sym_is_changeable(sym)) ? "" : " (NEW)");
+ goto conf_childs;
}
item_add_str("%*c%s%s", indent + 1, ' ',
menu_get_prompt(menu),
@@ -1214,8 +1175,7 @@ static void selected_conf(struct menu *menu, struct menu *active_menu)
conf(submenu);
break;
case 't':
- if (sym_is_choice(sym) &&
- sym_get_tristate_value(sym) == yes)
+ if (sym_is_choice(sym))
conf_choice(submenu);
else if (submenu->prompt &&
submenu->prompt->type == P_MENU)
@@ -1280,7 +1240,7 @@ static void conf_choice(struct menu *menu)
.pattern = "",
};
- active = sym_get_choice_value(menu->sym);
+ active = sym_calc_choice(menu);
/* this is mostly duplicated from the conf() function. */
while (!global_exit) {
reset_menu();
@@ -1289,7 +1249,7 @@ static void conf_choice(struct menu *menu)
if (!show_all_items && !menu_is_visible(child))
continue;
- if (child->sym == sym_get_choice_value(menu->sym))
+ if (child->sym == sym_calc_choice(menu))
item_make(child, ':', "<X> %s",
menu_get_prompt(child));
else if (child->sym)
@@ -1372,7 +1332,7 @@ static void conf_choice(struct menu *menu)
case ' ':
case 10:
case KEY_RIGHT:
- sym_set_tristate_value(child->sym, yes);
+ choice_set_value(menu, child->sym);
return;
case 'h':
case '?':
diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c
index 25a7263ef3c8..4bfdf8ac2a9a 100644
--- a/scripts/kconfig/nconf.gui.c
+++ b/scripts/kconfig/nconf.gui.c
@@ -4,6 +4,7 @@
*
* Derived from menuconfig.
*/
+#include <xalloc.h>
#include "nconf.h"
#include "lkc.h"
@@ -276,6 +277,15 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
case KEY_RIGHT:
menu_driver(menu, REQ_RIGHT_ITEM);
break;
+ case 9: /* TAB */
+ if (btn_num > 1) {
+ /* cycle through buttons */
+ if (item_index(current_item(menu)) == btn_num - 1)
+ menu_driver(menu, REQ_FIRST_ITEM);
+ else
+ menu_driver(menu, REQ_NEXT_ITEM);
+ }
+ break;
case 10: /* ENTER */
case 27: /* ESCAPE */
case ' ':
diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y
index 2af7ce4e1531..68372d3ff325 100644
--- a/scripts/kconfig/parser.y
+++ b/scripts/kconfig/parser.y
@@ -11,8 +11,10 @@
#include <string.h>
#include <stdbool.h>
+#include <xalloc.h>
#include "lkc.h"
#include "internal.h"
+#include "preprocess.h"
#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
@@ -22,14 +24,11 @@
int cdebug = PRINTD;
static void yyerror(const char *err);
-static void zconfprint(const char *err, ...);
static void zconf_error(const char *err, ...);
static bool zconf_endtoken(const char *tokenname,
const char *expected_tokenname);
-struct symbol *symbol_hash[SYMBOL_HASHSIZE];
-
-struct menu *current_menu, *current_entry;
+struct menu *current_menu, *current_entry, *current_choice;
%}
@@ -70,7 +69,6 @@ struct menu *current_menu, *current_entry;
%token T_MODULES
%token T_ON
%token T_OPEN_PAREN
-%token T_OPTIONAL
%token T_PLUS_EQUAL
%token T_PROMPT
%token T_RANGE
@@ -90,17 +88,17 @@ struct menu *current_menu, *current_entry;
%type <symbol> nonconst_symbol
%type <symbol> symbol
-%type <type> type logic_type default
+%type <type> type default
%type <expr> expr
%type <expr> if_expr
%type <string> end
%type <menu> if_entry menu_entry choice_entry
-%type <string> word_opt assign_val
+%type <string> assign_val
%type <flavor> assign_op
%destructor {
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
- $$->file->name, $$->lineno);
+ $$->filename, $$->lineno);
if (current_menu == $$)
menu_end_menu();
} if_entry menu_entry choice_entry
@@ -141,21 +139,42 @@ stmt_list_in_choice:
config_entry_start: T_CONFIG nonconst_symbol T_EOL
{
- $2->flags |= SYMBOL_OPTIONAL;
menu_add_entry($2);
- printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2->name);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);
};
config_stmt: config_entry_start config_option_list
{
- printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+ if (current_choice) {
+ if (!current_entry->prompt) {
+ fprintf(stderr, "%s:%d: error: choice member must have a prompt\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ if (current_entry->sym->type != S_BOOLEAN) {
+ fprintf(stderr, "%s:%d: error: choice member must be bool\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
+ /*
+ * If the same symbol appears twice in a choice block, the list
+ * node would be added twice, leading to a broken linked list.
+ * list_empty() ensures that this symbol has not yet added.
+ */
+ if (list_empty(&current_entry->sym->choice_link))
+ list_add_tail(&current_entry->sym->choice_link,
+ &current_choice->choice_members);
+ }
+
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
};
menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
{
- $2->flags |= SYMBOL_OPTIONAL;
menu_add_entry($2);
- printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2->name);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);
};
menuconfig_stmt: menuconfig_entry_start config_option_list
@@ -163,8 +182,8 @@ menuconfig_stmt: menuconfig_entry_start config_option_list
if (current_entry->prompt)
current_entry->prompt->type = P_MENU;
else
- zconfprint("warning: menuconfig statement without prompt");
- printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+ zconf_error("menuconfig statement without prompt");
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
};
config_option_list:
@@ -177,15 +196,13 @@ config_option_list:
config_option: type prompt_stmt_opt T_EOL
{
menu_set_type($1);
- printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
- zconf_curname(), zconf_lineno(),
- $1);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
};
config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
{
menu_add_prompt(P_PROMPT, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
};
config_option: default expr if_expr T_EOL
@@ -193,27 +210,26 @@ config_option: default expr if_expr T_EOL
menu_add_expr(P_DEFAULT, $2, $3);
if ($1 != S_UNKNOWN)
menu_set_type($1);
- printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
- zconf_curname(), zconf_lineno(),
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno,
$1);
};
config_option: T_SELECT nonconst_symbol if_expr T_EOL
{
menu_add_symbol(P_SELECT, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno);
};
config_option: T_IMPLY nonconst_symbol if_expr T_EOL
{
menu_add_symbol(P_IMPLY, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno);
};
config_option: T_RANGE symbol symbol if_expr T_EOL
{
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
- printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno);
};
config_option: T_MODULES T_EOL
@@ -226,26 +242,37 @@ config_option: T_MODULES T_EOL
/* choice entry */
-choice: T_CHOICE word_opt T_EOL
+choice: T_CHOICE T_EOL
{
- struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
- sym->flags |= SYMBOL_NO_WRITE;
+ struct symbol *sym = sym_lookup(NULL, 0);
+
menu_add_entry(sym);
- menu_add_expr(P_CHOICE, NULL, NULL);
- free($2);
- printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+ menu_set_type(S_BOOLEAN);
+ INIT_LIST_HEAD(&current_entry->choice_members);
+
+ printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
};
choice_entry: choice choice_option_list
{
+ if (!current_entry->prompt) {
+ fprintf(stderr, "%s:%d: error: choice must have a prompt\n",
+ current_entry->filename, current_entry->lineno);
+ yynerrs++;
+ }
+
$$ = menu_add_menu();
+
+ current_choice = current_entry;
};
choice_end: end
{
+ current_choice = NULL;
+
if (zconf_endtoken($1, "choice")) {
menu_end_menu();
- printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno);
}
};
@@ -262,39 +289,22 @@ choice_option_list:
choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
{
menu_add_prompt(P_PROMPT, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-};
-
-choice_option: logic_type prompt_stmt_opt T_EOL
-{
- menu_set_type($1);
- printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
- zconf_curname(), zconf_lineno(), $1);
-};
-
-choice_option: T_OPTIONAL T_EOL
-{
- current_entry->sym->flags |= SYMBOL_OPTIONAL;
- printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
};
choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
{
menu_add_symbol(P_DEFAULT, $2, $3);
- printd(DEBUG_PARSE, "%s:%d:default\n",
- zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno);
};
type:
- logic_type
+ T_BOOL { $$ = S_BOOLEAN; }
+ | T_TRISTATE { $$ = S_TRISTATE; }
| T_INT { $$ = S_INT; }
| T_HEX { $$ = S_HEX; }
| T_STRING { $$ = S_STRING; }
-logic_type:
- T_BOOL { $$ = S_BOOLEAN; }
- | T_TRISTATE { $$ = S_TRISTATE; }
-
default:
T_DEFAULT { $$ = S_UNKNOWN; }
| T_DEF_BOOL { $$ = S_BOOLEAN; }
@@ -304,7 +314,7 @@ default:
if_entry: T_IF expr T_EOL
{
- printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
menu_add_entry(NULL);
menu_add_dep($2);
$$ = menu_add_menu();
@@ -314,7 +324,7 @@ if_end: end
{
if (zconf_endtoken($1, "if")) {
menu_end_menu();
- printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno);
}
};
@@ -330,7 +340,7 @@ menu: T_MENU T_WORD_QUOTE T_EOL
{
menu_add_entry(NULL);
menu_add_prompt(P_MENU, $2, NULL);
- printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);
};
menu_entry: menu menu_option_list
@@ -342,7 +352,7 @@ menu_end: end
{
if (zconf_endtoken($1, "menu")) {
menu_end_menu();
- printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno);
}
};
@@ -357,7 +367,7 @@ menu_option_list:
source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
{
- printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2);
zconf_nextfile($2);
free($2);
};
@@ -368,7 +378,7 @@ comment: T_COMMENT T_WORD_QUOTE T_EOL
{
menu_add_entry(NULL);
menu_add_prompt(P_COMMENT, $2, NULL);
- printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);
};
comment_stmt: comment comment_option_list
@@ -383,7 +393,7 @@ comment_option_list:
help_start: T_HELP T_EOL
{
- printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno);
zconf_starthelp();
};
@@ -391,14 +401,14 @@ help: help_start T_HELPTEXT
{
if (current_entry->help) {
free(current_entry->help);
- zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used",
- current_entry->sym->name ?: "<choice>");
+ zconf_error("'%s' defined with more than one help text",
+ current_entry->sym->name ?: "<choice>");
}
/* Is the help text empty or all whitespace? */
if ($2[strspn($2, " \f\n\r\t\v")] == '\0')
- zconfprint("warning: '%s' defined with blank help text",
- current_entry->sym->name ?: "<choice>");
+ zconf_error("'%s' defined with blank help text",
+ current_entry->sym->name ?: "<choice>");
current_entry->help = $2;
};
@@ -408,7 +418,7 @@ help: help_start T_HELPTEXT
depends: T_DEPENDS T_ON expr T_EOL
{
menu_add_dep($3);
- printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
};
/* visibility option */
@@ -455,9 +465,6 @@ symbol: nonconst_symbol
| T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
;
-word_opt: /* empty */ { $$ = NULL; }
- | T_WORD
-
/* assignment statement */
assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); }
@@ -475,10 +482,45 @@ assign_val:
%%
+/**
+ * choice_check_sanity - check sanity of a choice member
+ *
+ * @menu: menu of the choice member
+ *
+ * Return: -1 if an error is found, 0 otherwise.
+ */
+static int choice_check_sanity(const struct menu *menu)
+{
+ struct property *prop;
+ int ret = 0;
+
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_DEFAULT) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "defaults for choice values not supported\n");
+ ret = -1;
+ }
+
+ if (prop->menu != menu && prop->type == P_PROMPT &&
+ prop->menu->parent != menu->parent) {
+ fprintf(stderr, "%s:%d: error: %s",
+ prop->filename, prop->lineno,
+ "choice value has a prompt outside its choice group\n");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
void conf_parse(const char *name)
{
- struct symbol *sym;
- int i;
+ struct menu *menu;
+
+ autoconf_cmd = str_new();
+
+ str_printf(&autoconf_cmd, "\ndeps_config := \\\n");
zconf_initscan(name);
@@ -488,24 +530,41 @@ void conf_parse(const char *name)
yydebug = 1;
yyparse();
+ str_printf(&autoconf_cmd,
+ "\n"
+ "$(autoconfig): $(deps_config)\n"
+ "$(deps_config): ;\n");
+
+ env_write_dep(&autoconf_cmd);
+
/* Variables are expanded in the parse phase. We can free them here. */
variable_all_del();
if (yynerrs)
exit(1);
if (!modules_sym)
- modules_sym = sym_find( "n" );
+ modules_sym = &symbol_no;
if (!menu_has_prompt(&rootmenu)) {
current_entry = &rootmenu;
menu_add_prompt(P_MENU, "Main menu", NULL);
}
- menu_finalize(&rootmenu);
- for_all_symbols(i, sym) {
- if (sym_check_deps(sym))
+ menu_finalize();
+
+ menu_for_each_entry(menu) {
+ struct menu *child;
+
+ if (menu->sym && sym_check_deps(menu->sym))
yynerrs++;
+
+ if (menu->sym && sym_is_choice(menu->sym)) {
+ menu_for_each_sub_entry(child, menu)
+ if (child->sym && choice_check_sanity(child))
+ yynerrs++;
+ }
}
+
if (yynerrs)
exit(1);
conf_set_changed(true);
@@ -520,11 +579,11 @@ static bool zconf_endtoken(const char *tokenname,
yynerrs++;
return false;
}
- if (current_menu->file != current_file) {
+ if (strcmp(current_menu->filename, cur_filename)) {
zconf_error("'%s' in different file than '%s'",
tokenname, expected_tokenname);
fprintf(stderr, "%s:%d: location of the '%s'\n",
- current_menu->file->name, current_menu->lineno,
+ current_menu->filename, current_menu->lineno,
expected_tokenname);
yynerrs++;
return false;
@@ -532,23 +591,12 @@ static bool zconf_endtoken(const char *tokenname,
return true;
}
-static void zconfprint(const char *err, ...)
-{
- va_list ap;
-
- fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
- va_start(ap, err);
- vfprintf(stderr, err, ap);
- va_end(ap);
- fprintf(stderr, "\n");
-}
-
static void zconf_error(const char *err, ...)
{
va_list ap;
yynerrs++;
- fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
va_start(ap, err);
vfprintf(stderr, err, ap);
va_end(ap);
@@ -557,7 +605,7 @@ static void zconf_error(const char *err, ...)
static void yyerror(const char *err)
{
- fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+ fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err);
}
static void print_quoted_string(FILE *out, const char *str)
@@ -577,7 +625,7 @@ static void print_quoted_string(FILE *out, const char *str)
putc('"', out);
}
-static void print_symbol(FILE *out, struct menu *menu)
+static void print_symbol(FILE *out, const struct menu *menu)
{
struct symbol *sym = menu->sym;
struct property *prop;
@@ -628,9 +676,6 @@ static void print_symbol(FILE *out, struct menu *menu)
}
fputc('\n', out);
break;
- case P_CHOICE:
- fputs(" #choice value\n", out);
- break;
case P_SELECT:
fputs( " select ", out);
expr_fprint(prop->expr, out);
@@ -651,10 +696,6 @@ static void print_symbol(FILE *out, struct menu *menu)
print_quoted_string(out, prop->text);
fputc('\n', out);
break;
- case P_SYMBOL:
- fputs( " symbol ", out);
- fprintf(out, "%s\n", prop->menu->sym->name);
- break;
default:
fprintf(out, " unknown prop %d!\n", prop->type);
break;
diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c
index d1f5bcff4b62..783abcaa5cc5 100644
--- a/scripts/kconfig/preprocess.c
+++ b/scripts/kconfig/preprocess.c
@@ -9,10 +9,12 @@
#include <stdlib.h>
#include <string.h>
-#include "list.h"
+#include <array_size.h>
+#include <list.h>
+#include <xalloc.h>
+#include "internal.h"
#include "lkc.h"
-
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#include "preprocess.h"
static char *expand_string_with_args(const char *in, int argc, char *argv[]);
static char *expand_string(const char *in);
@@ -21,7 +23,7 @@ static void __attribute__((noreturn)) pperror(const char *format, ...)
{
va_list ap;
- fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
+ fprintf(stderr, "%s:%d: ", cur_filename, yylineno);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
@@ -87,14 +89,17 @@ static char *env_expand(const char *name)
return xstrdup(value);
}
-void env_write_dep(FILE *f, const char *autoconfig_name)
+void env_write_dep(struct gstr *s)
{
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");
+ str_printf(s,
+ "\n"
+ "ifneq \"$(%s)\" \"%s\"\n"
+ "$(autoconfig): FORCE\n"
+ "endif\n",
+ e->name, e->value);
env_del(e);
}
}
@@ -119,7 +124,7 @@ static char *do_error_if(int argc, char *argv[])
static char *do_filename(int argc, char *argv[])
{
- return xstrdup(current_file->name);
+ return xstrdup(cur_filename);
}
static char *do_info(int argc, char *argv[])
@@ -181,8 +186,7 @@ static char *do_shell(int argc, char *argv[])
static char *do_warning_if(int argc, char *argv[])
{
if (!strcmp(argv[0], "y"))
- fprintf(stderr, "%s:%d: %s\n",
- current_file->name, yylineno, argv[1]);
+ fprintf(stderr, "%s:%d: %s\n", cur_filename, yylineno, argv[1]);
return xstrdup("");
}
diff --git a/scripts/kconfig/preprocess.h b/scripts/kconfig/preprocess.h
new file mode 100644
index 000000000000..a7e4a550638c
--- /dev/null
+++ b/scripts/kconfig/preprocess.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef PREPROCESS_H
+#define PREPROCESS_H
+
+enum variable_flavor {
+ VAR_SIMPLE,
+ VAR_RECURSIVE,
+ VAR_APPEND,
+};
+
+struct gstr;
+void env_write_dep(struct gstr *gs);
+void variable_add(const char *name, const char *value,
+ enum variable_flavor flavor);
+void variable_all_del(void);
+char *expand_dollar(const char **str);
+char *expand_one_token(const char **str);
+
+#endif /* PREPROCESS_H */
diff --git a/scripts/kconfig/qconf-cfg.sh b/scripts/kconfig/qconf-cfg.sh
index 0e113b0f2455..bb2df66363a8 100755
--- a/scripts/kconfig/qconf-cfg.sh
+++ b/scripts/kconfig/qconf-cfg.sh
@@ -1,6 +1,8 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+set -eu
+
cflags=$1
libs=$2
bin=$3
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 620a3527c767..eaa465b0ccf9 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -22,6 +22,7 @@
#include <stdlib.h>
+#include <xalloc.h>
#include "lkc.h"
#include "qconf.h"
@@ -109,7 +110,7 @@ void ConfigItem::updateMenu(void)
if (prop) switch (prop->type) {
case P_MENU:
- if (list->mode == singleMode || list->mode == symbolMode) {
+ if (list->mode == singleMode) {
/* a menuconfig entry is displayed differently
* depending whether it's at the view root or a child.
*/
@@ -147,7 +148,7 @@ void ConfigItem::updateMenu(void)
expr = sym_get_tristate_value(sym);
switch (expr) {
case yes:
- if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+ if (sym_is_choice_value(sym))
setIcon(promptColIdx, choiceYesIcon);
else
setIcon(promptColIdx, symbolYesIcon);
@@ -158,7 +159,7 @@ void ConfigItem::updateMenu(void)
ch = 'M';
break;
default:
- if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+ if (sym_is_choice_value(sym))
setIcon(promptColIdx, choiceNoIcon);
else
setIcon(promptColIdx, symbolNoIcon);
@@ -174,17 +175,16 @@ void ConfigItem::updateMenu(void)
setText(dataColIdx, sym_get_string_value(sym));
break;
}
- if (!sym_has_value(sym) && visible)
+ if (!sym_has_value(sym))
prompt += " (NEW)";
set_prompt:
setText(promptColIdx, prompt);
}
-void ConfigItem::testUpdateMenu(bool v)
+void ConfigItem::testUpdateMenu(void)
{
ConfigItem* i;
- visible = v;
if (!menu)
return;
@@ -306,7 +306,6 @@ ConfigList::ConfigList(QWidget *parent, const char *name)
{
setObjectName(name);
setSortingEnabled(false);
- setRootIsDecorated(true);
setVerticalScrollMode(ScrollPerPixel);
setHorizontalScrollMode(ScrollPerPixel);
@@ -429,27 +428,26 @@ void ConfigList::updateList()
item = (ConfigItem*)(*it);
if (!item->menu)
continue;
- item->testUpdateMenu(menu_is_visible(item->menu));
+ item->testUpdateMenu();
++it;
}
return;
}
- if (rootEntry != &rootmenu && (mode == singleMode ||
- (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+ if (rootEntry != &rootmenu && mode == singleMode) {
item = (ConfigItem *)topLevelItem(0);
if (!item)
- item = new ConfigItem(this, 0, true);
+ item = new ConfigItem(this, 0);
last = item;
}
if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
rootEntry->sym && rootEntry->prompt) {
item = last ? last->nextSibling() : nullptr;
if (!item)
- item = new ConfigItem(this, last, rootEntry, true);
+ item = new ConfigItem(this, last, rootEntry);
else
- item->testUpdateMenu(true);
+ item->testUpdateMenu();
updateMenuList(item, rootEntry);
update();
@@ -598,7 +596,6 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
struct menu* child;
ConfigItem* item;
ConfigItem* last;
- bool visible;
enum prop_type type;
if (!menu) {
@@ -630,14 +627,13 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
break;
}
- visible = menu_is_visible(child);
if (!menuSkip(child)) {
if (!child->sym && !child->list && !child->prompt)
continue;
if (!item || item->menu != child)
- item = new ConfigItem(parent, last, child, visible);
+ item = new ConfigItem(parent, last, child);
else
- item->testUpdateMenu(visible);
+ item->testUpdateMenu();
if (mode == fullMode || mode == menuMode || type != P_MENU)
updateMenuList(item, child);
@@ -663,7 +659,6 @@ void ConfigList::updateMenuList(struct menu *menu)
struct menu* child;
ConfigItem* item;
ConfigItem* last;
- bool visible;
enum prop_type type;
if (!menu) {
@@ -695,14 +690,13 @@ void ConfigList::updateMenuList(struct menu *menu)
break;
}
- visible = menu_is_visible(child);
if (!menuSkip(child)) {
if (!child->sym && !child->list && !child->prompt)
continue;
if (!item || item->menu != child)
- item = new ConfigItem(this, last, child, visible);
+ item = new ConfigItem(this, last, child);
else
- item->testUpdateMenu(visible);
+ item->testUpdateMenu();
if (mode == fullMode || mode == menuMode || type != P_MENU)
updateMenuList(item, child);
@@ -730,7 +724,7 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
struct menu *menu;
enum prop_type type;
- if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
+ if (ev->key() == Qt::Key_Escape && mode == singleMode) {
emit parentSelected();
ev->accept();
return;
@@ -780,13 +774,6 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
ev->accept();
}
-void ConfigList::mousePressEvent(QMouseEvent* e)
-{
- //QPoint p(contentsToViewport(e->pos()));
- //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
- Parent::mousePressEvent(e);
-}
-
void ConfigList::mouseReleaseEvent(QMouseEvent* e)
{
QPoint p = e->pos();
@@ -833,13 +820,6 @@ skip:
Parent::mouseReleaseEvent(e);
}
-void ConfigList::mouseMoveEvent(QMouseEvent* e)
-{
- //QPoint p(contentsToViewport(e->pos()));
- //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
- Parent::mouseMoveEvent(e);
-}
-
void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
{
QPoint p = e->pos();
@@ -1021,7 +1001,7 @@ void ConfigInfoView::menuInfo(void)
if (sym->name) {
stream << " (";
if (showDebug())
- stream << "<a href=\"s" << sym->name << "\">";
+ stream << "<a href=\"" << sym->name << "\">";
stream << print_filter(sym->name);
if (showDebug())
stream << "</a>";
@@ -1030,7 +1010,7 @@ void ConfigInfoView::menuInfo(void)
} else if (sym->name) {
stream << "<big><b>";
if (showDebug())
- stream << "<a href=\"s" << sym->name << "\">";
+ stream << "<a href=\"" << sym->name << "\">";
stream << print_filter(sym->name);
if (showDebug())
stream << "</a>";
@@ -1058,7 +1038,7 @@ void ConfigInfoView::menuInfo(void)
stream << "<br><br>";
}
- stream << "defined at " << _menu->file->name << ":"
+ stream << "defined at " << _menu->filename << ":"
<< _menu->lineno << "<br><br>";
}
}
@@ -1085,30 +1065,21 @@ QString ConfigInfoView::debug_info(struct symbol *sym)
switch (prop->type) {
case P_PROMPT:
case P_MENU:
- stream << "prompt: <a href=\"m" << sym->name << "\">";
+ stream << "prompt: ";
stream << print_filter(prop->text);
- stream << "</a><br>";
+ stream << "<br>";
break;
case P_DEFAULT:
case P_SELECT:
case P_RANGE:
case P_COMMENT:
case P_IMPLY:
- case P_SYMBOL:
stream << prop_get_type_name(prop->type);
stream << ": ";
expr_print(prop->expr, expr_print_help,
&stream, E_NONE);
stream << "<br>";
break;
- case P_CHOICE:
- if (sym_is_choice(sym)) {
- stream << "choice: ";
- expr_print(prop->expr, expr_print_help,
- &stream, E_NONE);
- stream << "<br>";
- }
- break;
default:
stream << "unknown property: ";
stream << prop_get_type_name(prop->type);
@@ -1130,28 +1101,19 @@ QString ConfigInfoView::print_filter(const QString &str)
{
QRegularExpression re("[<>&\"\\n]");
QString res = str;
+
+ QHash<QChar, QString> patterns;
+ patterns['<'] = "&lt;";
+ patterns['>'] = "&gt;";
+ patterns['&'] = "&amp;";
+ patterns['"'] = "&quot;";
+ patterns['\n'] = "<br>";
+
for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
- switch (res[i].toLatin1()) {
- case '<':
- res.replace(i, 1, "&lt;");
- i += 4;
- break;
- case '>':
- res.replace(i, 1, "&gt;");
- i += 4;
- break;
- case '&':
- res.replace(i, 1, "&amp;");
- i += 5;
- break;
- case '"':
- res.replace(i, 1, "&quot;");
- i += 6;
- break;
- case '\n':
- res.replace(i, 1, "<br>");
- i += 4;
- break;
+ const QString n = patterns.value(res[i], QString());
+ if (!n.isEmpty()) {
+ res.replace(i, 1, n);
+ i += n.length();
}
}
return res;
@@ -1162,7 +1124,7 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
QTextStream *stream = reinterpret_cast<QTextStream *>(data);
if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
- *stream << "<a href=\"s" << sym->name << "\">";
+ *stream << "<a href=\"" << sym->name << "\">";
*stream << print_filter(str);
*stream << "</a>";
} else {
@@ -1172,39 +1134,11 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
void ConfigInfoView::clicked(const QUrl &url)
{
- QByteArray str = url.toEncoded();
- const std::size_t count = str.size();
- char *data = new char[count + 1];
- struct symbol **result;
- struct menu *m = NULL;
-
- if (count < 1) {
- delete[] data;
- return;
- }
+ struct menu *m;
- memcpy(data, str.constData(), count);
- data[count] = '\0';
-
- /* Seek for exact match */
- data[0] = '^';
- strcat(data, "$");
- result = sym_re_search(data);
- if (!result) {
- delete[] data;
- return;
- }
-
- sym = *result;
-
- /* Seek for the menu which holds the symbol */
- for (struct property *prop = sym->prop; prop; prop = prop->next) {
- if (prop->type != P_PROMPT && prop->type != P_MENU)
- continue;
- m = prop->menu;
- break;
- }
+ sym = sym_find(url.toEncoded().constData());
+ m = sym_get_prompt_menu(sym);
if (!m) {
/* Symbol is not visible as a menu */
symbolInfo();
@@ -1212,9 +1146,6 @@ void ConfigInfoView::clicked(const QUrl &url)
} else {
emit menuSelected(m);
}
-
- free(result);
- delete[] data;
}
void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
@@ -1248,8 +1179,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
layout2->addWidget(searchButton);
layout1->addLayout(layout2);
- split = new QSplitter(this);
- split->setOrientation(Qt::Vertical);
+ split = new QSplitter(Qt::Vertical, this);
list = new ConfigList(split, "search");
list->mode = listMode;
info = new ConfigInfoView(split, "search");
@@ -1308,8 +1238,7 @@ void ConfigSearchWindow::search(void)
return;
for (p = result; *p; p++) {
for_all_prompts((*p), prop)
- lastItem = new ConfigItem(list, lastItem, prop->menu,
- menu_is_visible(prop->menu));
+ lastItem = new ConfigItem(list, lastItem, prop->menu);
}
}
@@ -1349,63 +1278,56 @@ ConfigMainWindow::ConfigMainWindow(void)
ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
QWidget *widget = new QWidget(this);
- QVBoxLayout *layout = new QVBoxLayout(widget);
setCentralWidget(widget);
- split1 = new QSplitter(widget);
- split1->setOrientation(Qt::Horizontal);
- split1->setChildrenCollapsible(false);
-
- menuList = new ConfigList(widget, "menu");
+ QVBoxLayout *layout = new QVBoxLayout(widget);
- split2 = new QSplitter(widget);
+ split2 = new QSplitter(Qt::Vertical, widget);
+ layout->addWidget(split2);
split2->setChildrenCollapsible(false);
- split2->setOrientation(Qt::Vertical);
- // create config tree
- configList = new ConfigList(widget, "config");
+ split1 = new QSplitter(Qt::Horizontal, split2);
+ split1->setChildrenCollapsible(false);
- helpText = new ConfigInfoView(widget, "help");
+ configList = new ConfigList(split1, "config");
- layout->addWidget(split2);
- split2->addWidget(split1);
- split1->addWidget(configList);
- split1->addWidget(menuList);
- split2->addWidget(helpText);
+ menuList = new ConfigList(split1, "menu");
+ helpText = new ConfigInfoView(split2, "help");
setTabOrder(configList, helpText);
+
configList->setFocus();
backAction = new QAction(QPixmap(xpm_back), "Back", this);
+ backAction->setShortcut(QKeySequence::Back);
connect(backAction, &QAction::triggered,
this, &ConfigMainWindow::goBack);
QAction *quitAction = new QAction("&Quit", this);
- quitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
+ quitAction->setShortcut(QKeySequence::Quit);
connect(quitAction, &QAction::triggered,
this, &ConfigMainWindow::close);
- QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
- loadAction->setShortcut(Qt::CTRL | Qt::Key_L);
+ QAction *loadAction = new QAction(QPixmap(xpm_load), "&Open", this);
+ loadAction->setShortcut(QKeySequence::Open);
connect(loadAction, &QAction::triggered,
this, &ConfigMainWindow::loadConfig);
saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
- saveAction->setShortcut(Qt::CTRL | Qt::Key_S);
+ saveAction->setShortcut(QKeySequence::Save);
connect(saveAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfig);
conf_set_changed_callback(conf_changed);
- // Set saveAction's initial state
- conf_changed();
- configname = xstrdup(conf_get_configname());
+ configname = conf_get_configname();
QAction *saveAsAction = new QAction("Save &As...", this);
+ saveAsAction->setShortcut(QKeySequence::SaveAs);
connect(saveAsAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfigAs);
QAction *searchAction = new QAction("&Find", this);
- searchAction->setShortcut(Qt::CTRL | Qt::Key_F);
+ searchAction->setShortcut(QKeySequence::Find);
connect(searchAction, &QAction::triggered,
this, &ConfigMainWindow::searchConfig);
singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
@@ -1515,6 +1437,11 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(helpText, &ConfigInfoView::menuSelected,
this, &ConfigMainWindow::setMenuLink);
+ connect(configApp, &QApplication::aboutToQuit,
+ this, &ConfigMainWindow::saveSettings);
+
+ conf_read(NULL);
+
QString listMode = configSettings->value("/listMode", "symbol").toString();
if (listMode == "single")
showSingleView();
@@ -1536,28 +1463,22 @@ ConfigMainWindow::ConfigMainWindow(void)
void ConfigMainWindow::loadConfig(void)
{
QString str;
- QByteArray ba;
- const char *name;
- str = QFileDialog::getOpenFileName(this, "", configname);
- if (str.isNull())
+ str = QFileDialog::getOpenFileName(this, QString(), configname);
+ if (str.isEmpty())
return;
- ba = str.toLocal8Bit();
- name = ba.data();
-
- if (conf_read(name))
+ if (conf_read(str.toLocal8Bit().constData()))
QMessageBox::information(this, "qconf", "Unable to load configuration!");
- free(configname);
- configname = xstrdup(name);
+ configname = str;
ConfigList::updateListAllForAll();
}
bool ConfigMainWindow::saveConfig(void)
{
- if (conf_write(configname)) {
+ if (conf_write(configname.toLocal8Bit().constData())) {
QMessageBox::information(this, "qconf", "Unable to save configuration!");
return false;
}
@@ -1569,23 +1490,17 @@ bool ConfigMainWindow::saveConfig(void)
void ConfigMainWindow::saveConfigAs(void)
{
QString str;
- QByteArray ba;
- const char *name;
- str = QFileDialog::getSaveFileName(this, "", configname);
- if (str.isNull())
+ str = QFileDialog::getSaveFileName(this, QString(), configname);
+ if (str.isEmpty())
return;
- ba = str.toLocal8Bit();
- name = ba.data();
-
- if (conf_write(name)) {
+ if (conf_write(str.toLocal8Bit().constData())) {
QMessageBox::information(this, "qconf", "Unable to save configuration!");
}
conf_write_autoconf(0);
- free(configname);
- configname = xstrdup(name);
+ configname = str;
}
void ConfigMainWindow::searchConfig(void)
@@ -1670,9 +1585,6 @@ void ConfigMainWindow::listFocusChanged(void)
void ConfigMainWindow::goBack(void)
{
- if (configList->rootEntry == &rootmenu)
- return;
-
configList->setParentMenu();
}
@@ -1851,10 +1763,10 @@ void ConfigMainWindow::saveSettings(void)
configSettings->writeSizes("/split2", split2->sizes());
}
-void ConfigMainWindow::conf_changed(void)
+void ConfigMainWindow::conf_changed(bool dirty)
{
if (saveAction)
- saveAction->setEnabled(conf_get_changed());
+ saveAction->setEnabled(dirty);
}
void fixup_rootmenu(struct menu *menu)
@@ -1904,7 +1816,6 @@ int main(int ac, char** av)
conf_parse(name);
fixup_rootmenu(&rootmenu);
- conf_read(NULL);
//zconfdump(stdout);
configApp = new QApplication(ac, av);
@@ -1914,8 +1825,7 @@ int main(int ac, char** av)
v = new ConfigMainWindow();
//zconfdump(stdout);
- configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
- configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+
v->show();
configApp->exec();
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index 78b0a1dfcd53..62ab3286d04f 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -55,9 +55,7 @@ public:
protected:
void keyPressEvent(QKeyEvent *e);
- void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
- void mouseMoveEvent(QMouseEvent *e);
void mouseDoubleClickEvent(QMouseEvent *e);
void focusInEvent(QFocusEvent *e);
void contextMenuEvent(QContextMenuEvent *e);
@@ -116,25 +114,25 @@ public:
class ConfigItem : public QTreeWidgetItem {
typedef class QTreeWidgetItem Parent;
public:
- ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v)
- : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
+ ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m)
+ : Parent(parent, after), nextItem(0), menu(m), goParent(false)
{
init();
}
- ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
- : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
+ ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m)
+ : Parent(parent, after), nextItem(0), menu(m), goParent(false)
{
init();
}
- ConfigItem(ConfigList *parent, ConfigItem *after, bool v)
- : Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true)
+ ConfigItem(ConfigList *parent, ConfigItem *after)
+ : Parent(parent, after), nextItem(0), menu(0), goParent(true)
{
init();
}
~ConfigItem(void);
void init(void);
void updateMenu(void);
- void testUpdateMenu(bool v);
+ void testUpdateMenu(void);
ConfigList* listView() const
{
return (ConfigList*)Parent::treeWidget();
@@ -161,7 +159,6 @@ public:
ConfigItem* nextItem;
struct menu *menu;
- bool visible;
bool goParent;
static QIcon symbolYesIcon, symbolModIcon, symbolNoIcon;
@@ -237,9 +234,9 @@ protected:
class ConfigMainWindow : public QMainWindow {
Q_OBJECT
- char *configname;
+ QString configname;
static QAction *saveAction;
- static void conf_changed(void);
+ static void conf_changed(bool);
public:
ConfigMainWindow(void);
public slots:
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index d51cd7ac15d2..8e23faab5d22 100755
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -144,6 +144,7 @@ my %selects;
my %prompts;
my %objects;
my %config2kfile;
+my %defaults;
my $var;
my $iflevel = 0;
my @ifdeps;
@@ -220,8 +221,9 @@ sub read_kconfig {
$depends{$config} = $1;
} elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
$depends{$config} .= " " . $1;
- } elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
+ } elsif ($state ne "NONE" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) {
my $dep = $3;
+ $defaults{$config} = 1;
if ($dep !~ /^\s*(y|m|n)\s*$/) {
$dep =~ s/.*\sif\s+//;
$depends{$config} .= " " . $dep;
@@ -503,7 +505,7 @@ sub parse_config_selects
# Check if something other than a module selects this config
if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
- dprint "$conf (non module) selects config, we are good\n";
+ dprint "$conf (non module) selects $config, we are good\n";
# we are good with this
return;
}
@@ -523,8 +525,16 @@ sub parse_config_selects
# If no possible config selected this, then something happened.
if (!defined($next_config)) {
- print STDERR "WARNING: $config is required, but nothing in the\n";
- print STDERR " current config selects it.\n";
+
+ # Some config options have no prompt, and nothing selects them, but
+ # they stay turned on once the final checks for the configs
+ # are done. These configs have a default option, so turn off the
+ # warnings for configs with default options.
+ if (!defined($defaults{$config})) {
+ print STDERR "WARNING: $config is required, but nothing in the\n";
+ print STDERR " current config selects it.\n";
+ }
+
return;
}
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index e9e9fb8d8674..7beb59dec5a0 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -9,23 +9,32 @@
#include <string.h>
#include <regex.h>
+#include <hash.h>
+#include <xalloc.h>
+#include "internal.h"
#include "lkc.h"
struct symbol symbol_yes = {
.name = "y",
+ .type = S_TRISTATE,
.curr = { "y", yes },
+ .menus = LIST_HEAD_INIT(symbol_yes.menus),
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
struct symbol symbol_mod = {
.name = "m",
+ .type = S_TRISTATE,
.curr = { "m", mod },
+ .menus = LIST_HEAD_INIT(symbol_mod.menus),
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
struct symbol symbol_no = {
.name = "n",
+ .type = S_TRISTATE,
.curr = { "n", no },
+ .menus = LIST_HEAD_INIT(symbol_no.menus),
.flags = SYMBOL_CONST|SYMBOL_VALID,
};
@@ -33,16 +42,12 @@ struct symbol *modules_sym;
static tristate modules_val;
static int sym_warnings;
-enum symbol_type sym_get_type(struct symbol *sym)
+enum symbol_type sym_get_type(const struct symbol *sym)
{
enum symbol_type type = sym->type;
- if (type == S_TRISTATE) {
- if (sym_is_choice_value(sym) && sym->visible == yes)
- type = S_BOOLEAN;
- else if (modules_val == no)
- type = S_BOOLEAN;
- }
+ if (type == S_TRISTATE && modules_val == no)
+ type = S_BOOLEAN;
return type;
}
@@ -65,12 +70,50 @@ const char *sym_type_name(enum symbol_type type)
return "???";
}
-struct property *sym_get_choice_prop(struct symbol *sym)
+/**
+ * sym_get_prompt_menu - get the menu entry with a prompt
+ *
+ * @sym: a symbol pointer
+ *
+ * Return: the menu entry with a prompt.
+ */
+struct menu *sym_get_prompt_menu(const struct symbol *sym)
{
- struct property *prop;
+ struct menu *m;
+
+ list_for_each_entry(m, &sym->menus, link)
+ if (m->prompt)
+ return m;
+
+ return NULL;
+}
+
+/**
+ * sym_get_choice_menu - get the parent choice menu if present
+ *
+ * @sym: a symbol pointer
+ *
+ * Return: a choice menu if this function is called against a choice member.
+ */
+struct menu *sym_get_choice_menu(const struct symbol *sym)
+{
+ struct menu *menu = NULL;
+
+ /*
+ * Choice members must have a prompt. Find a menu entry with a prompt,
+ * and assume it resides inside a choice block.
+ */
+ menu = sym_get_prompt_menu(sym);
+ if (!menu)
+ return NULL;
+
+ do {
+ menu = menu->parent;
+ } while (menu && !menu->sym);
+
+ if (menu && menu->sym && sym_is_choice(menu->sym))
+ return menu;
- for_all_choices(sym, prop)
- return prop;
return NULL;
}
@@ -148,47 +191,29 @@ static void sym_validate_range(struct symbol *sym)
static void sym_set_changed(struct symbol *sym)
{
- struct property *prop;
+ struct menu *menu;
- sym->flags |= SYMBOL_CHANGED;
- for (prop = sym->prop; prop; prop = prop->next) {
- if (prop->menu)
- prop->menu->flags |= MENU_CHANGED;
- }
+ list_for_each_entry(menu, &sym->menus, link)
+ menu->flags |= MENU_CHANGED;
}
static void sym_set_all_changed(void)
{
struct symbol *sym;
- int i;
- for_all_symbols(i, sym)
+ for_all_symbols(sym)
sym_set_changed(sym);
}
static void sym_calc_visibility(struct symbol *sym)
{
struct property *prop;
- struct symbol *choice_sym = NULL;
tristate tri;
/* any prompt visible? */
tri = no;
-
- if (sym_is_choice_value(sym))
- choice_sym = prop_get_symbol(sym_get_choice_prop(sym));
-
for_all_prompts(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
- /*
- * Tristate choice_values with visibility 'mod' are
- * not visible if the corresponding choice's value is
- * 'yes'.
- */
- if (choice_sym && sym->type == S_TRISTATE &&
- prop->visible.tri == mod && choice_sym->curr.tri == yes)
- prop->visible.tri = no;
-
tri = EXPR_OR(tri, prop->visible.tri);
}
if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
@@ -235,14 +260,14 @@ static void sym_calc_visibility(struct symbol *sym)
* Next locate the first visible choice value
* Return NULL if none was found
*/
-struct symbol *sym_choice_default(struct symbol *sym)
+struct symbol *sym_choice_default(struct menu *choice)
{
+ struct menu *menu;
struct symbol *def_sym;
struct property *prop;
- struct expr *e;
/* any of the defaults visible? */
- for_all_defaults(sym, prop) {
+ for_all_defaults(choice->sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
if (prop->visible.tri == no)
continue;
@@ -252,48 +277,99 @@ struct symbol *sym_choice_default(struct symbol *sym)
}
/* just get the first visible value */
- prop = sym_get_choice_prop(sym);
- expr_list_for_each_sym(prop->expr, e, def_sym)
- if (def_sym->visible != no)
- return def_sym;
+ menu_for_each_sub_entry(menu, choice)
+ if (menu->sym && menu->sym->visible != no)
+ return menu->sym;
/* failed to locate any defaults */
return NULL;
}
-static struct symbol *sym_calc_choice(struct symbol *sym)
+/*
+ * sym_calc_choice - calculate symbol values in a choice
+ *
+ * @choice: a menu of the choice
+ *
+ * Return: a chosen symbol
+ */
+struct symbol *sym_calc_choice(struct menu *choice)
{
- struct symbol *def_sym;
- struct property *prop;
- struct expr *e;
- int flags;
-
- /* first calculate all choice values' visibilities */
- flags = sym->flags;
- prop = sym_get_choice_prop(sym);
- expr_list_for_each_sym(prop->expr, e, def_sym) {
- sym_calc_visibility(def_sym);
- if (def_sym->visible != no)
- flags &= def_sym->flags;
+ struct symbol *res = NULL;
+ struct symbol *sym;
+ struct menu *menu;
+
+ /* Traverse the list of choice members in the priority order. */
+ list_for_each_entry(sym, &choice->choice_members, choice_link) {
+ sym_calc_visibility(sym);
+ if (sym->visible == no)
+ continue;
+
+ /* The first visible symble with the user value 'y'. */
+ if (sym_has_value(sym) && sym->def[S_DEF_USER].tri == yes) {
+ res = sym;
+ break;
+ }
}
- sym->flags &= flags | ~SYMBOL_DEF_USER;
+ /*
+ * If 'y' is not found in the user input, use the default, unless it is
+ * explicitly set to 'n'.
+ */
+ if (!res) {
+ res = sym_choice_default(choice);
+ if (res && sym_has_value(res) && res->def[S_DEF_USER].tri == no)
+ res = NULL;
+ }
- /* is the user choice visible? */
- def_sym = sym->def[S_DEF_USER].val;
- if (def_sym && def_sym->visible != no)
- return def_sym;
+ /* Still not found. Pick up the first visible, user-unspecified symbol. */
+ if (!res) {
+ menu_for_each_sub_entry(menu, choice) {
+ sym = menu->sym;
- def_sym = sym_choice_default(sym);
+ if (!sym || sym->visible == no || sym_has_value(sym))
+ continue;
- if (def_sym == NULL)
- /* no choice? reset tristate value */
- sym->curr.tri = no;
+ res = sym;
+ break;
+ }
+ }
+
+ /*
+ * Still not found. Traverse the linked list in the _reverse_ order to
+ * pick up the least prioritized 'n'.
+ */
+ if (!res) {
+ list_for_each_entry_reverse(sym, &choice->choice_members,
+ choice_link) {
+ if (sym->visible == no)
+ continue;
+
+ res = sym;
+ break;
+ }
+ }
+
+ menu_for_each_sub_entry(menu, choice) {
+ tristate val;
+
+ sym = menu->sym;
+
+ if (!sym || sym->visible == no)
+ continue;
- return def_sym;
+ val = sym == res ? yes : no;
+
+ if (sym->curr.tri != val)
+ sym_set_changed(sym);
+
+ sym->curr.tri = val;
+ sym->flags |= SYMBOL_VALID | SYMBOL_WRITE;
+ }
+
+ return res;
}
-static void sym_warn_unmet_dep(struct symbol *sym)
+static void sym_warn_unmet_dep(const struct symbol *sym)
{
struct gstr gs = str_new();
@@ -312,6 +388,7 @@ static void sym_warn_unmet_dep(struct symbol *sym)
" Selected by [m]:\n");
fputs(str_get(&gs), stderr);
+ str_free(&gs);
sym_warnings++;
}
@@ -326,7 +403,7 @@ void sym_calc_value(struct symbol *sym)
{
struct symbol_value newval, oldval;
struct property *prop;
- struct expr *e;
+ struct menu *choice_menu;
if (!sym)
return;
@@ -334,13 +411,6 @@ void sym_calc_value(struct symbol *sym)
if (sym->flags & SYMBOL_VALID)
return;
- if (sym_is_choice_value(sym) &&
- sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
- sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
- prop = sym_get_choice_prop(sym);
- sym_calc_value(prop_get_symbol(prop));
- }
-
sym->flags |= SYMBOL_VALID;
oldval = sym->curr;
@@ -379,9 +449,11 @@ void sym_calc_value(struct symbol *sym)
switch (sym_get_type(sym)) {
case S_BOOLEAN:
case S_TRISTATE:
- if (sym_is_choice_value(sym) && sym->visible == yes) {
- prop = sym_get_choice_prop(sym);
- newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+ choice_menu = sym_get_choice_menu(sym);
+
+ if (choice_menu) {
+ sym_calc_choice(choice_menu);
+ newval.tri = sym->curr.tri;
} else {
if (sym->visible != no) {
/* if the symbol is visible use the user value
@@ -440,8 +512,6 @@ void sym_calc_value(struct symbol *sym)
}
sym->curr = newval;
- if (sym_is_choice(sym) && newval.tri == yes)
- sym->curr.val = sym_calc_choice(sym);
sym_validate_range(sym);
if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
@@ -452,38 +522,22 @@ void sym_calc_value(struct symbol *sym)
}
}
- if (sym_is_choice(sym)) {
- struct symbol *choice_sym;
-
- prop = sym_get_choice_prop(sym);
- expr_list_for_each_sym(prop->expr, e, choice_sym) {
- if ((sym->flags & SYMBOL_WRITE) &&
- choice_sym->visible != no)
- choice_sym->flags |= SYMBOL_WRITE;
- if (sym->flags & SYMBOL_CHANGED)
- sym_set_changed(choice_sym);
- }
- }
-
- if (sym->flags & SYMBOL_NO_WRITE)
+ if (sym_is_choice(sym))
sym->flags &= ~SYMBOL_WRITE;
-
- if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
- set_all_choice_values(sym);
}
void sym_clear_all_valid(void)
{
struct symbol *sym;
- int i;
- for_all_symbols(i, sym)
+ for_all_symbols(sym)
sym->flags &= ~SYMBOL_VALID;
+ expr_invalidate_all();
conf_set_changed(true);
sym_calc_value(modules_sym);
}
-bool sym_tristate_within_range(struct symbol *sym, tristate val)
+bool sym_tristate_within_range(const struct symbol *sym, tristate val)
{
int type = sym_get_type(sym);
@@ -497,8 +551,6 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
return false;
if (sym->visible <= sym->rev_dep.tri)
return false;
- if (sym_is_choice_value(sym) && sym->visible == yes)
- return val == yes;
return val >= sym->rev_dep.tri && val <= sym->visible;
}
@@ -506,42 +558,75 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val)
{
tristate oldval = sym_get_tristate_value(sym);
- if (oldval != val && !sym_tristate_within_range(sym, val))
+ if (!sym_tristate_within_range(sym, val))
return false;
- if (!(sym->flags & SYMBOL_DEF_USER)) {
+ if (!(sym->flags & SYMBOL_DEF_USER) || sym->def[S_DEF_USER].tri != val) {
+ sym->def[S_DEF_USER].tri = val;
sym->flags |= SYMBOL_DEF_USER;
sym_set_changed(sym);
}
- /*
- * setting a choice value also resets the new flag of the choice
- * symbol and all other choice values.
- */
- if (sym_is_choice_value(sym) && val == yes) {
- struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
- struct property *prop;
- struct expr *e;
-
- cs->def[S_DEF_USER].val = sym;
- cs->flags |= SYMBOL_DEF_USER;
- prop = sym_get_choice_prop(cs);
- for (e = prop->expr; e; e = e->left.expr) {
- if (e->right.sym->visible != no)
- e->right.sym->flags |= SYMBOL_DEF_USER;
- }
- }
- sym->def[S_DEF_USER].tri = val;
if (oldval != val)
sym_clear_all_valid();
return true;
}
+/**
+ * choice_set_value - set the user input to a choice
+ *
+ * @choice: menu entry for the choice
+ * @sym: selected symbol
+ */
+void choice_set_value(struct menu *choice, struct symbol *sym)
+{
+ struct menu *menu;
+ bool changed = false;
+
+ menu_for_each_sub_entry(menu, choice) {
+ tristate val;
+
+ if (!menu->sym)
+ continue;
+
+ if (menu->sym->visible == no)
+ continue;
+
+ val = menu->sym == sym ? yes : no;
+
+ if (menu->sym->curr.tri != val)
+ changed = true;
+
+ menu->sym->def[S_DEF_USER].tri = val;
+ menu->sym->flags |= SYMBOL_DEF_USER;
+
+ /*
+ * Now, the user has explicitly enabled or disabled this symbol,
+ * it should be given the highest priority. We are possibly
+ * setting multiple symbols to 'n', where the first symbol is
+ * given the least prioritized 'n'. This works well when the
+ * choice block ends up with selecting 'n' symbol.
+ * (see sym_calc_choice())
+ */
+ list_move(&menu->sym->choice_link, &choice->choice_members);
+ }
+
+ if (changed)
+ sym_clear_all_valid();
+}
+
tristate sym_toggle_tristate_value(struct symbol *sym)
{
+ struct menu *choice;
tristate oldval, newval;
+ choice = sym_get_choice_menu(sym);
+ if (choice) {
+ choice_set_value(choice, sym);
+ return yes;
+ }
+
oldval = newval = sym_get_tristate_value(sym);
do {
switch (newval) {
@@ -786,8 +871,7 @@ const char *sym_get_string_value(struct symbol *sym)
case no:
return "n";
case mod:
- sym_calc_value(modules_sym);
- return (modules_sym->curr.tri == no) ? "n" : "m";
+ return "m";
case yes:
return "y";
}
@@ -798,20 +882,18 @@ const char *sym_get_string_value(struct symbol *sym)
return (const char *)sym->curr.val;
}
-bool sym_is_changeable(struct symbol *sym)
+bool sym_is_changeable(const struct symbol *sym)
{
- return sym->visible > sym->rev_dep.tri;
+ return !sym_is_choice(sym) && sym->visible > sym->rev_dep.tri;
}
-static unsigned strhash(const char *s)
+bool sym_is_choice_value(const struct symbol *sym)
{
- /* fnv32 hash */
- unsigned hash = 2166136261U;
- for (; *s; s++)
- hash = (hash ^ *s) * 0x01000193;
- return hash;
+ return !list_empty(&sym->choice_link);
}
+HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE);
+
struct symbol *sym_lookup(const char *name, int flags)
{
struct symbol *symbol;
@@ -826,13 +908,13 @@ struct symbol *sym_lookup(const char *name, int flags)
case 'n': return &symbol_no;
}
}
- hash = strhash(name) % SYMBOL_HASHSIZE;
+ hash = hash_str(name);
- for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ hash_for_each_possible(sym_hashtable, symbol, node, hash) {
if (symbol->name &&
!strcmp(symbol->name, name) &&
(flags ? symbol->flags & flags
- : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+ : !(symbol->flags & SYMBOL_CONST)))
return symbol;
}
new_name = xstrdup(name);
@@ -846,9 +928,10 @@ struct symbol *sym_lookup(const char *name, int flags)
symbol->name = new_name;
symbol->type = S_UNKNOWN;
symbol->flags = flags;
+ INIT_LIST_HEAD(&symbol->menus);
+ INIT_LIST_HEAD(&symbol->choice_link);
- symbol->next = symbol_hash[hash];
- symbol_hash[hash] = symbol;
+ hash_add(sym_hashtable, &symbol->node, hash);
return symbol;
}
@@ -868,9 +951,9 @@ struct symbol *sym_find(const char *name)
case 'n': return &symbol_no;
}
}
- hash = strhash(name) % SYMBOL_HASHSIZE;
+ hash = hash_str(name);
- for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ hash_for_each_possible(sym_hashtable, symbol, node, hash) {
if (symbol->name &&
!strcmp(symbol->name, name) &&
!(symbol->flags & SYMBOL_CONST))
@@ -930,7 +1013,7 @@ struct symbol **sym_re_search(const char *pattern)
if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
return NULL;
- for_all_symbols(i, sym) {
+ for_all_symbols(sym) {
if (sym->flags & SYMBOL_CONST || !sym->name)
continue;
if (regexec(&re, sym->name, 1, match, 0))
@@ -1007,13 +1090,14 @@ static void sym_check_print_recursive(struct symbol *last_sym)
{
struct dep_stack *stack;
struct symbol *sym, *next_sym;
- struct menu *menu = NULL;
- struct property *prop;
+ struct menu *choice;
struct dep_stack cv_stack;
+ enum prop_type type;
- if (sym_is_choice_value(last_sym)) {
+ choice = sym_get_choice_menu(last_sym);
+ if (choice) {
dep_stack_insert(&cv_stack, last_sym);
- last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+ last_sym = choice->sym;
}
for (stack = check_top; stack != NULL; stack = stack->prev)
@@ -1027,59 +1111,37 @@ static void sym_check_print_recursive(struct symbol *last_sym)
for (; stack; stack = stack->next) {
sym = stack->sym;
next_sym = stack->next ? stack->next->sym : last_sym;
- prop = stack->prop;
- if (prop == NULL)
- prop = stack->sym->prop;
-
- /* for choice values find the menu entry (used below) */
- if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
- for (prop = sym->prop; prop; prop = prop->next) {
- menu = prop->menu;
- if (prop->menu)
- break;
- }
- }
+ type = stack->prop ? stack->prop->type : P_UNKNOWN;
+
if (stack->sym == last_sym)
- fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
- prop->file->name, prop->lineno);
+ fprintf(stderr, "error: recursive dependency detected!\n");
- if (sym_is_choice(sym)) {
- fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
- menu->file->name, menu->lineno,
- sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
- } else if (sym_is_choice_value(sym)) {
- fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
- menu->file->name, menu->lineno,
+ if (sym_is_choice(next_sym)) {
+ choice = list_first_entry(&next_sym->menus, struct menu, link);
+
+ fprintf(stderr, "\tsymbol %s is part of choice block at %s:%d\n",
sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
+ choice->filename, choice->lineno);
} else if (stack->expr == &sym->dir_dep.expr) {
- fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
- prop->file->name, prop->lineno,
+ fprintf(stderr, "\tsymbol %s depends on %s\n",
sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
+ next_sym->name);
} else if (stack->expr == &sym->rev_dep.expr) {
- fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
- prop->file->name, prop->lineno,
- sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
+ fprintf(stderr, "\tsymbol %s is selected by %s\n",
+ sym->name, next_sym->name);
} else if (stack->expr == &sym->implied.expr) {
- fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n",
- prop->file->name, prop->lineno,
- sym->name ? sym->name : "<choice>",
- next_sym->name ? next_sym->name : "<choice>");
+ fprintf(stderr, "\tsymbol %s is implied by %s\n",
+ sym->name, next_sym->name);
} else if (stack->expr) {
- fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
- prop->file->name, prop->lineno,
+ fprintf(stderr, "\tsymbol %s %s value contains %s\n",
sym->name ? sym->name : "<choice>",
- prop_get_type_name(prop->type),
- next_sym->name ? next_sym->name : "<choice>");
+ prop_get_type_name(type),
+ next_sym->name);
} else {
- fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n",
- prop->file->name, prop->lineno,
+ fprintf(stderr, "\tsymbol %s %s is visible depending on %s\n",
sym->name ? sym->name : "<choice>",
- prop_get_type_name(prop->type),
- next_sym->name ? next_sym->name : "<choice>");
+ prop_get_type_name(type),
+ next_sym->name);
}
}
@@ -1092,7 +1154,7 @@ static void sym_check_print_recursive(struct symbol *last_sym)
dep_stack_remove();
}
-static struct symbol *sym_check_expr_deps(struct expr *e)
+static struct symbol *sym_check_expr_deps(const struct expr *e)
{
struct symbol *sym;
@@ -1153,8 +1215,7 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
stack.expr = NULL;
for (prop = sym->prop; prop; prop = prop->next) {
- if (prop->type == P_CHOICE || prop->type == P_SELECT ||
- prop->type == P_IMPLY)
+ if (prop->type == P_SELECT || prop->type == P_IMPLY)
continue;
stack.prop = prop;
sym2 = sym_check_expr_deps(prop->visible.expr);
@@ -1177,16 +1238,18 @@ out:
static struct symbol *sym_check_choice_deps(struct symbol *choice)
{
- struct symbol *sym, *sym2;
- struct property *prop;
- struct expr *e;
+ struct menu *choice_menu, *menu;
+ struct symbol *sym2;
struct dep_stack stack;
dep_stack_insert(&stack, choice);
- prop = sym_get_choice_prop(choice);
- expr_list_for_each_sym(prop->expr, e, sym)
- sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ choice_menu = list_first_entry(&choice->menus, struct menu, link);
+
+ menu_for_each_sub_entry(menu, choice_menu) {
+ if (menu->sym)
+ menu->sym->flags |= SYMBOL_CHECK | SYMBOL_CHECKED;
+ }
choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
sym2 = sym_check_sym_deps(choice);
@@ -1194,18 +1257,25 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
if (sym2)
goto out;
- expr_list_for_each_sym(prop->expr, e, sym) {
- sym2 = sym_check_sym_deps(sym);
+ menu_for_each_sub_entry(menu, choice_menu) {
+ if (!menu->sym)
+ continue;
+ sym2 = sym_check_sym_deps(menu->sym);
if (sym2)
break;
}
out:
- expr_list_for_each_sym(prop->expr, e, sym)
- sym->flags &= ~SYMBOL_CHECK;
+ menu_for_each_sub_entry(menu, choice_menu)
+ if (menu->sym)
+ menu->sym->flags &= ~SYMBOL_CHECK;
- if (sym2 && sym_is_choice_value(sym2) &&
- prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
- sym2 = choice;
+ if (sym2) {
+ struct menu *choice_menu2;
+
+ choice_menu2 = sym_get_choice_menu(sym2);
+ if (choice_menu2 == choice_menu)
+ sym2 = choice;
+ }
dep_stack_remove();
@@ -1214,8 +1284,8 @@ out:
struct symbol *sym_check_deps(struct symbol *sym)
{
+ struct menu *choice;
struct symbol *sym2;
- struct property *prop;
if (sym->flags & SYMBOL_CHECK) {
sym_check_print_recursive(sym);
@@ -1224,13 +1294,13 @@ struct symbol *sym_check_deps(struct symbol *sym)
if (sym->flags & SYMBOL_CHECKED)
return NULL;
- if (sym_is_choice_value(sym)) {
+ choice = sym_get_choice_menu(sym);
+ if (choice) {
struct dep_stack stack;
/* for choice groups start the check with main choice symbol */
dep_stack_insert(&stack, sym);
- prop = sym_get_choice_prop(sym);
- sym2 = sym_check_deps(prop_get_symbol(prop));
+ sym2 = sym_check_deps(choice->sym);
dep_stack_remove();
} else if (sym_is_choice(sym)) {
sym2 = sym_check_choice_deps(sym);
@@ -1243,10 +1313,9 @@ struct symbol *sym_check_deps(struct symbol *sym)
return sym2;
}
-struct symbol *prop_get_symbol(struct property *prop)
+struct symbol *prop_get_symbol(const struct property *prop)
{
- if (prop->expr && (prop->expr->type == E_SYMBOL ||
- prop->expr->type == E_LIST))
+ if (prop->expr && prop->expr->type == E_SYMBOL)
return prop->expr->left.sym;
return NULL;
}
@@ -1262,16 +1331,12 @@ const char *prop_get_type_name(enum prop_type type)
return "menu";
case P_DEFAULT:
return "default";
- case P_CHOICE:
- return "choice";
case P_SELECT:
return "select";
case P_IMPLY:
return "imply";
case P_RANGE:
return "range";
- case P_SYMBOL:
- return "symbol";
case P_UNKNOWN:
break;
}
diff --git a/scripts/kconfig/tests/choice/Kconfig b/scripts/kconfig/tests/choice/Kconfig
index 0930eb65e932..cd252579a623 100644
--- a/scripts/kconfig/tests/choice/Kconfig
+++ b/scripts/kconfig/tests/choice/Kconfig
@@ -1,10 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
-config MODULES
- bool "Enable loadable module support"
- modules
- default y
-
choice
prompt "boolean choice"
default BOOL_CHOICE1
@@ -16,41 +11,3 @@ config BOOL_CHOICE1
bool "choice 1"
endchoice
-
-choice
- prompt "optional boolean choice"
- optional
- default OPT_BOOL_CHOICE1
-
-config OPT_BOOL_CHOICE0
- bool "choice 0"
-
-config OPT_BOOL_CHOICE1
- bool "choice 1"
-
-endchoice
-
-choice
- prompt "tristate choice"
- default TRI_CHOICE1
-
-config TRI_CHOICE0
- tristate "choice 0"
-
-config TRI_CHOICE1
- tristate "choice 1"
-
-endchoice
-
-choice
- prompt "optional tristate choice"
- optional
- default OPT_TRI_CHOICE1
-
-config OPT_TRI_CHOICE0
- tristate "choice 0"
-
-config OPT_TRI_CHOICE1
- tristate "choice 1"
-
-endchoice
diff --git a/scripts/kconfig/tests/choice/__init__.py b/scripts/kconfig/tests/choice/__init__.py
index 4318fce05912..0fc7bf9b5c78 100644
--- a/scripts/kconfig/tests/choice/__init__.py
+++ b/scripts/kconfig/tests/choice/__init__.py
@@ -1,13 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
"""
Basic choice tests.
-
-The handling of 'choice' is a bit complicated part in Kconfig.
-
-The behavior of 'y' choice is intuitive. If choice values are tristate,
-the choice can be 'm' where each value can be enabled independently.
-Also, if a choice is marked as 'optional', the whole choice can be
-invisible.
"""
@@ -16,11 +9,6 @@ def test_oldask0(conf):
assert conf.stdout_contains('oldask0_expected_stdout')
-def test_oldask1(conf):
- assert conf.oldaskconfig('oldask1_config') == 0
- assert conf.stdout_contains('oldask1_expected_stdout')
-
-
def test_allyes(conf):
assert conf.allyesconfig() == 0
assert conf.config_contains('allyes_expected_config')
diff --git a/scripts/kconfig/tests/choice/alldef_expected_config b/scripts/kconfig/tests/choice/alldef_expected_config
index 7a754bf4be94..b359a2e6493e 100644
--- a/scripts/kconfig/tests/choice/alldef_expected_config
+++ b/scripts/kconfig/tests/choice/alldef_expected_config
@@ -1,5 +1,2 @@
-CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
-# CONFIG_TRI_CHOICE0 is not set
-# CONFIG_TRI_CHOICE1 is not set
diff --git a/scripts/kconfig/tests/choice/allmod_expected_config b/scripts/kconfig/tests/choice/allmod_expected_config
index f1f5dcdb7923..b359a2e6493e 100644
--- a/scripts/kconfig/tests/choice/allmod_expected_config
+++ b/scripts/kconfig/tests/choice/allmod_expected_config
@@ -1,9 +1,2 @@
-CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
-# CONFIG_OPT_BOOL_CHOICE0 is not set
-CONFIG_OPT_BOOL_CHOICE1=y
-CONFIG_TRI_CHOICE0=m
-CONFIG_TRI_CHOICE1=m
-CONFIG_OPT_TRI_CHOICE0=m
-CONFIG_OPT_TRI_CHOICE1=m
diff --git a/scripts/kconfig/tests/choice/allno_expected_config b/scripts/kconfig/tests/choice/allno_expected_config
index b88ee7a43136..b359a2e6493e 100644
--- a/scripts/kconfig/tests/choice/allno_expected_config
+++ b/scripts/kconfig/tests/choice/allno_expected_config
@@ -1,5 +1,2 @@
-# CONFIG_MODULES is not set
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
-# CONFIG_TRI_CHOICE0 is not set
-CONFIG_TRI_CHOICE1=y
diff --git a/scripts/kconfig/tests/choice/allyes_expected_config b/scripts/kconfig/tests/choice/allyes_expected_config
index e5a062a1157c..b359a2e6493e 100644
--- a/scripts/kconfig/tests/choice/allyes_expected_config
+++ b/scripts/kconfig/tests/choice/allyes_expected_config
@@ -1,9 +1,2 @@
-CONFIG_MODULES=y
# CONFIG_BOOL_CHOICE0 is not set
CONFIG_BOOL_CHOICE1=y
-# CONFIG_OPT_BOOL_CHOICE0 is not set
-CONFIG_OPT_BOOL_CHOICE1=y
-# CONFIG_TRI_CHOICE0 is not set
-CONFIG_TRI_CHOICE1=y
-# CONFIG_OPT_TRI_CHOICE0 is not set
-CONFIG_OPT_TRI_CHOICE1=y
diff --git a/scripts/kconfig/tests/choice/oldask0_expected_stdout b/scripts/kconfig/tests/choice/oldask0_expected_stdout
index b251bba9698b..80ec34c61ebc 100644
--- a/scripts/kconfig/tests/choice/oldask0_expected_stdout
+++ b/scripts/kconfig/tests/choice/oldask0_expected_stdout
@@ -1,10 +1,4 @@
-Enable loadable module support (MODULES) [Y/n/?] (NEW)
boolean choice
1. choice 0 (BOOL_CHOICE0) (NEW)
> 2. choice 1 (BOOL_CHOICE1) (NEW)
choice[1-2?]:
-optional boolean choice [N/y/?] (NEW)
-tristate choice [M/y/?] (NEW)
- choice 0 (TRI_CHOICE0) [N/m/?] (NEW)
- choice 1 (TRI_CHOICE1) [N/m/?] (NEW)
-optional tristate choice [N/m/y/?] (NEW)
diff --git a/scripts/kconfig/tests/choice/oldask1_config b/scripts/kconfig/tests/choice/oldask1_config
deleted file mode 100644
index b67bfe3c641f..000000000000
--- a/scripts/kconfig/tests/choice/oldask1_config
+++ /dev/null
@@ -1,2 +0,0 @@
-# CONFIG_MODULES is not set
-CONFIG_OPT_BOOL_CHOICE0=y
diff --git a/scripts/kconfig/tests/choice/oldask1_expected_stdout b/scripts/kconfig/tests/choice/oldask1_expected_stdout
deleted file mode 100644
index c2125e9bf96a..000000000000
--- a/scripts/kconfig/tests/choice/oldask1_expected_stdout
+++ /dev/null
@@ -1,15 +0,0 @@
-Enable loadable module support (MODULES) [N/y/?]
-boolean choice
- 1. choice 0 (BOOL_CHOICE0) (NEW)
-> 2. choice 1 (BOOL_CHOICE1) (NEW)
-choice[1-2?]:
-optional boolean choice [Y/n/?] (NEW)
-optional boolean choice
-> 1. choice 0 (OPT_BOOL_CHOICE0)
- 2. choice 1 (OPT_BOOL_CHOICE1) (NEW)
-choice[1-2?]:
-tristate choice
- 1. choice 0 (TRI_CHOICE0) (NEW)
-> 2. choice 1 (TRI_CHOICE1) (NEW)
-choice[1-2?]:
-optional tristate choice [N/y/?]
diff --git a/scripts/kconfig/tests/choice_randomize/Kconfig b/scripts/kconfig/tests/choice_randomize/Kconfig
new file mode 100644
index 000000000000..93a1699ce3cb
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize/Kconfig
@@ -0,0 +1,22 @@
+choice
+ prompt "choose A or B"
+
+config A
+ bool "A"
+
+config B
+ bool "B"
+
+endchoice
+
+choice
+ prompt "choose X or Y"
+ depends on B
+
+config X
+ bool "X"
+
+config Y
+ bool "Y"
+
+endchoice
diff --git a/scripts/kconfig/tests/choice_randomize/__init__.py b/scripts/kconfig/tests/choice_randomize/__init__.py
new file mode 100644
index 000000000000..d380045be79c
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize/__init__.py
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+"""
+Randomize all dependent choices
+
+This is a somewhat tricky case for randconfig; the visibility of one choice is
+determined by a member of another choice. Randconfig should be able to generate
+all possible patterns.
+"""
+
+
+def test(conf):
+
+ expected0 = False
+ expected1 = False
+ expected2 = False
+
+ for i in range(100):
+ assert conf.randconfig(seed=i) == 0
+
+ if conf.config_matches('expected_config0'):
+ expected0 = True
+ elif conf.config_matches('expected_config1'):
+ expected1 = True
+ elif conf.config_matches('expected_config2'):
+ expected2 = True
+ else:
+ assert False
+
+ if expected0 and expected1 and expected2:
+ break
+
+ assert expected0
+ assert expected1
+ assert expected2
diff --git a/scripts/kconfig/tests/choice_randomize/expected_config0 b/scripts/kconfig/tests/choice_randomize/expected_config0
new file mode 100644
index 000000000000..f69227323759
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize/expected_config0
@@ -0,0 +1,6 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_A=y
+# CONFIG_B is not set
diff --git a/scripts/kconfig/tests/choice_randomize/expected_config1 b/scripts/kconfig/tests/choice_randomize/expected_config1
new file mode 100644
index 000000000000..bf83784c9b2a
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize/expected_config1
@@ -0,0 +1,8 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+# CONFIG_A is not set
+CONFIG_B=y
+CONFIG_X=y
+# CONFIG_Y is not set
diff --git a/scripts/kconfig/tests/choice_randomize/expected_config2 b/scripts/kconfig/tests/choice_randomize/expected_config2
new file mode 100644
index 000000000000..38f93a8f37bd
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize/expected_config2
@@ -0,0 +1,8 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+# CONFIG_A is not set
+CONFIG_B=y
+# CONFIG_X is not set
+CONFIG_Y=y
diff --git a/scripts/kconfig/tests/choice_randomize2/Kconfig b/scripts/kconfig/tests/choice_randomize2/Kconfig
new file mode 100644
index 000000000000..530cf2ef7f47
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize2/Kconfig
@@ -0,0 +1,32 @@
+choice
+ prompt "This is always invisible"
+ depends on n
+
+config DUMMY
+ bool "DUMMY"
+
+endchoice
+
+choice
+ prompt "Choose A or B"
+
+config A
+ bool "A"
+
+config B
+ bool "B"
+
+endchoice
+
+config FOO
+ bool "FOO"
+ depends on A
+
+choice
+ prompt "Choose X"
+ depends on FOO
+
+config X
+ bool "X"
+
+endchoice
diff --git a/scripts/kconfig/tests/choice_randomize2/__init__.py b/scripts/kconfig/tests/choice_randomize2/__init__.py
new file mode 100644
index 000000000000..2066757b80b9
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize2/__init__.py
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+"""
+Randomize choices with correct dependencies
+
+When shuffling a choice may potentially disrupt certain dependencies, symbol
+values must be recalculated.
+
+Related Linux commits:
+ - c8fb7d7e48d11520ad24808cfce7afb7b9c9f798
+"""
+
+
+def test(conf):
+ for i in range(20):
+ assert conf.randconfig(seed=i) == 0
+ assert (conf.config_matches('expected_config0') or
+ conf.config_matches('expected_config1') or
+ conf.config_matches('expected_config2'))
diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config0 b/scripts/kconfig/tests/choice_randomize2/expected_config0
new file mode 100644
index 000000000000..5c9e1c172c15
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize2/expected_config0
@@ -0,0 +1,8 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_A=y
+# CONFIG_B is not set
+CONFIG_FOO=y
+CONFIG_X=y
diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config1 b/scripts/kconfig/tests/choice_randomize2/expected_config1
new file mode 100644
index 000000000000..5b975d91bef1
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize2/expected_config1
@@ -0,0 +1,7 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+CONFIG_A=y
+# CONFIG_B is not set
+# CONFIG_FOO is not set
diff --git a/scripts/kconfig/tests/choice_randomize2/expected_config2 b/scripts/kconfig/tests/choice_randomize2/expected_config2
new file mode 100644
index 000000000000..5a5ebb90d1d7
--- /dev/null
+++ b/scripts/kconfig/tests/choice_randomize2/expected_config2
@@ -0,0 +1,6 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Main menu
+#
+# CONFIG_A is not set
+CONFIG_B=y
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
deleted file mode 100644
index bd970cec07d6..000000000000
--- a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-config MODULES
- def_bool y
- modules
-
-config DEP
- tristate
- default m
-
-choice
- prompt "Tristate Choice"
-
-config CHOICE0
- tristate "Choice 0"
-
-config CHOICE1
- tristate "Choice 1"
- depends on DEP
-
-endchoice
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py b/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
deleted file mode 100644
index 075b4e08696e..000000000000
--- a/scripts/kconfig/tests/choice_value_with_m_dep/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-"""
-Hide tristate choice values with mod dependency in y choice.
-
-If tristate choice values depend on symbols set to 'm', they should be
-hidden when the choice containing them is changed from 'm' to 'y'
-(i.e. exclusive choice).
-
-Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
-"""
-
-
-def test(conf):
- assert conf.oldaskconfig('config', 'y') == 0
- assert conf.config_contains('expected_config')
- assert conf.stdout_contains('expected_stdout')
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/config b/scripts/kconfig/tests/choice_value_with_m_dep/config
deleted file mode 100644
index 3a126b7a2546..000000000000
--- a/scripts/kconfig/tests/choice_value_with_m_dep/config
+++ /dev/null
@@ -1,2 +0,0 @@
-CONFIG_CHOICE0=m
-CONFIG_CHOICE1=m
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/expected_config b/scripts/kconfig/tests/choice_value_with_m_dep/expected_config
deleted file mode 100644
index 4d07b449540e..000000000000
--- a/scripts/kconfig/tests/choice_value_with_m_dep/expected_config
+++ /dev/null
@@ -1,3 +0,0 @@
-CONFIG_MODULES=y
-CONFIG_DEP=m
-CONFIG_CHOICE0=y
diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout b/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout
deleted file mode 100644
index 2b50ab65c86a..000000000000
--- a/scripts/kconfig/tests/choice_value_with_m_dep/expected_stdout
+++ /dev/null
@@ -1,4 +0,0 @@
-Tristate Choice [M/y/?] y
-Tristate Choice
-> 1. Choice 0 (CHOICE0)
-choice[1]: 1
diff --git a/scripts/kconfig/tests/conftest.py b/scripts/kconfig/tests/conftest.py
index af8774a5697c..2a2a7e2da060 100644
--- a/scripts/kconfig/tests/conftest.py
+++ b/scripts/kconfig/tests/conftest.py
@@ -154,12 +154,10 @@ class Conf:
defconfig_path = os.path.join(self._test_dir, defconfig)
return self._run_conf('--defconfig={}'.format(defconfig_path))
- def _allconfig(self, mode, all_config):
+ def _allconfig(self, mode, all_config, extra_env={}):
if all_config:
all_config_path = os.path.join(self._test_dir, all_config)
- extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
- else:
- extra_env = {}
+ extra_env['KCONFIG_ALLCONFIG'] = all_config_path
return self._run_conf('--{}config'.format(mode), extra_env=extra_env)
@@ -195,13 +193,19 @@ class Conf:
"""
return self._allconfig('alldef', all_config)
- def randconfig(self, all_config=None):
+ def randconfig(self, all_config=None, seed=None):
"""Run randconfig.
all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
+ seed: the seed for randconfig (optional)
returncode: exit status of the Kconfig executable
"""
- return self._allconfig('rand', all_config)
+ if seed is not None:
+ extra_env = {'KCONFIG_SEED': hex(seed)}
+ else:
+ extra_env = {}
+
+ return self._allconfig('rand', all_config, extra_env=extra_env)
def savedefconfig(self, dot_config):
"""Run savedefconfig.
diff --git a/scripts/kconfig/tests/err_recursive_dep/expected_stderr b/scripts/kconfig/tests/err_recursive_dep/expected_stderr
index c9f4abf9a791..fc2e860af082 100644
--- a/scripts/kconfig/tests/err_recursive_dep/expected_stderr
+++ b/scripts/kconfig/tests/err_recursive_dep/expected_stderr
@@ -1,38 +1,38 @@
-Kconfig:11:error: recursive dependency detected!
-Kconfig:11: symbol B is selected by B
+error: recursive dependency detected!
+ symbol A depends on A
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
-Kconfig:5:error: recursive dependency detected!
-Kconfig:5: symbol A depends on A
+error: recursive dependency detected!
+ symbol B is selected by B
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
-Kconfig:17:error: recursive dependency detected!
-Kconfig:17: symbol C1 depends on C2
-Kconfig:21: symbol C2 depends on C1
+error: recursive dependency detected!
+ symbol C1 depends on C2
+ symbol C2 depends on C1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
-Kconfig:32:error: recursive dependency detected!
-Kconfig:32: symbol D2 is selected by D1
-Kconfig:27: symbol D1 depends on D2
+error: recursive dependency detected!
+ symbol D1 depends on D2
+ symbol D2 is selected by D1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
-Kconfig:37:error: recursive dependency detected!
-Kconfig:37: symbol E1 depends on E2
-Kconfig:42: symbol E2 is implied by E1
+error: recursive dependency detected!
+ symbol E1 depends on E2
+ symbol E2 is implied by E1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
-Kconfig:60:error: recursive dependency detected!
-Kconfig:60: symbol G depends on G
+error: recursive dependency detected!
+ symbol F1 default value contains F2
+ symbol F2 depends on F1
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
-Kconfig:51:error: recursive dependency detected!
-Kconfig:51: symbol F2 depends on F1
-Kconfig:49: symbol F1 default value contains F2
+error: recursive dependency detected!
+ symbol G depends on G
For a resolution refer to Documentation/kbuild/kconfig-language.rst
subsection "Kconfig recursive dependency limitations"
diff --git a/scripts/kconfig/tests/inter_choice/Kconfig b/scripts/kconfig/tests/inter_choice/Kconfig
deleted file mode 100644
index 26c25f68695b..000000000000
--- a/scripts/kconfig/tests/inter_choice/Kconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-config MODULES
- def_bool y
- modules
-
-choice
- prompt "Choice"
-
-config CHOICE_VAL0
- tristate "Choice 0"
-
-config CHOIVE_VAL1
- tristate "Choice 1"
-
-endchoice
-
-choice
- prompt "Another choice"
- depends on CHOICE_VAL0
-
-config DUMMY
- bool "dummy"
-
-endchoice
diff --git a/scripts/kconfig/tests/inter_choice/__init__.py b/scripts/kconfig/tests/inter_choice/__init__.py
deleted file mode 100644
index ffea6b1148a6..000000000000
--- a/scripts/kconfig/tests/inter_choice/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-"""
-Do not affect user-assigned choice value by another choice.
-
-Handling of state flags for choices is complecated. In old days,
-the defconfig result of a choice could be affected by another choice
-if those choices interact by 'depends on', 'select', etc.
-
-Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
-"""
-
-
-def test(conf):
- assert conf.defconfig('defconfig') == 0
- assert conf.config_contains('expected_config')
diff --git a/scripts/kconfig/tests/inter_choice/defconfig b/scripts/kconfig/tests/inter_choice/defconfig
deleted file mode 100644
index 162c4148e2a5..000000000000
--- a/scripts/kconfig/tests/inter_choice/defconfig
+++ /dev/null
@@ -1 +0,0 @@
-CONFIG_CHOICE_VAL0=y
diff --git a/scripts/kconfig/tests/inter_choice/expected_config b/scripts/kconfig/tests/inter_choice/expected_config
deleted file mode 100644
index 5dceefb054e3..000000000000
--- a/scripts/kconfig/tests/inter_choice/expected_config
+++ /dev/null
@@ -1,4 +0,0 @@
-CONFIG_MODULES=y
-CONFIG_CHOICE_VAL0=y
-# CONFIG_CHOIVE_VAL1 is not set
-CONFIG_DUMMY=y
diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c
index 92e5b2b9761d..5cdcee144b58 100644
--- a/scripts/kconfig/util.c
+++ b/scripts/kconfig/util.c
@@ -7,25 +7,42 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+
+#include <hash.h>
+#include <hashtable.h>
+#include <xalloc.h>
#include "lkc.h"
+/* hash table of all parsed Kconfig files */
+static HASHTABLE_DEFINE(file_hashtable, 1U << 11);
+
+struct file {
+ struct hlist_node node;
+ char name[];
+};
+
/* file already present in list? If not add it */
-struct file *file_lookup(const char *name)
+const char *file_lookup(const char *name)
{
struct file *file;
+ size_t len;
+ int hash = hash_str(name);
- for (file = file_list; file; file = file->next) {
- if (!strcmp(name, file->name)) {
- return file;
- }
- }
+ hash_for_each_possible(file_hashtable, file, node, hash)
+ if (!strcmp(name, file->name))
+ return file->name;
- file = xmalloc(sizeof(*file));
+ len = strlen(name);
+ file = xmalloc(sizeof(*file) + len + 1);
memset(file, 0, sizeof(*file));
- file->name = xstrdup(name);
- file->next = file_list;
- file_list = file;
- return file;
+ memcpy(file->name, name, len);
+ file->name[len] = '\0';
+
+ hash_add(file_hashtable, &file->node, hash);
+
+ str_printf(&autoconf_cmd, "\t%s \\\n", name);
+
+ return file->name;
}
/* Allocate initial growable string */
@@ -73,56 +90,7 @@ void str_printf(struct gstr *gs, const char *fmt, ...)
}
/* Retrieve value of growable string */
-char *str_get(struct gstr *gs)
+char *str_get(const struct gstr *gs)
{
return gs->s;
}
-
-void *xmalloc(size_t size)
-{
- void *p = malloc(size);
- if (p)
- return p;
- fprintf(stderr, "Out of memory.\n");
- exit(1);
-}
-
-void *xcalloc(size_t nmemb, size_t size)
-{
- void *p = calloc(nmemb, size);
- if (p)
- return p;
- fprintf(stderr, "Out of memory.\n");
- exit(1);
-}
-
-void *xrealloc(void *p, size_t size)
-{
- p = realloc(p, size);
- if (p)
- return p;
- fprintf(stderr, "Out of memory.\n");
- exit(1);
-}
-
-char *xstrdup(const char *s)
-{
- char *p;
-
- p = strdup(s);
- if (p)
- return p;
- 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);
-}