yann@1: /* yann@1: * Copyright (C) 2002 Roman Zippel yann@1: * Released under the terms of the GNU GPL v2.0. yann@1: */ yann@1: yann@1: #include yann@1: #include yann@2448: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: yann@1: #define LKC_DIRECT_LINK yann@1: #include "lkc.h" yann@1: yann@1: static void conf_warning(const char *fmt, ...) yann@1: __attribute__ ((format (printf, 1, 2))); yann@1: yann@2448: static void conf_message(const char *fmt, ...) yann@2448: __attribute__ ((format (printf, 1, 2))); yann@2448: yann@1: static const char *conf_filename; yann@1: static int conf_lineno, conf_warnings, conf_unsaved; yann@1: yann@1: const char conf_defname[] = "arch/$ARCH/defconfig"; yann@1: yann@1: static void conf_warning(const char *fmt, ...) yann@1: { yann@1: va_list ap; yann@1: va_start(ap, fmt); yann@1: fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); yann@1: vfprintf(stderr, fmt, ap); yann@1: fprintf(stderr, "\n"); yann@1: va_end(ap); yann@1: conf_warnings++; yann@1: } yann@1: yann@2448: static void conf_default_message_callback(const char *fmt, va_list ap) yann@2448: { yann@2448: printf("#\n# "); yann@2448: vprintf(fmt, ap); yann@2448: printf("\n#\n"); yann@2448: } yann@2448: yann@2448: static void (*conf_message_callback) (const char *fmt, va_list ap) = yann@2448: conf_default_message_callback; yann@2448: void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) yann@2448: { yann@2448: conf_message_callback = fn; yann@2448: } yann@2448: yann@2448: static void conf_message(const char *fmt, ...) yann@2448: { yann@2448: va_list ap; yann@2448: yann@2448: va_start(ap, fmt); yann@2448: if (conf_message_callback) yann@2448: conf_message_callback(fmt, ap); yann@2448: } yann@2448: yann@1: const char *conf_get_configname(void) yann@1: { yann@1: char *name = getenv("KCONFIG_CONFIG"); yann@1: yann@1: return name ? name : ".config"; yann@1: } yann@1: yann@2448: const char *conf_get_autoconfig_name(void) yann@2448: { yann@2448: char *name = getenv("KCONFIG_AUTOCONFIG"); yann@2448: yann@2448: return name ? name : "include/config/auto.conf"; yann@2448: } yann@2448: yann@1: static char *conf_expand_value(const char *in) yann@1: { yann@1: struct symbol *sym; yann@1: const char *src; yann@1: static char res_value[SYMBOL_MAXLENGTH]; yann@1: char *dst, name[SYMBOL_MAXLENGTH]; yann@1: yann@1: res_value[0] = 0; yann@1: dst = name; yann@1: while ((src = strchr(in, '$'))) { yann@1: strncat(res_value, in, src - in); yann@1: src++; yann@1: dst = name; yann@1: while (isalnum(*src) || *src == '_') yann@1: *dst++ = *src++; yann@1: *dst = 0; yann@1: sym = sym_lookup(name, 0); yann@1: sym_calc_value(sym); yann@1: strcat(res_value, sym_get_string_value(sym)); yann@1: in = src; yann@1: } yann@1: strcat(res_value, in); yann@1: yann@1: return res_value; yann@1: } yann@1: yann@1: char *conf_get_default_confname(void) yann@1: { yann@1: struct stat buf; yann@1: static char fullname[PATH_MAX+1]; yann@1: char *env, *name; yann@1: yann@1: name = conf_expand_value(conf_defname); yann@1: env = getenv(SRCTREE); yann@1: if (env) { yann@1: sprintf(fullname, "%s/%s", env, name); yann@1: if (!stat(fullname, &buf)) yann@1: return fullname; yann@1: } yann@1: return name; yann@1: } yann@1: yann@943: static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) yann@943: { yann@943: char *p2; yann@943: yann@943: switch (sym->type) { yann@943: case S_TRISTATE: yann@943: if (p[0] == 'm') { yann@943: sym->def[def].tri = mod; yann@943: sym->flags |= def_flags; yann@943: break; yann@943: } yann@943: case S_BOOLEAN: yann@943: if (p[0] == 'y') { yann@943: sym->def[def].tri = yes; yann@943: sym->flags |= def_flags; yann@943: break; yann@943: } yann@943: if (p[0] == 'n') { yann@943: sym->def[def].tri = no; yann@943: sym->flags |= def_flags; yann@943: break; yann@943: } yann@943: conf_warning("symbol value '%s' invalid for %s", p, sym->name); yann@943: break; yann@943: case S_OTHER: yann@943: if (*p != '"') { yann@943: for (p2 = p; *p2 && !isspace(*p2); p2++) yann@943: ; yann@943: sym->type = S_STRING; yann@943: goto done; yann@943: } yann@943: case S_STRING: yann@943: if (*p++ != '"') yann@943: break; yann@943: for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { yann@943: if (*p2 == '"') { yann@943: *p2 = 0; yann@943: break; yann@943: } yann@943: memmove(p2, p2 + 1, strlen(p2)); yann@943: } yann@943: if (!p2) { yann@943: conf_warning("invalid string found"); yann@943: return 1; yann@943: } yann@943: case S_INT: yann@943: case S_HEX: yann@943: done: yann@943: if (sym_string_valid(sym, p)) { yann@943: sym->def[def].val = strdup(p); yann@943: sym->flags |= def_flags; yann@943: } else { yann@943: conf_warning("symbol value '%s' invalid for %s", p, sym->name); yann@943: return 1; yann@943: } yann@943: break; yann@943: default: yann@943: ; yann@943: } yann@943: return 0; yann@943: } yann@943: yann@1: int conf_read_simple(const char *name, int def) yann@1: { yann@1: FILE *in = NULL; yann@1: char line[1024]; yann@1: char *p, *p2; yann@1: struct symbol *sym; yann@1: int i, def_flags; yann@1: yann@1: if (name) { yann@1: in = zconf_fopen(name); yann@1: } else { yann@1: struct property *prop; yann@1: yann@1: name = conf_get_configname(); yann@1: in = zconf_fopen(name); yann@1: if (in) yann@1: goto load; yann@39: sym_add_change_count(1); yann@2448: if (!sym_defconfig_list) { yann@2448: if (modules_sym) yann@2448: sym_calc_value(modules_sym); yann@1: return 1; yann@2448: } yann@1: yann@1: for_all_defaults(sym_defconfig_list, prop) { yann@1: if (expr_calc_value(prop->visible.expr) == no || yann@1: prop->expr->type != E_SYMBOL) yann@1: continue; yann@1: name = conf_expand_value(prop->expr->left.sym->name); yann@1: in = zconf_fopen(name); yann@1: if (in) { yann@2448: conf_message(_("using defaults found in %s"), yann@2448: name); yann@1: goto load; yann@1: } yann@1: } yann@1: } yann@1: if (!in) yann@1: return 1; yann@1: yann@1: load: yann@1: conf_filename = name; yann@1: conf_lineno = 0; yann@1: conf_warnings = 0; yann@1: conf_unsaved = 0; yann@1: yann@1: def_flags = SYMBOL_DEF << def; yann@1: for_all_symbols(i, sym) { yann@1: sym->flags |= SYMBOL_CHANGED; yann@1: sym->flags &= ~(def_flags|SYMBOL_VALID); yann@1: if (sym_is_choice(sym)) yann@1: sym->flags |= def_flags; yann@1: switch (sym->type) { yann@1: case S_INT: yann@1: case S_HEX: yann@1: case S_STRING: yann@1: if (sym->def[def].val) yann@1: free(sym->def[def].val); yann@1: default: yann@1: sym->def[def].val = NULL; yann@1: sym->def[def].tri = no; yann@1: } yann@1: } yann@1: yann@1: while (fgets(line, sizeof(line), in)) { yann@1: conf_lineno++; yann@1: sym = NULL; yann@2448: if (line[0] == '#') { yann@2448: if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) yann@1: continue; yann@2448: p = strchr(line + 2 + strlen(CONFIG_), ' '); yann@1: if (!p) yann@1: continue; yann@1: *p++ = 0; yann@1: if (strncmp(p, "is not set", 10)) yann@1: continue; yann@1: if (def == S_DEF_USER) { yann@2448: sym = sym_find(line + 2 + strlen(CONFIG_)); yann@1: if (!sym) { yann@943: sym_add_change_count(1); yann@2448: goto setsym; yann@1: } yann@1: } else { yann@2448: sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); yann@1: if (sym->type == S_UNKNOWN) yann@1: sym->type = S_BOOLEAN; yann@1: } yann@1: if (sym->flags & def_flags) { yann@943: conf_warning("override: reassigning to symbol %s", sym->name); yann@1: } yann@1: switch (sym->type) { yann@1: case S_BOOLEAN: yann@1: case S_TRISTATE: yann@1: sym->def[def].tri = no; yann@1: sym->flags |= def_flags; yann@1: break; yann@1: default: yann@1: ; yann@1: } yann@2448: } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { yann@2448: p = strchr(line + strlen(CONFIG_), '='); yann@1: if (!p) yann@1: continue; yann@1: *p++ = 0; yann@1: p2 = strchr(p, '\n'); yann@1: if (p2) { yann@1: *p2-- = 0; yann@1: if (*p2 == '\r') yann@1: *p2 = 0; yann@1: } yann@1: if (def == S_DEF_USER) { yann@2448: sym = sym_find(line + strlen(CONFIG_)); yann@1: if (!sym) { yann@943: sym_add_change_count(1); yann@2448: goto setsym; yann@1: } yann@1: } else { yann@2448: sym = sym_lookup(line + strlen(CONFIG_), 0); yann@1: if (sym->type == S_UNKNOWN) yann@1: sym->type = S_OTHER; yann@1: } yann@1: if (sym->flags & def_flags) { yann@943: conf_warning("override: reassigning to symbol %s", sym->name); yann@1: } yann@943: if (conf_set_sym_val(sym, def, def_flags, p)) yann@943: continue; yann@2448: } else { yann@2448: if (line[0] != '\r' && line[0] != '\n') yann@2448: conf_warning("unexpected data"); yann@1: continue; yann@1: } yann@2448: setsym: yann@1: if (sym && sym_is_choice_value(sym)) { yann@1: struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); yann@1: switch (sym->def[def].tri) { yann@1: case no: yann@1: break; yann@1: case mod: yann@1: if (cs->def[def].tri == yes) { yann@1: conf_warning("%s creates inconsistent choice state", sym->name); yann@1: cs->flags &= ~def_flags; yann@1: } yann@1: break; yann@1: case yes: yann@943: if (cs->def[def].tri != no) yann@943: conf_warning("override: %s changes choice state", sym->name); yann@943: cs->def[def].val = sym; yann@1: break; yann@1: } yann@943: cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); yann@1: } yann@1: } yann@1: fclose(in); yann@1: yann@1: if (modules_sym) yann@1: sym_calc_value(modules_sym); yann@1: return 0; yann@1: } yann@1: yann@1: int conf_read(const char *name) yann@1: { yann@943: struct symbol *sym, *choice_sym; yann@1: struct property *prop; yann@1: struct expr *e; yann@1: int i, flags; yann@1: yann@39: sym_set_change_count(0); yann@1: yann@1: if (conf_read_simple(name, S_DEF_USER)) yann@1: return 1; yann@1: yann@1: for_all_symbols(i, sym) { yann@1: sym_calc_value(sym); yann@1: if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) yann@1: goto sym_ok; yann@1: if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { yann@1: /* check that calculated value agrees with saved value */ yann@1: switch (sym->type) { yann@1: case S_BOOLEAN: yann@1: case S_TRISTATE: yann@1: if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) yann@1: break; yann@1: if (!sym_is_choice(sym)) yann@1: goto sym_ok; yann@1: default: yann@1: if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) yann@1: goto sym_ok; yann@1: break; yann@1: } yann@1: } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) yann@1: /* no previous value and not saved */ yann@1: goto sym_ok; yann@1: conf_unsaved++; yann@1: /* maybe print value in verbose mode... */ yann@1: sym_ok: yann@943: if (!sym_is_choice(sym)) yann@943: continue; yann@943: /* The choice symbol only has a set value (and thus is not new) yann@943: * if all its visible childs have values. yann@943: */ yann@943: prop = sym_get_choice_prop(sym); yann@943: flags = sym->flags; yann@943: expr_list_for_each_sym(prop->expr, e, choice_sym) yann@943: if (choice_sym->visible != no) yann@943: flags &= choice_sym->flags; yann@943: sym->flags &= flags | ~SYMBOL_DEF_USER; yann@943: } yann@943: yann@943: for_all_symbols(i, sym) { yann@1: if (sym_has_value(sym) && !sym_is_choice_value(sym)) { yann@943: /* Reset values of generates values, so they'll appear yann@943: * as new, if they should become visible, but that yann@943: * doesn't quite work if the Kconfig and the saved yann@943: * configuration disagree. yann@943: */ yann@943: if (sym->visible == no && !conf_unsaved) yann@1: sym->flags &= ~SYMBOL_DEF_USER; yann@1: switch (sym->type) { yann@1: case S_STRING: yann@1: case S_INT: yann@1: case S_HEX: yann@943: /* Reset a string value if it's out of range */ yann@943: if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) yann@943: break; yann@943: sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); yann@943: conf_unsaved++; yann@943: break; yann@1: default: yann@1: break; yann@1: } yann@1: } yann@1: } yann@1: yann@39: sym_add_change_count(conf_warnings || conf_unsaved); yann@1: yann@1: return 0; yann@1: } yann@1: yann@2448: /* Write a S_STRING */ yann@2448: static void conf_write_string(bool headerfile, const char *name, yann@2448: const char *str, FILE *out) yann@2448: { yann@2448: int l; yann@2448: if (headerfile) yann@2448: fprintf(out, "#define %s%s \"", CONFIG_, name); yann@2448: else yann@2448: fprintf(out, "%s%s=\"", CONFIG_, name); yann@2448: yann@2448: while (1) { yann@2448: l = strcspn(str, "\"\\"); yann@2448: if (l) { yann@2448: xfwrite(str, l, 1, out); yann@2448: str += l; yann@2448: } yann@2448: if (!*str) yann@2448: break; yann@2448: fprintf(out, "\\%c", *str++); yann@2448: } yann@2448: fputs("\"\n", out); yann@2448: } yann@2448: yann@2448: static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no) yann@2448: { yann@2448: const char *str; yann@2448: yann@2448: switch (sym->type) { yann@2448: case S_BOOLEAN: yann@2448: case S_TRISTATE: yann@2448: switch (sym_get_tristate_value(sym)) { yann@2448: case no: yann@2448: if (write_no) yann@2448: fprintf(out, "# %s%s is not set\n", yann@2448: CONFIG_, sym->name); yann@2448: break; yann@2448: case mod: yann@2448: fprintf(out, "%s%s=m\n", CONFIG_, sym->name); yann@2448: break; yann@2448: case yes: yann@2448: fprintf(out, "%s%s=y\n", CONFIG_, sym->name); yann@2448: break; yann@2448: } yann@2448: break; yann@2448: case S_STRING: yann@2448: conf_write_string(false, sym->name, sym_get_string_value(sym), out); yann@2448: break; yann@2448: case S_HEX: yann@2448: case S_INT: yann@2448: str = sym_get_string_value(sym); yann@2448: fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str); yann@2448: break; yann@2448: case S_OTHER: yann@2448: case S_UNKNOWN: yann@2448: break; yann@2448: } yann@2448: } yann@2448: yann@2448: /* yann@2448: * Write out a minimal config. yann@2448: * All values that has default values are skipped as this is redundant. yann@2448: */ yann@2448: int conf_write_defconfig(const char *filename) yann@2448: { yann@2448: struct symbol *sym; yann@2448: struct menu *menu; yann@2448: FILE *out; yann@2448: yann@2448: out = fopen(filename, "w"); yann@2448: if (!out) yann@2448: return 1; yann@2448: yann@2448: sym_clear_all_valid(); yann@2448: yann@2448: /* Traverse all menus to find all relevant symbols */ yann@2448: menu = rootmenu.list; yann@2448: yann@2448: while (menu != NULL) yann@2448: { yann@2448: sym = menu->sym; yann@2448: if (sym == NULL) { yann@2448: if (!menu_is_visible(menu)) yann@2448: goto next_menu; yann@2448: } else if (!sym_is_choice(sym)) { yann@2448: sym_calc_value(sym); yann@2448: if (!(sym->flags & SYMBOL_WRITE)) yann@2448: goto next_menu; yann@2448: sym->flags &= ~SYMBOL_WRITE; yann@2448: /* If we cannot change the symbol - skip */ yann@2448: if (!sym_is_changable(sym)) yann@2448: goto next_menu; yann@2448: /* If symbol equals to default value - skip */ yann@2448: if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) yann@2448: goto next_menu; yann@2448: yann@2448: /* yann@2448: * If symbol is a choice value and equals to the yann@2448: * default for a choice - skip. yann@2448: * But only if value is bool and equal to "y" and yann@2448: * choice is not "optional". yann@2448: * (If choice is "optional" then all values can be "n") yann@2448: */ yann@2448: if (sym_is_choice_value(sym)) { yann@2448: struct symbol *cs; yann@2448: struct symbol *ds; yann@2448: yann@2448: cs = prop_get_symbol(sym_get_choice_prop(sym)); yann@2448: ds = sym_choice_default(cs); yann@2448: if (!sym_is_optional(cs) && sym == ds) { yann@2448: if ((sym->type == S_BOOLEAN) && yann@2448: sym_get_tristate_value(sym) == yes) yann@2448: goto next_menu; yann@2448: } yann@2448: } yann@2448: conf_write_symbol(sym, out, true); yann@2448: } yann@2448: next_menu: yann@2448: if (menu->list != NULL) { yann@2448: menu = menu->list; yann@2448: } yann@2448: else if (menu->next != NULL) { yann@2448: menu = menu->next; yann@2448: } else { yann@2448: while ((menu = menu->parent)) { yann@2448: if (menu->next != NULL) { yann@2448: menu = menu->next; yann@2448: break; yann@2448: } yann@2448: } yann@2448: } yann@2448: } yann@2448: fclose(out); yann@2448: return 0; yann@2448: } yann@2448: yann@1: int conf_write(const char *name) yann@1: { yann@1: FILE *out; yann@1: struct symbol *sym; yann@1: struct menu *menu; yann@1: const char *basename; yann@1: const char *str; yann@2448: char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; yann@1: time_t now; yann@1: int use_timestamp = 1; yann@1: char *env; yann@1: yann@1: dirname[0] = 0; yann@1: if (name && name[0]) { yann@1: struct stat st; yann@1: char *slash; yann@1: yann@1: if (!stat(name, &st) && S_ISDIR(st.st_mode)) { yann@1: strcpy(dirname, name); yann@1: strcat(dirname, "/"); yann@1: basename = conf_get_configname(); yann@1: } else if ((slash = strrchr(name, '/'))) { yann@1: int size = slash - name + 1; yann@1: memcpy(dirname, name, size); yann@1: dirname[size] = 0; yann@1: if (slash[1]) yann@1: basename = slash + 1; yann@1: else yann@1: basename = conf_get_configname(); yann@1: } else yann@1: basename = name; yann@1: } else yann@1: basename = conf_get_configname(); yann@1: yann@1: sprintf(newname, "%s%s", dirname, basename); yann@1: env = getenv("KCONFIG_OVERWRITECONFIG"); yann@1: if (!env || !*env) { yann@1: sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); yann@1: out = fopen(tmpname, "w"); yann@1: } else { yann@1: *tmpname = 0; yann@1: out = fopen(newname, "w"); yann@1: } yann@1: if (!out) yann@1: return 1; yann@1: yann@1: time(&now); yann@1: env = getenv("KCONFIG_NOTIMESTAMP"); yann@1: if (env && *env) yann@1: use_timestamp = 0; yann@1: yann@1: fprintf(out, _("#\n" yann@1: "# Automatically generated make config: don't edit\n" yann@2448: "# %s\n" yann@1: "%s%s" yann@1: "#\n"), yann@2448: rootmenu.prompt->text, yann@1: use_timestamp ? "# " : "", yann@1: use_timestamp ? ctime(&now) : ""); yann@1: yann@39: if (!conf_get_changed()) yann@1: sym_clear_all_valid(); yann@1: yann@1: menu = rootmenu.list; yann@1: while (menu) { yann@1: sym = menu->sym; yann@1: if (!sym) { yann@1: if (!menu_is_visible(menu)) yann@1: goto next; yann@1: str = menu_get_prompt(menu); yann@1: fprintf(out, "\n" yann@1: "#\n" yann@1: "# %s\n" yann@1: "#\n", str); yann@1: } else if (!(sym->flags & SYMBOL_CHOICE)) { yann@1: sym_calc_value(sym); yann@39: if (!(sym->flags & SYMBOL_WRITE)) yann@1: goto next; yann@39: sym->flags &= ~SYMBOL_WRITE; yann@2448: /* Write config symbol to file */ yann@2448: conf_write_symbol(sym, out, true); yann@1: } yann@1: yann@2448: next: yann@39: if (menu->list) { yann@39: menu = menu->list; yann@39: continue; yann@39: } yann@39: if (menu->next) yann@39: menu = menu->next; yann@39: else while ((menu = menu->parent)) { yann@39: if (menu->next) { yann@39: menu = menu->next; yann@39: break; yann@1: } yann@39: } yann@1: } yann@1: fclose(out); yann@1: yann@1: if (*tmpname) { yann@1: strcat(dirname, basename); yann@1: strcat(dirname, ".old"); yann@1: rename(newname, dirname); yann@1: if (rename(tmpname, newname)) yann@1: return 1; yann@1: } yann@1: yann@2452: conf_message(_("configuration saved")); yann@2448: yann@39: sym_set_change_count(0); yann@1: yann@1: return 0; yann@1: } yann@1: yann@2448: static int conf_split_config(void) yann@1: { yann@2448: const char *name; yann@2448: char path[PATH_MAX+1]; yann@1: char *s, *d, c; yann@1: struct symbol *sym; yann@1: struct stat sb; yann@1: int res, i, fd; yann@1: yann@2448: name = conf_get_autoconfig_name(); yann@1: conf_read_simple(name, S_DEF_AUTO); yann@1: yann@1: if (chdir("include/config")) yann@1: return 1; yann@1: yann@1: res = 0; yann@1: for_all_symbols(i, sym) { yann@1: sym_calc_value(sym); yann@1: if ((sym->flags & SYMBOL_AUTO) || !sym->name) yann@1: continue; yann@1: if (sym->flags & SYMBOL_WRITE) { yann@1: if (sym->flags & SYMBOL_DEF_AUTO) { yann@1: /* yann@1: * symbol has old and new value, yann@1: * so compare them... yann@1: */ yann@1: switch (sym->type) { yann@1: case S_BOOLEAN: yann@1: case S_TRISTATE: yann@1: if (sym_get_tristate_value(sym) == yann@1: sym->def[S_DEF_AUTO].tri) yann@1: continue; yann@1: break; yann@1: case S_STRING: yann@1: case S_HEX: yann@1: case S_INT: yann@1: if (!strcmp(sym_get_string_value(sym), yann@1: sym->def[S_DEF_AUTO].val)) yann@1: continue; yann@1: break; yann@1: default: yann@1: break; yann@1: } yann@1: } else { yann@1: /* yann@1: * If there is no old value, only 'no' (unset) yann@1: * is allowed as new value. yann@1: */ yann@1: switch (sym->type) { yann@1: case S_BOOLEAN: yann@1: case S_TRISTATE: yann@1: if (sym_get_tristate_value(sym) == no) yann@1: continue; yann@1: break; yann@1: default: yann@1: break; yann@1: } yann@1: } yann@1: } else if (!(sym->flags & SYMBOL_DEF_AUTO)) yann@1: /* There is neither an old nor a new value. */ yann@1: continue; yann@1: /* else yann@1: * There is an old value, but no new value ('no' (unset) yann@1: * isn't saved in auto.conf, so the old value is always yann@1: * different from 'no'). yann@1: */ yann@1: yann@1: /* Replace all '_' and append ".h" */ yann@1: s = sym->name; yann@1: d = path; yann@1: while ((c = *s++)) { yann@1: c = tolower(c); yann@1: *d++ = (c == '_') ? '/' : c; yann@1: } yann@1: strcpy(d, ".h"); yann@1: yann@1: /* Assume directory path already exists. */ yann@1: fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); yann@1: if (fd == -1) { yann@1: if (errno != ENOENT) { yann@1: res = 1; yann@1: break; yann@1: } yann@1: /* yann@1: * Create directory components, yann@1: * unless they exist already. yann@1: */ yann@1: d = path; yann@1: while ((d = strchr(d, '/'))) { yann@1: *d = 0; yann@1: if (stat(path, &sb) && mkdir(path, 0755)) { yann@1: res = 1; yann@1: goto out; yann@1: } yann@1: *d++ = '/'; yann@1: } yann@1: /* Try it again. */ yann@1: fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); yann@1: if (fd == -1) { yann@1: res = 1; yann@1: break; yann@1: } yann@1: } yann@1: close(fd); yann@1: } yann@1: out: yann@1: if (chdir("../..")) yann@1: return 1; yann@1: yann@1: return res; yann@1: } yann@1: yann@1: int conf_write_autoconf(void) yann@1: { yann@1: struct symbol *sym; yann@1: const char *str; yann@2448: const char *name; yann@2448: FILE *out, *tristate, *out_h; yann@2448: int i; yann@1: yann@1: sym_clear_all_valid(); yann@1: yann@1: file_write_dep("include/config/auto.conf.cmd"); yann@1: yann@1: if (conf_split_config()) yann@1: return 1; yann@1: yann@1: out = fopen(".tmpconfig", "w"); yann@1: if (!out) yann@1: return 1; yann@1: yann@2448: tristate = fopen(".tmpconfig_tristate", "w"); yann@2448: if (!tristate) { yann@1: fclose(out); yann@1: return 1; yann@1: } yann@1: yann@2448: out_h = fopen(".tmpconfig.h", "w"); yann@2448: if (!out_h) { yann@2448: fclose(out); yann@2448: fclose(tristate); yann@2448: return 1; yann@2448: } yann@2448: yann@1: fprintf(out, "#\n" yann@1: "# Automatically generated make config: don't edit\n" yann@2448: "# %s\n" yann@1: "#\n", yann@2448: rootmenu.prompt->text); yann@2448: fprintf(tristate, "#\n" yann@2448: "# Automatically generated - do not edit\n" yann@2448: "\n"); yann@1: fprintf(out_h, "/*\n" yann@1: " * Automatically generated C config: don't edit\n" yann@2448: " * %s\n" yann@2448: " */\n", yann@2448: rootmenu.prompt->text); yann@1: yann@1: for_all_symbols(i, sym) { yann@1: sym_calc_value(sym); yann@1: if (!(sym->flags & SYMBOL_WRITE) || !sym->name) yann@1: continue; yann@2448: yann@2448: /* write symbol to config file */ yann@2448: conf_write_symbol(sym, out, false); yann@2448: yann@2448: /* update autoconf and tristate files */ yann@1: switch (sym->type) { yann@1: case S_BOOLEAN: yann@1: case S_TRISTATE: yann@1: switch (sym_get_tristate_value(sym)) { yann@1: case no: yann@1: break; yann@1: case mod: yann@2448: fprintf(tristate, "%s%s=M\n", yann@2448: CONFIG_, sym->name); yann@2448: fprintf(out_h, "#define %s%s_MODULE 1\n", yann@2448: CONFIG_, sym->name); yann@1: break; yann@1: case yes: yann@2448: if (sym->type == S_TRISTATE) yann@2448: fprintf(tristate,"%s%s=Y\n", yann@2448: CONFIG_, sym->name); yann@2448: fprintf(out_h, "#define %s%s 1\n", yann@2448: CONFIG_, sym->name); yann@1: break; yann@1: } yann@1: break; yann@1: case S_STRING: yann@2448: conf_write_string(true, sym->name, sym_get_string_value(sym), out_h); yann@1: break; yann@1: case S_HEX: yann@1: str = sym_get_string_value(sym); yann@1: if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { yann@2448: fprintf(out_h, "#define %s%s 0x%s\n", yann@2448: CONFIG_, sym->name, str); yann@1: break; yann@1: } yann@1: case S_INT: yann@1: str = sym_get_string_value(sym); yann@2448: fprintf(out_h, "#define %s%s %s\n", yann@2448: CONFIG_, sym->name, str); yann@1: break; yann@1: default: yann@1: break; yann@1: } yann@1: } yann@1: fclose(out); yann@2448: fclose(tristate); yann@1: fclose(out_h); yann@1: yann@1: name = getenv("KCONFIG_AUTOHEADER"); yann@1: if (!name) yann@2448: name = "include/generated/autoconf.h"; yann@1: if (rename(".tmpconfig.h", name)) yann@1: return 1; yann@2448: name = getenv("KCONFIG_TRISTATE"); yann@1: if (!name) yann@2448: name = "include/config/tristate.conf"; yann@2448: if (rename(".tmpconfig_tristate", name)) yann@2448: return 1; yann@2448: name = conf_get_autoconfig_name(); yann@1: /* yann@1: * This must be the last step, kbuild has a dependency on auto.conf yann@1: * and this marks the successful completion of the previous steps. yann@1: */ yann@1: if (rename(".tmpconfig", name)) yann@1: return 1; yann@1: yann@1: return 0; yann@1: } yann@39: yann@39: static int sym_change_count; yann@39: static void (*conf_changed_callback)(void); yann@39: yann@39: void sym_set_change_count(int count) yann@39: { yann@39: int _sym_change_count = sym_change_count; yann@39: sym_change_count = count; yann@39: if (conf_changed_callback && yann@39: (bool)_sym_change_count != (bool)count) yann@39: conf_changed_callback(); yann@39: } yann@39: yann@39: void sym_add_change_count(int count) yann@39: { yann@39: sym_set_change_count(count + sym_change_count); yann@39: } yann@39: yann@39: bool conf_get_changed(void) yann@39: { yann@39: return sym_change_count; yann@39: } yann@39: yann@39: void conf_set_changed_callback(void (*fn)(void)) yann@39: { yann@39: conf_changed_callback = fn; yann@39: } yann@943: yann@2448: static void randomize_choice_values(struct symbol *csym) yann@2448: { yann@2448: struct property *prop; yann@2448: struct symbol *sym; yann@2448: struct expr *e; yann@2448: int cnt, def; yann@2448: yann@2448: /* yann@2448: * If choice is mod then we may have more items selected yann@2448: * and if no then no-one. yann@2448: * In both cases stop. yann@2448: */ yann@2448: if (csym->curr.tri != yes) yann@2448: return; yann@2448: yann@2448: prop = sym_get_choice_prop(csym); yann@2448: yann@2448: /* count entries in choice block */ yann@2448: cnt = 0; yann@2448: expr_list_for_each_sym(prop->expr, e, sym) yann@2448: cnt++; yann@2448: yann@2448: /* yann@2448: * find a random value and set it to yes, yann@2448: * set the rest to no so we have only one set yann@2448: */ yann@2448: def = (rand() % cnt); yann@2448: yann@2448: cnt = 0; yann@2448: expr_list_for_each_sym(prop->expr, e, sym) { yann@2448: if (def == cnt++) { yann@2448: sym->def[S_DEF_USER].tri = yes; yann@2448: csym->def[S_DEF_USER].val = sym; yann@2448: } yann@2448: else { yann@2448: sym->def[S_DEF_USER].tri = no; yann@2448: } yann@2448: } yann@2448: csym->flags |= SYMBOL_DEF_USER; yann@2448: /* clear VALID to get value calculated */ yann@2448: csym->flags &= ~(SYMBOL_VALID); yann@2448: } yann@2448: yann@2448: static void set_all_choice_values(struct symbol *csym) yann@2448: { yann@2448: struct property *prop; yann@2448: struct symbol *sym; yann@2448: struct expr *e; yann@2448: yann@2448: prop = sym_get_choice_prop(csym); yann@2448: yann@2448: /* yann@2448: * Set all non-assinged choice values to no yann@2448: */ yann@2448: expr_list_for_each_sym(prop->expr, e, sym) { yann@2448: if (!sym_has_value(sym)) yann@2448: sym->def[S_DEF_USER].tri = no; yann@2448: } yann@2448: csym->flags |= SYMBOL_DEF_USER; yann@2448: /* clear VALID to get value calculated */ yann@2448: csym->flags &= ~(SYMBOL_VALID); yann@2448: } yann@943: yann@943: void conf_set_all_new_symbols(enum conf_def_mode mode) yann@943: { yann@943: struct symbol *sym, *csym; yann@2448: int i, cnt; yann@943: yann@943: for_all_symbols(i, sym) { yann@943: if (sym_has_value(sym)) yann@943: continue; yann@943: switch (sym_get_type(sym)) { yann@943: case S_BOOLEAN: yann@943: case S_TRISTATE: yann@943: switch (mode) { yann@943: case def_yes: yann@943: sym->def[S_DEF_USER].tri = yes; yann@943: break; yann@943: case def_mod: yann@943: sym->def[S_DEF_USER].tri = mod; yann@943: break; yann@943: case def_no: yann@943: sym->def[S_DEF_USER].tri = no; yann@943: break; yann@943: case def_random: yann@2448: cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2; yann@2448: sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt); yann@943: break; yann@943: default: yann@943: continue; yann@943: } yann@2448: if (!(sym_is_choice(sym) && mode == def_random)) yann@943: sym->flags |= SYMBOL_DEF_USER; yann@943: break; yann@943: default: yann@943: break; yann@943: } yann@943: yann@943: } yann@943: yann@1228: sym_clear_all_valid(); yann@943: yann@2448: /* yann@2448: * We have different type of choice blocks. yann@2448: * If curr.tri equals to mod then we can select several yann@2448: * choice symbols in one block. yann@2448: * In this case we do nothing. yann@2448: * If curr.tri equals yes then only one symbol can be yann@2448: * selected in a choice block and we set it to yes, yann@2448: * and the rest to no. yann@2448: */ yann@943: for_all_symbols(i, csym) { yann@943: if (sym_has_value(csym) || !sym_is_choice(csym)) yann@943: continue; yann@943: yann@943: sym_calc_value(csym); yann@2448: if (mode == def_random) yann@2448: randomize_choice_values(csym); yann@2448: else yann@2448: set_all_choice_values(csym); yann@943: } yann@943: }