diff options
Diffstat (limited to 'extra/config/confdata.c')
-rw-r--r-- | extra/config/confdata.c | 869 |
1 files changed, 604 insertions, 265 deletions
diff --git a/extra/config/confdata.c b/extra/config/confdata.c index 2b848d5d0..61c91c248 100644 --- a/extra/config/confdata.c +++ b/extra/config/confdata.c @@ -5,24 +5,27 @@ #include <sys/stat.h> #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> -#include <libgen.h> -#define LKC_DIRECT_LINK #include "lkc.h" static void conf_warning(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +static void conf_message(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + static const char *conf_filename; static int conf_lineno, conf_warnings, conf_unsaved; -const char conf_defname[] = "extra/Configs/defconfigs/$ARCH"; +const char conf_defname[] = "arch/$ARCH/defconfig"; static void conf_warning(const char *fmt, ...) { @@ -35,6 +38,29 @@ static void conf_warning(const char *fmt, ...) conf_warnings++; } +static void conf_default_message_callback(const char *fmt, va_list ap) +{ + printf("#\n# "); + vprintf(fmt, ap); + printf("\n#\n"); +} + +static void (*conf_message_callback) (const char *fmt, va_list ap) = + conf_default_message_callback; +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +{ + conf_message_callback = fn; +} + +static void conf_message(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (conf_message_callback) + conf_message_callback(fmt, ap); +} + const char *conf_get_configname(void) { char *name = getenv("KCONFIG_CONFIG"); @@ -42,6 +68,13 @@ const char *conf_get_configname(void) 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; @@ -95,6 +128,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; @@ -107,7 +141,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) break; } conf_warning("symbol value '%s' invalid for %s", p, sym->name); - break; + return 1; case S_OTHER: if (*p != '"') { for (p2 = p; *p2 && !isspace(*p2); p2++) @@ -115,6 +149,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; @@ -129,6 +164,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) conf_warning("invalid string found"); return 1; } + /* fall through */ case S_INT: case S_HEX: done: @@ -146,10 +182,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; @@ -164,8 +256,11 @@ int conf_read_simple(const char *name, int def) if (in) goto load; sym_add_change_count(1); - if (!sym_defconfig_list) + if (!sym_defconfig_list) { + if (modules_sym) + sym_calc_value(modules_sym); return 1; + } for_all_defaults(sym_defconfig_list, prop) { if (expr_calc_value(prop->visible.expr) == no || @@ -174,9 +269,8 @@ int conf_read_simple(const char *name, int def) 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); + conf_message(_("using defaults found in %s"), + name); goto load; } } @@ -202,33 +296,33 @@ 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; - switch (line[0]) { - case '#': - if (line[1] != ' ') + if (line[0] == '#') { + if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) continue; - p = strchr(line + 2, ' '); + p = strchr(line + 2 + strlen(CONFIG_), ' '); if (!p) continue; *p++ = 0; if (strncmp(p, "is not set", 10)) continue; if (def == S_DEF_USER) { - sym = sym_find(line + 2); + sym = sym_find(line + 2 + strlen(CONFIG_)); if (!sym) { sym_add_change_count(1); - break; + goto setsym; } } else { - sym = sym_lookup(line + 2, 0); + sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); if (sym->type == S_UNKNOWN) sym->type = S_BOOLEAN; } @@ -244,13 +338,10 @@ load: default: ; } - break; - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - p = strchr(line, '='); - if (!p) { - conf_warning("unexpected data '%s'", line); + } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { + p = strchr(line + strlen(CONFIG_), '='); + if (!p) continue; - } *p++ = 0; p2 = strchr(p, '\n'); if (p2) { @@ -259,13 +350,13 @@ load: *p2 = 0; } if (def == S_DEF_USER) { - sym = sym_find(line); + sym = sym_find(line + strlen(CONFIG_)); if (!sym) { sym_add_change_count(1); - break; + goto setsym; } } else { - sym = sym_lookup(line, 0); + sym = sym_lookup(line + strlen(CONFIG_), 0); if (sym->type == S_UNKNOWN) sym->type = S_OTHER; } @@ -274,14 +365,12 @@ load: } if (conf_set_sym_val(sym, def, def_flags, p)) continue; - break; - case '\r': - case '\n': - break; - default: - conf_warning("unexpected data"); + } else { + if (line[0] != '\r' && line[0] != '\n') + conf_warning("unexpected data"); 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) { @@ -302,6 +391,7 @@ load: cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); } } + free(line); fclose(in); if (modules_sym) @@ -311,10 +401,8 @@ load: 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); @@ -324,7 +412,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) { @@ -333,29 +421,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) { @@ -388,43 +465,300 @@ int conf_read(const char *name) return 0; } +/* + * 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) +{ + const char *p = value; + size_t l; + + 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; + } +} + +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) +{ + + switch (sym->type) { + case S_BOOLEAN: + 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_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_STRING: + case S_INT: + 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. + */ +int conf_write_defconfig(const char *filename) +{ + struct symbol *sym; + struct menu *menu; + FILE *out; + + out = fopen(filename, "w"); + if (!out) + return 1; + + sym_clear_all_valid(); + + /* Traverse all menus to find all relevant symbols */ + menu = rootmenu.list; + + 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_changable(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; + } + } + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + } +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; + } + } + } + } + fclose(out); + return 0; +} + int conf_write(const char *name) { FILE *out; struct symbol *sym; struct menu *menu; const char *basename; - char dirname[128], tmpname[128], newname[128]; - int type, l; const char *str; - time_t now; - int use_timestamp = 1; - char *env; + char tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char *env, *dirname = NULL; - dirname[0] = 0; - if (name == NULL) - name = conf_get_configname(); if (name && name[0]) { struct stat st; char *slash; if (!stat(name, &st) && S_ISDIR(st.st_mode)) { - strcpy(dirname, name); + dirname = strndup(name, strlen(name) + 1); strcat(dirname, "/"); basename = conf_get_configname(); } else if ((slash = strrchr(name, '/'))) { int size = slash - name + 1; - memcpy(dirname, name, size); - dirname[size] = 0; + dirname = strndup(name, size); if (slash[1]) basename = slash + 1; else basename = conf_get_configname(); } else basename = name; - } else - basename = conf_get_configname(); - + } else { + dirname = strdup(conf_get_configname()); + basename = strdup(base_name(dirname)); + dirname = dir_name(dirname); + } sprintf(newname, "%s%s", dirname, basename); env = getenv("KCONFIG_OVERWRITECONFIG"); if (!env || !*env) { @@ -434,24 +768,11 @@ int conf_write(const char *name) *tmpname = 0; out = fopen(newname, "w"); } + free(dirname); if (!out) return 1; - sym = sym_lookup("VERSION", 0); - sym_calc_value(sym); - time(&now); - env = getenv("KCONFIG_NOTIMESTAMP"); - if (env && *env) - use_timestamp = 0; - - fprintf(out, _("#\n" - "# Automatically generated make config: don't edit\n" - "# Version: %s\n" - "%s%s" - "#\n"), - sym_get_string_value(sym), - use_timestamp ? "# " : "", - use_timestamp ? ctime(&now) : ""); + conf_write_heading(out, &kconfig_printer_cb, NULL); if (!conf_get_changed()) sym_clear_all_valid(); @@ -472,56 +793,11 @@ 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; - } - switch (type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (sym_get_tristate_value(sym)) { - case no: - fprintf(out, "# %s is not set\n", sym->name); - break; - case mod: - fprintf(out, "%s=m\n", sym->name); - break; - case yes: - fprintf(out, "%s=y\n", sym->name); - break; - } - break; - case S_STRING: - str = sym_get_string_value(sym); - fprintf(out, "%s=\"", sym->name); - while (1) { - l = strcspn(str, "\"\\"); - if (l) { - fwrite(str, l, 1, out); - str += l; - } - if (!*str) - break; - fprintf(out, "\\%c", *str++); - } - fputs("\"\n", out); - break; - case S_HEX: - str = sym_get_string_value(sym); - if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { - fprintf(out, "%s=%s\n", sym->name, str); - break; - } - case S_INT: - str = sym_get_string_value(sym); - fprintf(out, "%s=%s\n", sym->name, str); - break; - } + + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); } - next: +next: if (menu->list) { menu = menu->list; continue; @@ -538,38 +814,39 @@ int conf_write(const char *name) fclose(out); if (*tmpname) { - strcat(dirname, basename); + dirname = strndup(basename, strlen(basename) + 4); strcat(dirname, ".old"); rename(newname, dirname); + free(dirname); if (rename(tmpname, newname)) return 1; } - printf(_("#\n" - "# configuration written to %s\n" - "#\n"), newname); + conf_message(_("configuration written to %s"), newname); sym_set_change_count(0); return 0; } -int conf_split_config(void) +static int conf_split_config(void) { - char *name, path[128], opwd[512]; + const char *name; + char path[PATH_MAX+1], opwd[PATH_MAX+1]; char *s, *d, c; struct symbol *sym; struct stat sb; int res, i, fd; - name = getenv("KCONFIG_AUTOCONFIG"); - if (!name) - name = "include/config/auto.conf"; - conf_read_simple(name, S_DEF_AUTO); - if (getcwd(opwd, sizeof(opwd)) == NULL) return 1; - if (chdir(dirname(strdup(name)))) + name = conf_get_autoconfig_name(); + conf_read_simple(name, S_DEF_AUTO); + + strcpy(path, name); + dir_name(path); + + if (chdir(path)) return 1; res = 0; @@ -671,126 +948,85 @@ out: int conf_write_autoconf(void) { - char opwd[512]; struct symbol *sym; - const char *str; - char *name; - FILE *out, *out_h; - time_t now; - int i, l; + const char *name; + char cfg_fname[PATH_MAX+1], tristate_fname[PATH_MAX+1], + cfgh_fname[PATH_MAX+1]; + char *dirname; + FILE *out, *tristate, *out_h; + int i; - if (getcwd(opwd, sizeof(opwd)) == NULL) - return 1; - if (chdir(dirname(strdup(conf_get_configname())))) - return 1; sym_clear_all_valid(); - file_write_dep("include/config/auto.conf.cmd"); + sprintf(cfg_fname, "%s.cmd", conf_get_autoconfig_name()); + file_write_dep(cfg_fname); if (conf_split_config()) return 1; - out = fopen(".tmpconfig", "w"); + dirname = dir_name(strdup(conf_get_configname())); + sprintf(cfg_fname, "%s.tmpconfig", dirname); + sprintf(tristate_fname, "%s.tmpconfig_tristate", dirname); + sprintf(cfgh_fname, "%s.tmpconfig.h", dirname); + free(dirname); + + out = fopen(cfg_fname, "w"); if (!out) return 1; - out_h = fopen(".tmpconfig.h", "w"); + tristate = fopen(tristate_fname, "w"); + if (!tristate) { + fclose(out); + return 1; + } + + out_h = fopen(cfgh_fname, "w"); if (!out_h) { fclose(out); + fclose(tristate); return 1; } - sym = sym_lookup("VERSION", 0); - sym_calc_value(sym); - time(&now); - fprintf(out, "#\n" - "# Automatically generated make config: don't edit\n" - "# Version: %s\n" - "# %s" - "#\n", - sym_get_string_value(sym), ctime(&now)); - fprintf(out_h, "/*\n" - " * Automatically generated C config: don't edit\n" - " * Version: %s\n" - " * %s" - " */\n" - "#define AUTOCONF_INCLUDED\n", - sym_get_string_value(sym), 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; - 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(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); - break; - case yes: - fprintf(out, "%s=y\n", sym->name); - fprintf(out_h, "#define %s 1\n", sym->name); - break; - } - break; - case S_STRING: - str = sym_get_string_value(sym); - fprintf(out, "%s=\"", sym->name); - fprintf(out_h, "#define %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, "%s=%s\n", sym->name, str); - fprintf(out_h, "#define %s 0x%s\n", sym->name, str); - break; - } - case S_INT: - str = sym_get_string_value(sym); - fprintf(out, "%s=%s\n", sym->name, str); - fprintf(out_h, "#define %s %s\n", sym->name, str); - break; - default: - break; - } + + /* write symbol to auto.conf, tristate and header files */ + conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); + + conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + + conf_write_symbol(out_h, sym, &header_printer_cb, NULL); } fclose(out); + fclose(tristate); fclose(out_h); name = getenv("KCONFIG_AUTOHEADER"); if (!name) - name = "include/config/autoconf.h"; - if (rename(".tmpconfig.h", name)) + name = "include/generated/autoconf.h"; + if (rename(cfgh_fname, name)) return 1; - name = getenv("KCONFIG_AUTOCONFIG"); + name = getenv("KCONFIG_TRISTATE"); if (!name) - name = "include/config/auto.conf"; + name = "include/config/tristate.conf"; + if (rename(tristate_fname, 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(cfg_fname, name)) return 1; - chdir(opwd); + return 0; } @@ -821,20 +1057,131 @@ void conf_set_changed_callback(void (*fn)(void)) conf_changed_callback = fn; } +static bool randomize_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + int cnt, def; + + /* + * 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 false; + + prop = sym_get_choice_prop(csym); -void conf_set_all_new_symbols(enum conf_def_mode mode) + /* 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; + } + 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; +} + +void set_all_choice_values(struct symbol *csym) { - struct symbol *sym, *csym; struct property *prop; + struct symbol *sym; struct expr *e; - int i, cnt, def; + + 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); +} + +bool conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + 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; @@ -846,7 +1193,15 @@ void conf_set_all_new_symbols(enum conf_def_mode mode) sym->def[S_DEF_USER].tri = no; break; case def_random: - sym->def[S_DEF_USER].tri = (tristate)(rand() % 3); + 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; @@ -862,51 +1217,35 @@ void conf_set_all_new_symbols(enum conf_def_mode mode) 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 + * 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 (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; - } + if (mode == def_random) + has_changed = randomize_choice_values(csym); + else { + set_all_choice_values(csym); + has_changed = true; } - csym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - csym->flags &= ~(SYMBOL_VALID); } + + return has_changed; } |