]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/tool/kconfig/scripts/kconfig/confdata.c
Update
[l4.git] / l4 / tool / kconfig / scripts / kconfig / confdata.c
index d036aa75f6b754bddbd56553dd938211d2d24db4..c66497805acaf2dfadc6884dc93340b1da6b6f5a 100644 (file)
@@ -7,15 +7,20 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
+struct conf_printer {
+       void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+       void (*print_comment)(FILE *, const char *, void *);
+};
+
 static void conf_warning(const char *fmt, ...)
        __attribute__ ((format (printf, 1, 2)));
 
@@ -59,6 +64,7 @@ static void conf_message(const char *fmt, ...)
        va_start(ap, fmt);
        if (conf_message_callback)
                conf_message_callback(fmt, ap);
+       va_end(ap);
 }
 
 const char *conf_get_configname(void)
@@ -128,6 +134,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->flags |= def_flags;
                        break;
                }
+               /* fall through */
        case S_BOOLEAN:
                if (p[0] == 'y') {
                        sym->def[def].tri = yes;
@@ -139,8 +146,10 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->flags |= def_flags;
                        break;
                }
-               conf_warning("symbol value '%s' invalid for %s", p, sym->name);
-               break;
+               if (def != S_DEF_AUTO)
+                       conf_warning("symbol value '%s' invalid for %s",
+                                    p, sym->name);
+               return 1;
        case S_OTHER:
                if (*p != '"') {
                        for (p2 = p; *p2 && !isspace(*p2); p2++)
@@ -148,6 +157,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->type = S_STRING;
                        goto done;
                }
+               /* fall through */
        case S_STRING:
                if (*p++ != '"')
                        break;
@@ -159,9 +169,11 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        memmove(p2, p2 + 1, strlen(p2));
                }
                if (!p2) {
-                       conf_warning("invalid string found");
+                       if (def != S_DEF_AUTO)
+                               conf_warning("invalid string found");
                        return 1;
                }
+               /* fall through */
        case S_INT:
        case S_HEX:
        done:
@@ -169,7 +181,9 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->def[def].val = strdup(p);
                        sym->flags |= def_flags;
                } else {
-                       conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                       if (def != S_DEF_AUTO)
+                               conf_warning("symbol value '%s' invalid for %s",
+                                            p, sym->name);
                        return 1;
                }
                break;
@@ -179,10 +193,66 @@ 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)
+{
+       char *nline;
+       size_t new_size = slen + 1;
+       if (new_size > *n) {
+               new_size += LINE_GROWTH - 1;
+               new_size *= 2;
+               nline = realloc(*lineptr, new_size);
+               if (!nline)
+                       return -1;
+
+               *lineptr = nline;
+               *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;
+}
+
 int conf_read_simple(const char *name, int def)
 {
        FILE *in = NULL;
-       char line[1024];
+       char   *line = NULL;
+       size_t  line_asize = 0;
        char *p, *p2;
        struct symbol *sym;
        int i, def_flags;
@@ -198,8 +268,7 @@ int conf_read_simple(const char *name, int def)
                        goto load;
                sym_add_change_count(1);
                if (!sym_defconfig_list) {
-                       if (modules_sym)
-                               sym_calc_value(modules_sym);
+                       sym_calc_value(modules_sym);
                        return 1;
                }
 
@@ -237,13 +306,14 @@ load:
                case S_STRING:
                        if (sym->def[def].val)
                                free(sym->def[def].val);
+                       /* fall through */
                default:
                        sym->def[def].val = NULL;
                        sym->def[def].tri = no;
                }
        }
 
-       while (fgets(line, sizeof(line), in)) {
+       while (compat_getline(&line, &line_asize, in) != -1) {
                conf_lineno++;
                sym = NULL;
                if (line[0] == '#') {
@@ -331,19 +401,16 @@ setsym:
                        cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
                }
        }
+       free(line);
        fclose(in);
-
-       if (modules_sym)
                sym_calc_value(modules_sym);
        return 0;
 }
 
 int conf_read(const char *name)
 {
-       struct symbol *sym, *choice_sym;
-       struct property *prop;
-       struct expr *e;
-       int i, flags;
+       struct symbol *sym;
+       int i;
 
        sym_set_change_count(0);
 
@@ -353,7 +420,7 @@ int conf_read(const char *name)
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
                if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
-                       goto sym_ok;
+                       continue;
                if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
                        /* check that calculated value agrees with saved value */
                        switch (sym->type) {
@@ -362,29 +429,18 @@ int conf_read(const char *name)
                                if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
                                        break;
                                if (!sym_is_choice(sym))
-                                       goto sym_ok;
+                                       continue;
+                               /* fall through */
                        default:
                                if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
-                                       goto sym_ok;
+                                       continue;
                                break;
                        }
                } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
                        /* no previous value and not saved */
