+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
*/
+#include <sys/mman.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "lkc.h"
+/* return true if 'path' exists, false otherwise */
+static bool is_present(const char *path)
+{
+ struct stat st;
+
+ return !stat(path, &st);
+}
+
+/* return true if 'path' exists and it is a directory, false otherwise */
+static bool is_dir(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st))
+ return 0;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* return true if the given two files are the same, false otherwise */
+static bool is_same(const char *file1, const char *file2)
+{
+ int fd1, fd2;
+ struct stat st1, st2;
+ void *map1, *map2;
+ bool ret = false;
+
+ fd1 = open(file1, O_RDONLY);
+ if (fd1 < 0)
+ return ret;
+
+ fd2 = open(file2, O_RDONLY);
+ if (fd2 < 0)
+ goto close1;
+
+ ret = fstat(fd1, &st1);
+ if (ret)
+ goto close2;
+ ret = fstat(fd2, &st2);
+ if (ret)
+ goto close2;
+
+ if (st1.st_size != st2.st_size)
+ goto close2;
+
+ map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if (map1 == MAP_FAILED)
+ goto close2;
+
+ map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if (map2 == MAP_FAILED)
+ goto close2;
+
+ if (bcmp(map1, map2, st1.st_size))
+ goto close2;
+
+ ret = true;
+close2:
+ close(fd2);
+close1:
+ close(fd1);
+
+ return ret;
+}
+
+/*
+ * Create the parent directory of the given path.
+ *
+ * For example, if 'include/config/auto.conf' is given, create 'include/config'.
+ */
+static int make_parent_dir(const char *path)
+{
+ char tmp[PATH_MAX + 1];
+ char *p;
+
+ strncpy(tmp, path, sizeof(tmp));
+ tmp[sizeof(tmp) - 1] = 0;
+
+ /* Remove the base name. Just return if nothing is left */
+ p = strrchr(tmp, '/');
+ if (!p)
+ return 0;
+ *(p + 1) = 0;
+
+ /* Just in case it is an absolute path */
+ p = tmp;
+ while (*p == '/')
+ p++;
+
+ while ((p = strchr(p, '/'))) {
+ *p = 0;
+
+ /* skip if the directory exists */
+ if (!is_dir(tmp) && mkdir(tmp, 0755))
+ return -1;
+
+ *p = '/';
+ while (*p == '/')
+ p++;
+ }
+
+ return 0;
+}
+
+static char depfile_path[PATH_MAX];
+static size_t depfile_prefix_len;
+
+/* touch depfile for symbol 'name' */
+static int conf_touch_dep(const char *name)
+{
+ int fd, ret;
+ const char *s;
+ char *d, c;
+
+ /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
+ if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
+ return -1;
+
+ d = depfile_path + depfile_prefix_len;
+ s = name;
+
+ while ((c = *s++))
+ *d++ = (c == '_') ? '/' : tolower(c);
+ strcpy(d, ".h");
+
+ /* Assume directory path already exists. */
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ if (errno != ENOENT)
+ return -1;
+
+ ret = make_parent_dir(depfile_path);
+ if (ret)
+ return ret;
+
+ /* Try it again. */
+ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ return -1;
+ }
+ close(fd);
+
+ return 0;
+}
+
+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)));
__attribute__ ((format (printf, 1, 2)));
static const char *conf_filename;
-static int conf_lineno, conf_warnings, conf_unsaved;
-
-const char conf_defname[] = "include/generated/defconfig";
+static int conf_lineno, conf_warnings;
static void conf_warning(const char *fmt, ...)
{
conf_warnings++;
}
-static void conf_default_message_callback(const char *fmt, va_list ap)
+static void conf_default_message_callback(const char *s)
{
printf("#\n# ");
- vprintf(fmt, ap);
+ printf("%s", s);
printf("\n#\n");
}
-static void (*conf_message_callback) (const char *fmt, va_list ap) =
+static void (*conf_message_callback)(const char *s) =
conf_default_message_callback;
-void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
+void conf_set_message_callback(void (*fn)(const char *s))
{
conf_message_callback = fn;
}
static void conf_message(const char *fmt, ...)
{
va_list ap;
+ char buf[4096];
+
+ if (!conf_message_callback)
+ return;
va_start(ap, fmt);
- if (conf_message_callback)
- conf_message_callback(fmt, ap);
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ conf_message_callback(buf);
+ va_end(ap);
}
const char *conf_get_configname(void)
return name ? name : ".config";
}
-const char *conf_get_autoconfig_name(void)
+static const char *conf_get_autoconfig_name(void)
{
char *name = getenv("KCONFIG_AUTOCONFIG");
return name ? name : "include/generated/auto.conf";
}
-static char *conf_expand_value(const char *in)
-{
- struct symbol *sym;
- const char *src;
- static char res_value[SYMBOL_MAXLENGTH];
- char *dst, name[SYMBOL_MAXLENGTH];
-
- res_value[0] = 0;
- dst = name;
- while ((src = strchr(in, '$'))) {
- strncat(res_value, in, src - in);
- src++;
- dst = name;
- while (isalnum(*src) || *src == '_')
- *dst++ = *src++;
- *dst = 0;
- sym = sym_lookup(name, 0);
- sym_calc_value(sym);
- strcat(res_value, sym_get_string_value(sym));
- in = src;
- }
- strcat(res_value, in);
-
- return res_value;
-}
-
-char *conf_get_default_confname(void)
-{
- struct stat buf;
- static char fullname[PATH_MAX+1];
- char *env, *name;
-
- name = conf_expand_value(conf_defname);
- env = getenv(SRCTREE);
- if (env) {
- sprintf(fullname, "%s/%s", env, name);
- if (!stat(fullname, &buf))
- return fullname;
- }
- return name;
-}
-
static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
{
char *p2;
sym->flags |= def_flags;
break;
}
- 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;
- case S_OTHER:
- if (*p != '"') {
- for (p2 = p; *p2 && !isspace(*p2); p2++)
- ;
- sym->type = S_STRING;
- goto done;
- }
- /* fall through */
case S_STRING:
if (*p++ != '"')
break;
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:
if (sym_string_valid(sym, p)) {
- sym->def[def].val = strdup(p);
+ sym->def[def].val = xstrdup(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;
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 = xrealloc(*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;
if (in)
goto load;
sym_add_change_count(1);
- if (!sym_defconfig_list) {
- if (modules_sym)
- sym_calc_value(modules_sym);
+ 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);
+ sym_calc_value(prop->expr->left.sym);
+ name = sym_get_string_value(prop->expr->left.sym);
in = zconf_fopen(name);
if (in) {
- conf_message(_("using defaults found in %s"),
+ conf_message("using defaults found in %s",
name);
goto load;
}
conf_filename = name;
conf_lineno = 0;
conf_warnings = 0;
- conf_unsaved = 0;
def_flags = SYMBOL_DEF << def;
for_all_symbols(i, sym) {
}
}
- while (fgets(line, sizeof(line), in)) {
+ while (compat_getline(&line, &line_asize, in) != -1) {
conf_lineno++;
sym = NULL;
if (line[0] == '#') {
sym = sym_find(line + 2 + strlen(CONFIG_));
if (!sym) {
sym_add_change_count(1);
- goto setsym;
+ continue;
}
} else {
sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
if (*p2 == '\r')
*p2 = 0;
}
- if (def == S_DEF_USER) {
- sym = sym_find(line + strlen(CONFIG_));
- if (!sym) {
+
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ if (def == S_DEF_AUTO)
+ /*
+ * Reading from include/config/auto.conf
+ * If CONFIG_FOO previously existed in
+ * auto.conf but it is missing now,
+ * include/config/foo.h must be touched.
+ */
+ conf_touch_dep(line + strlen(CONFIG_));
+ else
sym_add_change_count(1);
- goto setsym;
- }
- } else {
- sym = sym_lookup(line + strlen(CONFIG_), 0);
- if (sym->type == S_UNKNOWN)
- sym->type = S_OTHER;
+ continue;
}
+
if (sym->flags & def_flags) {
conf_warning("override: reassigning to symbol %s", sym->name);
}
continue;
} else {
if (line[0] != '\r' && line[0] != '\n')
- conf_warning("unexpected data");
+ conf_warning("unexpected data: %.*s",
+ (int)strcspn(line, "\r\n"), line);
+
continue;
}
-setsym:
+
if (sym && sym_is_choice_value(sym)) {
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
switch (sym->def[def].tri) {
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;
+ int conf_unsaved = 0;
int i;
sym_set_change_count(0);
- if (conf_read_simple(name, S_DEF_USER))
+ if (conf_read_simple(name, S_DEF_USER)) {
+ sym_calc_value(modules_sym);
return 1;
+ }
+
+ sym_calc_value(modules_sym);
for_all_symbols(i, sym) {
sym_calc_value(sym);
- if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
continue;
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
/* check that calculated value agrees with saved value */
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
- if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
- break;
- if (!sym_is_choice(sym))
+ if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
continue;
- /* fall through */
+ break;
default:
if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
continue;
fprintf(fp, "#define %s%s%s 1\n",
CONFIG_, sym->name, suffix);
}
- /*
- * Generate the __enabled_CONFIG_* and
- * __enabled_CONFIG_*_MODULE macros for use by the
- * IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is
- * generated even for booleans so that the IS_ENABLED() macro
- * works.
- */
- fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n",
- sym->name, (*value == 'y'));
- fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n",
- sym->name, (*value == 'm'));
break;
}
case S_HEX: {
const char *str;
switch (sym->type) {
- case S_OTHER:
case S_UNKNOWN:
break;
case S_STRING:
goto next_menu;
sym->flags &= ~SYMBOL_WRITE;
/* If we cannot change the symbol - skip */
- if (!sym_is_changable(sym))
+ 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)
FILE *out;
struct symbol *sym;
struct menu *menu;
- const char *basename;
const char *str;
- char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
+ char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
char *env;
+ int i;
+ bool need_newline = false;
+
+ if (!name)
+ name = conf_get_configname();
+
+ if (!*name) {
+ fprintf(stderr, "config name is empty\n");
+ return -1;
+ }
+
+ if (is_dir(name)) {
+ fprintf(stderr, "%s: Is a directory\n", name);
+ return -1;
+ }
+
+ if (make_parent_dir(name))
+ return -1;
- dirname[0] = 0;
- if (name && name[0]) {
- struct stat st;
- char *slash;
-
- if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
- strcpy(dirname, name);
- strcat(dirname, "/");
- basename = conf_get_configname();
- } else if ((slash = strrchr(name, '/'))) {
- int size = slash - name + 1;
- memcpy(dirname, name, size);
- dirname[size] = 0;
- if (slash[1])
- basename = slash + 1;
- else
- basename = conf_get_configname();
- } else
- basename = name;
- } else
- basename = conf_get_configname();
-
- 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 {
+ if (env && *env) {
*tmpname = 0;
- out = fopen(newname, "w");
+ out = fopen(name, "w");
+ } else {
+ snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
+ name, (int)getpid());
+ out = fopen(tmpname, "w");
}
if (!out)
return 1;
"#\n"
"# %s\n"
"#\n", str);
- } else if (!(sym->flags & SYMBOL_CHOICE)) {
+ need_newline = false;
+ } else if (!(sym->flags & SYMBOL_CHOICE) &&
+ !(sym->flags & SYMBOL_WRITTEN)) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE))
goto next;
- sym->flags &= ~SYMBOL_WRITE;
-
+ if (need_newline) {
+ fprintf(out, "\n");
+ need_newline = false;
+ }
+ sym->flags |= SYMBOL_WRITTEN;
conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
}
if (menu->next)
menu = menu->next;
else while ((menu = menu->parent)) {
+ if (!menu->sym && menu_is_visible(menu) &&
+ menu != &rootmenu) {
+ str = menu_get_prompt(menu);
+ fprintf(out, "# end of %s\n", str);
+ need_newline = true;
+ }
if (menu->next) {
menu = menu->next;
break;
}
fclose(out);
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_WRITTEN;
+
if (*tmpname) {
- strcat(dirname, basename);
- strcat(dirname, ".old");
- rename(newname, dirname);
- if (rename(tmpname, newname))
+ if (is_same(name, tmpname)) {
+ conf_message("No change to %s", name);
+ unlink(tmpname);
+ sym_set_change_count(0);
+ return 0;
+ }
+
+ snprintf(oldname, sizeof(oldname), "%s.old", name);
+ rename(name, oldname);
+ if (rename(tmpname, name))
return 1;
}
- conf_message(_("configuration written to %s"), newname);
+ conf_message("configuration written to %s", name);
sym_set_change_count(0);
return 0;
}
-static int conf_split_config(void)
+/* write a dependency file as used by kbuild to track dependencies */
+static int conf_write_dep(const char *name)
+{
+ struct file *file;
+ FILE *out;
+
+ out = fopen("..config.tmp", "w");
+ if (!out)
+ return 1;
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next) {
+ if (file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+ else
+ fprintf(out, "\t%s\n", file->name);
+ }
+ fprintf(out, "\n%s: \\\n"
+ "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+ env_write_dep(out, conf_get_autoconfig_name());
+
+ fprintf(out, "\n$(deps_config): ;\n");
+ fclose(out);
+
+ if (make_parent_dir(name))
+ return 1;
+ rename("..config.tmp", name);
+ return 0;
+}
+
+static int conf_touch_deps(void)
{
const char *name;
- char path[PATH_MAX+1];
- char *s, *d, c;
struct symbol *sym;
- struct stat sb;
- int res, i, fd;
+ int res, i;
+
+ strcpy(depfile_path, "include/generated/");
+ depfile_prefix_len = strlen(depfile_path);
name = conf_get_autoconfig_name();
conf_read_simple(name, S_DEF_AUTO);
+ sym_calc_value(modules_sym);
- if (chdir("include/generated"))
- return 1;
-
- res = 0;
for_all_symbols(i, sym) {
sym_calc_value(sym);
- if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+ if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name)
continue;
if (sym->flags & SYMBOL_WRITE) {
if (sym->flags & SYMBOL_DEF_AUTO) {
* 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);
+ res = conf_touch_dep(sym->name);
+ if (res)
+ return res;
}
-out:
- if (chdir("../.."))
- return 1;
- return res;
+ return 0;
}
-int conf_write_autoconf(void)
+int conf_write_autoconf(int overwrite)
{
struct symbol *sym;
const char *name;
+ const char *autoconf_name = conf_get_autoconfig_name();
FILE *out, *tristate, *out_h, *out_c;
int i;
- sym_clear_all_valid();
+ if (!overwrite && is_present(autoconf_name))
+ return 0;
- file_write_dep("include/generated/auto.conf.cmd");
+ conf_write_dep("include/generated/auto.conf.cmd");
- if (conf_split_config())
+ if (conf_touch_deps())
return 1;
out = fopen(".tmpconfig", "w");
name = getenv("KCONFIG_AUTOHEADER");
if (!name)
name = "include/generated/autoconf.h";
+ if (make_parent_dir(name))
+ return 1;
if (rename(".tmpconfig.h", name))
return 1;
+
name = getenv("KCONFIG_TRISTATE");
if (!name)
name = "include/generated/tristate.conf";
+ if (make_parent_dir(name))
+ return 1;
if (rename(".tmpconfig_tristate", name))
return 1;
+
+ if (make_parent_dir(autoconf_name))
+ return 1;
+
name = getenv("KCONFIG_CMAKE");
if (!name)
name = "config.cmake";
+ if (make_parent_dir(name))
+ return 1;
if (rename(".tmpconfig.cmake", 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))
+ if (rename(".tmpconfig", autoconf_name))
return 1;
return 0;
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;
* In both cases stop.
*/
if (csym->curr.tri != yes)
- return;
+ return false;
prop = sym_get_choice_prop(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;
}
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 bool = 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;
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;
* 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;
}