diff options
Diffstat (limited to 'scripts/kconfig/confdata.c')
-rw-r--r-- | scripts/kconfig/confdata.c | 537 |
1 files changed, 385 insertions, 152 deletions
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 2b8f140635..73afcbafd3 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -41,6 +41,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; @@ -83,6 +90,68 @@ char *conf_get_default_confname(void) return 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; @@ -101,8 +170,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 || @@ -161,7 +233,7 @@ load: if (def == S_DEF_USER) { sym = sym_find(line + 9); if (!sym) { - conf_warning("trying to assign nonexistent symbol %s", line + 9); + sym_add_change_count(1); break; } } else { @@ -170,8 +242,7 @@ load: sym->type = S_BOOLEAN; } if (sym->flags & def_flags) { - conf_warning("trying to reassign symbol %s", sym->name); - break; + conf_warning("override: reassigning to symbol %s", sym->name); } switch (sym->type) { case S_BOOLEAN: @@ -201,7 +272,7 @@ load: if (def == S_DEF_USER) { sym = sym_find(line + 7); if (!sym) { - conf_warning("trying to assign nonexistent symbol %s", line + 7); + sym_add_change_count(1); break; } } else { @@ -210,64 +281,10 @@ load: sym->type = S_OTHER; } if (sym->flags & def_flags) { - conf_warning("trying to reassign symbol %s", sym->name); - break; - } - 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"); - continue; - } - 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); - continue; - } - break; - default: - ; + 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': @@ -288,14 +305,12 @@ load: } break; case yes: - if (cs->def[def].tri != no) { - conf_warning("%s creates inconsistent choice state", sym->name); - cs->flags &= ~def_flags; - } else - cs->def[def].val = sym; + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; break; } - cs->def[def].tri = E_OR(cs->def[def].tri, sym->def[def].tri); + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); } } fclose(in); @@ -307,7 +322,7 @@ load: int conf_read(const char *name) { - struct symbol *sym; + struct symbol *sym, *choice_sym; struct property *prop; struct expr *e; int i, flags; @@ -348,9 +363,9 @@ int conf_read(const char *name) */ prop = sym_get_choice_prop(sym); flags = sym->flags; - for (e = prop->expr; e; e = e->left.expr) - if (e->right.sym->visible != no) - flags &= e->right.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; } @@ -384,15 +399,148 @@ 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) +{ + int l; + if (headerfile) + fprintf(out, "#define CONFIG_%s \"", name); + else + fprintf(out, "CONFIG_%s=\"", name); + + while (1) { + l = strcspn(str, "\"\\"); + if (l) { + xfwrite(str, l, 1, out); + str += l; + } + if (!*str) + 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) +{ + const char *str; + + switch (type) { + case S_BOOLEAN: + case S_TRISTATE: + switch (sym_get_tristate_value(sym)) { + case no: + if (write_no) + fprintf(out, "# CONFIG_%s is not set\n", sym->name); + break; + case mod: + fprintf(out, "CONFIG_%s=m\n", sym->name); + break; + case yes: + fprintf(out, "CONFIG_%s=y\n", sym->name); + break; + } + break; + case S_STRING: + conf_write_string(false, sym->name, sym_get_string_value(sym), out); + break; + case S_HEX: + case S_INT: + str = sym_get_string_value(sym); + fprintf(out, "CONFIG_%s=%s\n", sym->name, str); + break; + case S_OTHER: + case S_UNKNOWN: + break; + } +} + +/* + * 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" . + */ + 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 == ds) { + if ((sym->type == S_BOOLEAN) && + sym_get_tristate_value(sym) == yes) + goto next_menu; + } + } + conf_write_symbol(sym, sym->type, out, true); + } +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; + char dirname[128], tmpname[128], newname[128]; + enum symbol_type type; time_t now; int use_timestamp = 1; char *env; @@ -440,7 +588,7 @@ int conf_write(const char *name) fprintf(out, _("#\n" "# Automatically generated make config: don't edit\n" - "# barebox version: %s\n" + "# Linux barebox version: %s\n" "%s%s" "#\n"), sym_get_string_value(sym), @@ -472,50 +620,11 @@ int conf_write(const char *name) 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, "# CONFIG_%s is not set\n", sym->name); - break; - case mod: - fprintf(out, "CONFIG_%s=m\n", sym->name); - break; - case yes: - fprintf(out, "CONFIG_%s=y\n", sym->name); - break; - } - break; - case S_STRING: - str = sym_get_string_value(sym); - fprintf(out, "CONFIG_%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, "CONFIG_%s=%s\n", sym->name, str); - break; - } - case S_INT: - str = sym_get_string_value(sym); - fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - break; - } + /* Write config symbol to file */ + conf_write_symbol(sym, type, out, true); } - next: +next: if (menu->list) { menu = menu->list; continue; @@ -548,17 +657,16 @@ int conf_write(const char *name) return 0; } -int conf_split_config(void) +static int conf_split_config(void) { - char *name, path[128]; + const char *name; + char path[128]; 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"; + name = conf_get_autoconfig_name(); conf_read_simple(name, S_DEF_AUTO); if (chdir("include/config")) @@ -665,10 +773,10 @@ int conf_write_autoconf(void) { struct symbol *sym; const char *str; - char *name; - FILE *out, *out_h; + const char *name; + FILE *out, *tristate, *out_h; time_t now; - int i, l; + int i; sym_clear_all_valid(); @@ -681,9 +789,16 @@ int conf_write_autoconf(void) if (!out) return 1; + tristate = fopen(".tmpconfig_tristate", "w"); + if (!tristate) { + fclose(out); + return 1; + } + out_h = fopen(".tmpconfig.h", "w"); if (!out_h) { fclose(out); + fclose(tristate); return 1; } @@ -692,13 +807,16 @@ int conf_write_autoconf(void) time(&now); fprintf(out, "#\n" "# Automatically generated make config: don't edit\n" - "# barebox version: %s\n" + "# Linux barebox 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" - " * barebox version: %s\n" + " * Linux barebox version: %s\n" " * %s" " */\n" "#define AUTOCONF_INCLUDED\n", @@ -708,6 +826,11 @@ int conf_write_autoconf(void) 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); + + /* update autoconf and tristate files */ switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: @@ -715,45 +838,28 @@ int conf_write_autoconf(void) 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); + 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, "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: @@ -761,16 +867,20 @@ int conf_write_autoconf(void) } } fclose(out); + fclose(tristate); fclose(out_h); name = getenv("KCONFIG_AUTOHEADER"); if (!name) - name = "include/linux/autoconf.h"; + name = "include/generated/autoconf.h"; if (rename(".tmpconfig.h", 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(".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. @@ -807,3 +917,126 @@ void conf_set_changed_callback(void (*fn)(void)) { conf_changed_callback = fn; } + +static void 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 slected + * and if no then no-one. + * In both cases stop. + */ + if (csym->curr.tri != yes) + return; + + 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); +} + +static void set_all_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + + prop = sym_get_choice_prop(csym); + + /* + * Set all non-assinged choice values to no + */ + expr_list_for_each_sym(prop->expr, e, sym) { + if (!sym_has_value(sym)) + sym->def[S_DEF_USER].tri = no; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~(SYMBOL_VALID); +} + +void conf_set_all_new_symbols(enum conf_def_mode mode) +{ + struct symbol *sym, *csym; + int i, cnt; + + 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: + cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2; + sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt); + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + + } + + sym_clear_all_valid(); + + /* + * 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 (mode == def_random) + randomize_choice_values(csym); + else + set_all_choice_values(csym); + } +} |