-                       goto sym_ok;
+                       continue;
                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) {
@@ -417,65 +473,191 @@ int conf_read(const char *name)
        return 0;
 }
 
-/* Write a S_STRING */
-static void conf_write_string(bool headerfile, const char *name,
-                              const char *str, FILE *out)
+/*
+ * Kconfig configuration printer
+ *
+ * This printer is used when generating the resulting configuration after
+ * kconfig invocation and `defconfig' files. Unset symbol might be omitted by
+ * passing a non-NULL argument to the printer.
+ *
+ */
+static void
+kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               if (*value == 'n') {
+                       bool skip_unset = (arg != NULL);
+
+                       if (!skip_unset)
+                               fprintf(fp, "# %s%s is not set\n",
+                                   CONFIG_, sym->name);
+                       return;
+               }
+               break;
+       default:
+               break;
+       }
+
+       fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
 {
-       int l;
-       if (headerfile)
-               fprintf(out, "#define %s%s \"", CONFIG_, name);
-       else
-               fprintf(out, "%s%s=\"", CONFIG_, name);
-
-       while (1) {
-               l = strcspn(str, "\"\\");
+       const char *p = value;
+       size_t l;
+
+       for (;;) {
+               l = strcspn(p, "\n");
+               fprintf(fp, "#");
                if (l) {
-                       xfwrite(str, l, 1, out);
-                       str += l;
+                       fprintf(fp, " ");
+                       xfwrite(p, l, 1, fp);
+                       p += l;
                }
-               if (!*str)
+               fprintf(fp, "\n");
+               if (*p++ == '\0')
                        break;
-               fprintf(out, "\\%c", *str++);
        }
-       fputs("\"\n", out);
 }
 
-static void conf_write_symbol(struct symbol *sym, enum symbol_type type,
-                              FILE *out, bool write_no)
+static struct conf_printer kconfig_printer_cb =
+{
+       .print_symbol = kconfig_print_symbol,
+       .print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
 {
-       const char *str;
 
-       switch (type) {
+       switch (sym->type) {
        case S_BOOLEAN:
-       case S_TRISTATE:
-               switch (sym_get_tristate_value(sym)) {
-               case no:
-                       if (write_no)
-                               fprintf(out, "# %s%s is not set\n",
-                                   CONFIG_, sym->name);
-                       break;
-               case mod:
-                       fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
-                       break;
-               case yes:
-                       fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
+       case S_TRISTATE: {
+               const char *suffix = "";
+
+               switch (*value) {
+               case 'n':
                        break;
+               case 'm':
+                       suffix = "_MODULE";
+                       /* fall through */
+               default:
+                       fprintf(fp, "#define %s%s%s 1\n",
+                           CONFIG_, sym->name, suffix);
                }
                break;
-       case S_STRING:
-               conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+       }
+       case S_HEX: {
+               const char *prefix = "";
+
+               if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+                       prefix = "0x";
+               fprintf(fp, "#define %s%s %s%s\n",
+                   CONFIG_, sym->name, prefix, value);
                break;
-       case S_HEX:
+       }
+       case S_STRING:
        case S_INT:
-               str = sym_get_string_value(sym);
-               fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
+               fprintf(fp, "#define %s%s %s\n",
+                   CONFIG_, sym->name, value);
                break;
+       default:
+               break;
+       }
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+       const char *p = value;
+       size_t l;
+
+       fprintf(fp, "/*\n");
+       for (;;) {
+               l = strcspn(p, "\n");
+               fprintf(fp, " *");
+               if (l) {
+                       fprintf(fp, " ");
+                       xfwrite(p, l, 1, fp);
+                       p += l;
+               }
+               fprintf(fp, "\n");
+               if (*p++ == '\0')
+                       break;
+       }
+       fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+       .print_symbol = header_print_symbol,
+       .print_comment = header_print_comment,
+};
+
+/*
+ * Tristate printer
+ *
+ * This printer is used when generating the `include/config/tristate.conf' file.
+ */
+static void
+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+       if (sym->type == S_TRISTATE && *value != 'n')
+               fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value));
+}
+
+static struct conf_printer tristate_printer_cb =
+{
+       .print_symbol = tristate_print_symbol,
+       .print_comment = kconfig_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+                             struct conf_printer *printer, void *printer_arg)
+{
+       const char *str;
+
+       switch (sym->type) {
        case S_OTHER:
        case S_UNKNOWN:
                break;
+       case S_STRING:
+               str = sym_get_string_value(sym);
+               str = sym_escape_string_value(str);
+               printer->print_symbol(fp, sym, str, printer_arg);
+               free((void *)str);
+               break;
+       default:
+               str = sym_get_string_value(sym);
+               printer->print_symbol(fp, sym, str, printer_arg);
        }
 }
 
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+       char buf[256];
+
+       snprintf(buf, sizeof(buf),
+           "\n"
+           "Automatically generated file; DO NOT EDIT.\n"
+           "%s\n",
+           rootmenu.prompt->text);
+
+       printer->print_comment(fp, buf, printer_arg);
+}
+
 /*
  * Write out a minimal config.
  * All values that has default values are skipped as this is redundant.
@@ -532,7 +714,7 @@ int conf_write_defconfig(const char *filename)
                                                goto next_menu;
                                }
                        }
-                       conf_write_symbol(sym, sym->type, out, true);
+                       conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
                }
 next_menu:
                if (menu->list != NULL) {
@@ -561,9 +743,6 @@ int conf_write(const char *name)
        const char *basename;
        const char *str;
        char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
-       enum symbol_type type;
-       time_t now;
-       int use_timestamp = 1;
        char *env;
 
        dirname[0] = 0;
@@ -600,19 +779,7 @@ int conf_write(const char *name)
        if (!out)
                return 1;
 
-       time(&now);
-       env = getenv("KCONFIG_NOTIMESTAMP");
-       if (env && *env)
-               use_timestamp = 0;
-
-       fprintf(out, _("#\n"
-                      "# Automatically generated make config: don't edit\n"
-                      "# L4Re version: %s\n"
-                      "%s%s"
-                      "#\n"),
-                    rootmenu.prompt->text,
-                    use_timestamp ? "# " : "",
-                    use_timestamp ? ctime(&now) : "");
+       conf_write_heading(out, &kconfig_printer_cb, NULL);
 
        if (!conf_get_changed())
                sym_clear_all_valid();
@@ -633,14 +800,8 @@ int conf_write(const char *name)
                        if (!(sym->flags & SYMBOL_WRITE))
                                goto next;
                        sym->flags &= ~SYMBOL_WRITE;
-                       type = sym->type;
-                       if (type == S_TRISTATE) {
-                               sym_calc_value(modules_sym);
-                               if (modules_sym->curr.tri == no)
-                                       type = S_BOOLEAN;
-                       }
-                       /* Write config symbol to file */
-                       conf_write_symbol(sym, type, out, true);
+
+                       conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
                }
 
 next:
