X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=scripts%2Fkconfig%2Fconfdata.c;h=c4dec80cfd8e14a94792af807da0e9705256257d;hb=d5aa407f59f5b83d2c50ec88f5bf56d40f1f8978;hp=b0cbbe2e41bb372c36a9aa152b44ab78607b0a62;hpb=2244cbd8a9185c197ec5ba5de175aec288697223;p=safe%2Fjmp%2Flinux-2.6 diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index b0cbbe2..c4dec80 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -20,19 +21,8 @@ static void conf_warning(const char *fmt, ...) static const char *conf_filename; static int conf_lineno, conf_warnings, conf_unsaved; -const char conf_def_filename[] = ".config"; - const char conf_defname[] = "arch/$ARCH/defconfig"; -const char *conf_confnames[] = { - ".config", - "/lib/modules/$UNAME_RELEASE/.config", - "/etc/kernel-config", - "/boot/config-$UNAME_RELEASE", - conf_defname, - NULL, -}; - static void conf_warning(const char *fmt, ...) { va_list ap; @@ -44,6 +34,20 @@ static void conf_warning(const char *fmt, ...) conf_warnings++; } +const char *conf_get_configname(void) +{ + char *name = getenv("KCONFIG_CONFIG"); + + return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ + char *name = getenv("KCONFIG_AUTOCONFIG"); + + return name ? name : "include/config/auto.conf"; +} + static char *conf_expand_value(const char *in) { struct symbol *sym; @@ -86,51 +90,127 @@ char *conf_get_default_confname(void) return name; } -int conf_read_simple(const char *name) +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ + char *p2; + + switch (sym->type) { + case S_TRISTATE: + if (p[0] == 'm') { + sym->def[def].tri = mod; + sym->flags |= def_flags; + break; + } + case S_BOOLEAN: + if (p[0] == 'y') { + sym->def[def].tri = yes; + sym->flags |= def_flags; + break; + } + if (p[0] == 'n') { + sym->def[def].tri = no; + sym->flags |= def_flags; + break; + } + conf_warning("symbol value '%s' invalid for %s", p, sym->name); + break; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + case S_STRING: + if (*p++ != '"') + break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); + } + if (!p2) { + conf_warning("invalid string found"); + return 1; + } + case S_INT: + case S_HEX: + done: + if (sym_string_valid(sym, p)) { + sym->def[def].val = strdup(p); + sym->flags |= def_flags; + } else { + conf_warning("symbol value '%s' invalid for %s", p, sym->name); + return 1; + } + break; + default: + ; + } + return 0; +} + +int conf_read_simple(const char *name, int def) { FILE *in = NULL; char line[1024]; char *p, *p2; struct symbol *sym; - int i; + int i, def_flags; if (name) { in = zconf_fopen(name); } else { - const char **names = conf_confnames; - while ((name = *names++)) { - name = conf_expand_value(name); + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + if (!sym_defconfig_list) + return 1; + + for_all_defaults(sym_defconfig_list, prop) { + if (expr_calc_value(prop->visible.expr) == no || + prop->expr->type != E_SYMBOL) + continue; + name = conf_expand_value(prop->expr->left.sym->name); in = zconf_fopen(name); if (in) { printf(_("#\n" - "# using defaults found in %s\n" - "#\n"), name); - break; + "# using defaults found in %s\n" + "#\n"), name); + goto load; } } } if (!in) return 1; +load: conf_filename = name; conf_lineno = 0; conf_warnings = 0; conf_unsaved = 0; + def_flags = SYMBOL_DEF << def; for_all_symbols(i, sym) { - sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED; + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); if (sym_is_choice(sym)) - sym->flags &= ~SYMBOL_NEW; - sym->flags &= ~SYMBOL_VALID; + sym->flags |= def_flags; switch (sym->type) { case S_INT: case S_HEX: case S_STRING: - if (sym->user.val) - free(sym->user.val); + if (sym->def[def].val) + free(sym->def[def].val); default: - sym->user.val = NULL; - sym->user.tri = no; + sym->def[def].val = NULL; + sym->def[def].tri = no; } } @@ -147,19 +227,25 @@ int conf_read_simple(const char *name) *p++ = 0; if (strncmp(p, "is not set", 10)) continue; - sym = sym_find(line + 9); - if (!sym) { - conf_warning("trying to assign nonexistent symbol %s", line + 9); - break; - } else if (!(sym->flags & SYMBOL_NEW)) { - conf_warning("trying to reassign symbol %s", sym->name); - break; + if (def == S_DEF_USER) { + sym = sym_find(line + 9); + if (!sym) { + sym_add_change_count(1); + break; + } + } else { + sym = sym_lookup(line + 9, 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); } switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: - sym->user.tri = no; - sym->flags &= ~SYMBOL_NEW; + sym->def[def].tri = no; + sym->flags |= def_flags; break; default: ; @@ -175,64 +261,29 @@ int conf_read_simple(const char *name) continue; *p++ = 0; p2 = strchr(p, '\n'); - if (p2) - *p2 = 0; - sym = sym_find(line + 7); - if (!sym) { - conf_warning("trying to assign nonexistent symbol %s", line + 7); - break; - } else if (!(sym->flags & SYMBOL_NEW)) { - conf_warning("trying to reassign symbol %s", sym->name); - break; + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; } - switch (sym->type) { - case S_TRISTATE: - if (p[0] == 'm') { - sym->user.tri = mod; - sym->flags &= ~SYMBOL_NEW; - break; - } - case S_BOOLEAN: - if (p[0] == 'y') { - sym->user.tri = yes; - sym->flags &= ~SYMBOL_NEW; + if (def == S_DEF_USER) { + sym = sym_find(line + 7); + if (!sym) { + sym_add_change_count(1); break; } - if (p[0] == 'n') { - sym->user.tri = no; - sym->flags &= ~SYMBOL_NEW; - break; - } - conf_warning("symbol value '%s' invalid for %s", p, sym->name); - break; - case S_STRING: - if (*p++ != '"') - break; - for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { - if (*p2 == '"') { - *p2 = 0; - break; - } - memmove(p2, p2 + 1, strlen(p2)); - } - if (!p2) { - conf_warning("invalid string found"); - continue; - } - case S_INT: - case S_HEX: - if (sym_string_valid(sym, p)) { - sym->user.val = strdup(p); - sym->flags &= ~SYMBOL_NEW; - } else { - conf_warning("symbol value '%s' invalid for %s", p, sym->name); - continue; - } - break; - default: - ; + } else { + sym = sym_lookup(line + 7, 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); + } + if (conf_set_sym_val(sym, def, def_flags, p)) + continue; break; + case '\r': case '\n': break; default: @@ -241,24 +292,22 @@ int conf_read_simple(const char *name) } if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - switch (sym->user.tri) { + switch (sym->def[def].tri) { case no: break; case mod: - if (cs->user.tri == yes) { + if (cs->def[def].tri == yes) { conf_warning("%s creates inconsistent choice state", sym->name); - cs->flags |= SYMBOL_NEW; + cs->flags &= ~def_flags; } break; case yes: - if (cs->user.tri != no) { - conf_warning("%s creates inconsistent choice state", sym->name); - cs->flags |= SYMBOL_NEW; - } else - cs->user.val = sym; + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; break; } - cs->user.tri = E_OR(cs->user.tri, sym->user.tri); + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); } } fclose(in); @@ -270,12 +319,14 @@ int conf_read_simple(const char *name) int conf_read(const char *name) { - struct symbol *sym; + struct symbol *sym, *choice_sym; struct property *prop; struct expr *e; - int i; + int i, flags; - if (conf_read_simple(name)) + sym_set_change_count(0); + + if (conf_read_simple(name, S_DEF_USER)) return 1; for_all_symbols(i, sym) { @@ -287,12 +338,12 @@ int conf_read(const char *name) switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: - if (sym->user.tri != sym_get_tristate_value(sym)) + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) break; if (!sym_is_choice(sym)) goto sym_ok; default: - if (!strcmp(sym->curr.val, sym->user.val)) + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) goto sym_ok; break; } @@ -302,37 +353,52 @@ int conf_read(const char *name) conf_unsaved++; /* maybe print value in verbose mode... */ sym_ok: + if (!sym_is_choice(sym)) + continue; + /* The choice symbol only has a set value (and thus is not new) + * if all its visible childs have values. + */ + prop = sym_get_choice_prop(sym); + flags = sym->flags; + expr_list_for_each_sym(prop->expr, e, choice_sym) + if (choice_sym->visible != no) + flags &= choice_sym->flags; + sym->flags &= flags | ~SYMBOL_DEF_USER; + } + + for_all_symbols(i, sym) { if (sym_has_value(sym) && !sym_is_choice_value(sym)) { - if (sym->visible == no) - sym->flags |= SYMBOL_NEW; + /* 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: - if (!sym_string_within_range(sym, sym->user.val)) { - sym->flags |= SYMBOL_NEW; - sym->flags &= ~SYMBOL_VALID; - } + /* 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|SYMBOL_DEF_USER); + conf_unsaved++; + break; default: break; } } - if (!sym_is_choice(sym)) - continue; - prop = sym_get_choice_prop(sym); - for (e = prop->expr; e; e = e->left.expr) - if (e->right.sym->visible != no) - sym->flags |= e->right.sym->flags & SYMBOL_NEW; } - sym_change_count = conf_warnings && conf_unsaved; + sym_add_change_count(conf_warnings || conf_unsaved); return 0; } int conf_write(const char *name) { - FILE *out, *out_h; + FILE *out; struct symbol *sym; struct menu *menu; const char *basename; @@ -351,7 +417,7 @@ int conf_write(const char *name) if (!stat(name, &st) && S_ISDIR(st.st_mode)) { strcpy(dirname, name); strcat(dirname, "/"); - basename = conf_def_filename; + basename = conf_get_configname(); } else if ((slash = strrchr(name, '/'))) { int size = slash - name + 1; memcpy(dirname, name, size); @@ -359,22 +425,24 @@ int conf_write(const char *name) if (slash[1]) basename = slash + 1; else - basename = conf_def_filename; + basename = conf_get_configname(); } else basename = name; } else - basename = conf_def_filename; + basename = conf_get_configname(); - sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid()); - out = fopen(newname, "w"); + sprintf(newname, "%s%s", dirname, basename); + env = getenv("KCONFIG_OVERWRITECONFIG"); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); + out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); + } if (!out) return 1; - out_h = NULL; - if (!name) { - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) - return 1; - } + sym = sym_lookup("KERNELVERSION", 0); sym_calc_value(sym); time(&now); @@ -390,18 +458,8 @@ int conf_write(const char *name) sym_get_string_value(sym), use_timestamp ? "# " : "", use_timestamp ? ctime(&now) : ""); - if (out_h) - fprintf(out_h, "/*\n" - " * Automatically generated C config: don't edit\n" - " * Linux kernel version: %s\n" - "%s%s" - " */\n" - "#define AUTOCONF_INCLUDED\n", - sym_get_string_value(sym), - use_timestamp ? " * " : "", - use_timestamp ? ctime(&now) : ""); - - if (!sym_change_count) + + if (!conf_get_changed()) sym_clear_all_valid(); menu = rootmenu.list; @@ -415,11 +473,6 @@ int conf_write(const char *name) "#\n" "# %s\n" "#\n", str); - if (out_h) - fprintf(out_h, "\n" - "/*\n" - " * %s\n" - " */\n", str); } else if (!(sym->flags & SYMBOL_CHOICE)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) @@ -437,59 +490,39 @@ int conf_write(const char *name) switch (sym_get_tristate_value(sym)) { case no: fprintf(out, "# CONFIG_%s is not set\n", sym->name); - if (out_h) - fprintf(out_h, "#undef CONFIG_%s\n", sym->name); break; case mod: fprintf(out, "CONFIG_%s=m\n", sym->name); - if (out_h) - fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); break; case yes: fprintf(out, "CONFIG_%s=y\n", sym->name); - if (out_h) - fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); break; } break; case S_STRING: - // fix me str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=\"", sym->name); - if (out_h) - fprintf(out_h, "#define CONFIG_%s \"", sym->name); - do { + while (1) { l = strcspn(str, "\"\\"); if (l) { fwrite(str, l, 1, out); - if (out_h) - fwrite(str, l, 1, out_h); - } - str += l; - while (*str == '\\' || *str == '"') { - fprintf(out, "\\%c", *str); - if (out_h) - fprintf(out_h, "\\%c", *str); - str++; + str += l; } - } while (*str); + if (!*str) + break; + fprintf(out, "\\%c", *str++); + } fputs("\"\n", out); - if (out_h) - fputs("\"\n", out_h); break; case S_HEX: str = sym_get_string_value(sym); if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - if (out_h) - fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); break; } case S_INT: str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - if (out_h) - fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); break; } } @@ -509,22 +542,387 @@ int conf_write(const char *name) } } fclose(out); - if (out_h) { - fclose(out_h); - rename(".tmpconfig.h", "include/linux/autoconf.h"); - file_write_dep(NULL); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; + } + + printf(_("#\n" + "# configuration written to %s\n" + "#\n"), newname); + + sym_set_change_count(0); + + return 0; +} + +static int conf_split_config(void) +{ + const char *name; + char path[128]; + char *s, *d, c; + struct symbol *sym; + struct stat sb; + int res, i, fd; + + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + if (chdir("include/config")) + return 1; + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * different from 'no'). + */ + + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); } - if (!name || basename != conf_def_filename) { - if (!name) - name = conf_def_filename; - sprintf(tmpname, "%s.old", name); - rename(name, tmpname); +out: + if (chdir("../..")) + return 1; + + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *str; + const char *name; + FILE *out, *tristate, *out_h; + time_t now; + int i, l; + + sym_clear_all_valid(); + + file_write_dep("include/config/auto.conf.cmd"); + + if (conf_split_config()) + return 1; + + out = fopen(".tmpconfig", "w"); + if (!out) + return 1; + + tristate = fopen(".tmpconfig_tristate", "w"); + if (!tristate) { + fclose(out); + return 1; } - sprintf(tmpname, "%s%s", dirname, basename); - if (rename(newname, tmpname)) + + out_h = fopen(".tmpconfig.h", "w"); + if (!out_h) { + fclose(out); + fclose(tristate); return 1; + } - sym_change_count = 0; + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); + time(&now); + fprintf(out, "#\n" + "# Automatically generated make config: don't edit\n" + "# Linux kernel version: %s\n" + "# %s" + "#\n", + sym_get_string_value(sym), ctime(&now)); + fprintf(tristate, "#\n" + "# Automatically generated - do not edit\n" + "\n"); + fprintf(out_h, "/*\n" + " * Automatically generated C config: don't edit\n" + " * Linux kernel version: %s\n" + " * %s" + " */\n" + "#define AUTOCONF_INCLUDED\n", + sym_get_string_value(sym), ctime(&now)); + + for_all_symbols(i, sym) { + sym_calc_value(sym); + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) + continue; + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (sym_get_tristate_value(sym)) { + case no: + break; + case mod: + fprintf(out, "CONFIG_%s=m\n", sym->name); + fprintf(tristate, "CONFIG_%s=M\n", sym->name); + fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); + break; + case yes: + fprintf(out, "CONFIG_%s=y\n", sym->name); + if (sym->type == S_TRISTATE) + fprintf(tristate, "CONFIG_%s=Y\n", + sym->name); + fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); + break; + } + break; + case S_STRING: + str = sym_get_string_value(sym); + fprintf(out, "CONFIG_%s=\"", sym->name); + fprintf(out_h, "#define CONFIG_%s \"", sym->name); + while (1) { + l = strcspn(str, "\"\\"); + if (l) { + fwrite(str, l, 1, out); + fwrite(str, l, 1, out_h); + str += l; + } + if (!*str) + break; + fprintf(out, "\\%c", *str); + fprintf(out_h, "\\%c", *str); + str++; + } + fputs("\"\n", out); + fputs("\"\n", out_h); + break; + case S_HEX: + str = sym_get_string_value(sym); + if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { + fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); + break; + } + case S_INT: + str = sym_get_string_value(sym); + fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); + break; + default: + break; + } + } + fclose(out); + fclose(tristate); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/generated/autoconf.h"; + if (rename(".tmpconfig.h", name)) + return 1; + name = getenv("KCONFIG_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + if (rename(".tmpconfig_tristate", name)) + return 1; + name = conf_get_autoconfig_name(); + /* + * This must be the last step, kbuild has a dependency on auto.conf + * and this marks the successful completion of the previous steps. + */ + if (rename(".tmpconfig", name)) + return 1; return 0; } + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} + + +void conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + struct property *prop; + struct expr *e; + int i, cnt, def; + + for_all_symbols(i, sym) { + if (sym_has_value(sym)) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + 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 = (tristate)(rand() % 3); + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + if (mode != def_random) + return; + /* + * We have different type of choice blocks. + * If curr.tri equal to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equal yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + + if (csym->curr.tri != yes) + continue; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * 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; + } + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); + } +}