@@ -789,10 +950,8 @@ out:
 int conf_write_autoconf(void)
 {
        struct symbol *sym;
-       const char *str;
        const char *name;
        FILE *out, *tristate, *out_h;
-       time_t now;
        int i;
 
        sym_clear_all_valid();
@@ -819,72 +978,23 @@ int conf_write_autoconf(void)
                return 1;
        }
 
-       time(&now);
-       fprintf(out, "#\n"
-                    "# Automatically generated make config: don't edit\n"
-                    "# L4Re version: %s\n"
-                    "# %s"
-                    "#\n",
-                    rootmenu.prompt->text, ctime(&now));
-       fprintf(tristate, "#\n"
-                         "# Automatically generated - do not edit\n"
-                         "\n");
-       fprintf(out_h, "/*\n"
-                      " * Automatically generated C config: don't edit\n"
-                      " * L4Re version: %s\n"
-                      " * %s"
-                      " */\n"
-                      "#define AUTOCONF_INCLUDED\n",
-                      rootmenu.prompt->text, ctime(&now));
+       conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+       conf_write_heading(tristate, &tristate_printer_cb, NULL);
+
+       conf_write_heading(out_h, &header_printer_cb, NULL);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
                if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
                        continue;
 
-               /* write symbol to config file */
-               conf_write_symbol(sym, sym->type, out, false);
+               /* write symbol to auto.conf, tristate and header files */
+               conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
 
-               /* update autoconf and tristate files */
-               switch (sym->type) {
-               case S_BOOLEAN:
-               case S_TRISTATE:
-                       switch (sym_get_tristate_value(sym)) {
-                       case no:
-                               break;
-                       case mod:
-                               fprintf(tristate, "%s%s=M\n",
-                                   CONFIG_, sym->name);
-                               fprintf(out_h, "#define %s%s_MODULE 1\n",
-                                   CONFIG_, sym->name);
-                               break;
-                       case yes:
-                               if (sym->type == S_TRISTATE)
-                                       fprintf(tristate,"%s%s=Y\n",
-                                           CONFIG_, sym->name);
-                               fprintf(out_h, "#define %s%s 1\n",
-                                   CONFIG_, sym->name);
-                               break;
-                       }
-                       break;
-               case S_STRING:
-                       conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
-                       break;
-               case S_HEX:
-                       str = sym_get_string_value(sym);
-                       if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
-                               fprintf(out_h, "#define %s%s 0x%s\n",
-                                   CONFIG_, sym->name, str);
-                               break;
-                       }
-               case S_INT:
-                       str = sym_get_string_value(sym);
-                       fprintf(out_h, "#define %s%s %s\n",
-                           CONFIG_, sym->name, str);
-                       break;
-               default:
-                       break;
-               }
+               conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
+
+               conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
        }
        fclose(out);
        fclose(tristate);
@@ -938,7 +1048,7 @@ void conf_set_changed_callback(void (*fn)(void))
        conf_changed_callback = fn;
 }
 
-static void randomize_choice_values(struct symbol *csym)
+static bool randomize_choice_values(struct symbol *csym)
 {
        struct property *prop;
        struct symbol *sym;
@@ -946,12 +1056,12 @@ static void randomize_choice_values(struct symbol *csym)
        int cnt, def;
 
        /*
-        * If choice is mod then we may have more items slected
+        * If choice is mod then we may have more items selected
         * and if no then no-one.
         * In both cases stop.
         */
        if (csym->curr.tri != yes)
-               return;
+               return false;
 
        prop = sym_get_choice_prop(csym);
 
@@ -975,13 +1085,18 @@ static void randomize_choice_values(struct symbol *csym)
                else {
                        sym->def[S_DEF_USER].tri = no;
                }
+               sym->flags |= SYMBOL_DEF_USER;
+               /* clear VALID to get value calculated */
+               sym->flags &= ~SYMBOL_VALID;
        }
        csym->flags |= SYMBOL_DEF_USER;
        /* clear VALID to get value calculated */
        csym->flags &= ~(SYMBOL_VALID);
+
+       return true;
 }
 
-static void set_all_choice_values(struct symbol *csym)
+void set_all_choice_values(struct symbol *csym)
 {
        struct property *prop;
        struct symbol *sym;
@@ -998,20 +1113,66 @@ static void set_all_choice_values(struct symbol *csym)
        }
        csym->flags |= SYMBOL_DEF_USER;
        /* clear VALID to get value calculated */
-       csym->flags &= ~(SYMBOL_VALID);
+       csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES);
 }
 
-void conf_set_all_new_symbols(enum conf_def_mode mode)
+bool conf_set_all_new_symbols(enum conf_def_mode mode)
 {
        struct symbol *sym, *csym;
-       int i, cnt;
+       int i, cnt, pby, pty, ptm;      /* pby: probability of boolean  = y
+                                        * pty: probability of tristate = y
+                                        * ptm: probability of tristate = m
+                                        */
+
+       pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
+                                  * below, otherwise gcc whines about
+                                  * -Wmaybe-uninitialized */
+       if (mode == def_random) {
+               int n, p[3];
+               char *env = getenv("KCONFIG_PROBABILITY");
+               n = 0;
+               while( env && *env ) {
+                       char *endp;
+                       int tmp = strtol( env, &endp, 10 );
+                       if( tmp >= 0 && tmp <= 100 ) {
+                               p[n++] = tmp;
+                       } else {
+                               errno = ERANGE;
+                               perror( "KCONFIG_PROBABILITY" );
+                               exit( 1 );
+                       }
+                       env = (*endp == ':') ? endp+1 : endp;
+                       if( n >=3 ) {
+                               break;
+                       }
+               }
+               switch( n ) {
+               case 1:
+                       pby = p[0]; ptm = pby/2; pty = pby-ptm;
+                       break;
+               case 2:
+                       pty = p[0]; ptm = p[1]; pby = pty + ptm;
+                       break;
+               case 3:
+                       pby = p[0]; pty = p[1]; ptm = p[2];
+                       break;
+               }
+
+               if( pty+ptm > 100 ) {
+                       errno = ERANGE;
+                       perror( "KCONFIG_PROBABILITY" );
+                       exit( 1 );
+               }
+       }
+       bool has_changed = false;
 
        for_all_symbols(i, sym) {
-               if (sym_has_value(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;
@@ -1020,11 +1181,21 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
                                sym->def[S_DEF_USER].tri = mod;
                                break;
                        case def_no:
-                               sym->def[S_DEF_USER].tri = no;
+                               if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
+                                       sym->def[S_DEF_USER].tri = yes;
+                               else
+                                       sym->def[S_DEF_USER].tri = no;
                                break;
                        case def_random:
-                               cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
-                               sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
+                               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;
@@ -1042,21 +1213,33 @@ void conf_set_all_new_symbols(enum conf_def_mode mode)
 
        /*
         * We have different type of choice blocks.
-        * If curr.tri equal to mod then we can select several
+        * 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 equal yes then only one symbol can be
+        * 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;
+               }
+       }
+
        for_all_symbols(i, csym) {
                if (sym_has_value(csym) || !sym_is_choice(csym))
                        continue;
 
                sym_calc_value(csym);
                if (mode == def_random)
-                       randomize_choice_values(csym);
-               else
+                       has_changed = randomize_choice_values(csym);
+               else {
                        set_all_choice_values(csym);
+                       has_changed = true;
+               }
        }
+
+       return has_changed;
 }