diff options
author | Uwe Hermann <uwe@hermann-uwe.de> | 2008-08-08 07:56:07 +0000 |
---|---|---|
committer | Uwe Hermann <uwe@hermann-uwe.de> | 2008-08-08 07:56:07 +0000 |
commit | e55b32ab627bac2108efb4a3d5b924e00ff60af9 (patch) | |
tree | cd42e58d2102370e476ddff38a4b61b3d7556601 /payloads/libpayload/util/kconfig/confdata.c | |
parent | dc93affe72b4e3162fde653da5c0ea0c84bd5e39 (diff) |
Update the kconfig copy in libpayload to a much more recent one. Among
other things this supposedly also fixes a number of build issues on Mac OS X.
This is more or less the same version (i.e. equally recent) as we have in
coreinfo and buildrom now.
This patch also includes the libintl.h fix from r3475 (coreinfo).
Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3482 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'payloads/libpayload/util/kconfig/confdata.c')
-rw-r--r-- | payloads/libpayload/util/kconfig/confdata.c | 693 |
1 files changed, 471 insertions, 222 deletions
diff --git a/payloads/libpayload/util/kconfig/confdata.c b/payloads/libpayload/util/kconfig/confdata.c index ce5fce530a..549dc0332e 100644 --- a/payloads/libpayload/util/kconfig/confdata.c +++ b/payloads/libpayload/util/kconfig/confdata.c @@ -5,6 +5,7 @@ #include <sys/stat.h> #include <ctype.h> +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -20,14 +21,7 @@ static void conf_warning(const char *fmt, ...) static const char *conf_filename; static int conf_lineno, conf_warnings, conf_unsaved; -const char conf_def_filename[] = ".config"; - -const char conf_defname[] = "util/defconfig"; - -const char *conf_confnames[] = { - ".config", - NULL, -}; +const char conf_defname[] = "arch/$ARCH/defconfig"; static void conf_warning(const char *fmt, ...) { @@ -40,6 +34,13 @@ static void conf_warning(const char *fmt, ...) conf_warnings++; } +const char *conf_get_configname(void) +{ + char *name = getenv("KCONFIG_CONFIG"); + + return name ? name : ".config"; +} + static char *conf_expand_value(const char *in) { struct symbol *sym; @@ -82,51 +83,127 @@ char *conf_get_default_confname(void) return name; } -int conf_read_simple(const char *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; char line[1024]; char *p, *p2; struct symbol *sym; - int i; + int i, def_flags; if (name) { in = zconf_fopen(name); } else { - const char **names = conf_confnames; - while ((name = *names++)) { - name = conf_expand_value(name); + struct property *prop; + + name = conf_get_configname(); + in = zconf_fopen(name); + if (in) + goto load; + sym_add_change_count(1); + 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); in = zconf_fopen(name); if (in) { printf(_("#\n" - "# using defaults found in %s\n" - "#\n"), name); - break; + "# using defaults found in %s\n" + "#\n"), name); + goto load; } } } if (!in) return 1; +load: conf_filename = name; conf_lineno = 0; conf_warnings = 0; conf_unsaved = 0; + def_flags = SYMBOL_DEF << def; for_all_symbols(i, sym) { - sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED; + sym->flags |= SYMBOL_CHANGED; + sym->flags &= ~(def_flags|SYMBOL_VALID); if (sym_is_choice(sym)) - sym->flags &= ~SYMBOL_NEW; - sym->flags &= ~SYMBOL_VALID; + sym->flags |= def_flags; switch (sym->type) { case S_INT: case S_HEX: case S_STRING: - if (sym->user.val) - free(sym->user.val); + if (sym->def[def].val) + free(sym->def[def].val); default: - sym->user.val = NULL; - sym->user.tri = no; + sym->def[def].val = NULL; + sym->def[def].tri = no; } } @@ -143,19 +220,25 @@ int conf_read_simple(const char *name) *p++ = 0; if (strncmp(p, "is not set", 10)) continue; - sym = sym_find(line + 9); - if (!sym) { - conf_warning("trying to assign nonexistent symbol %s", line + 9); - break; - } else if (!(sym->flags & SYMBOL_NEW)) { - conf_warning("trying to reassign symbol %s", sym->name); - break; + if (def == S_DEF_USER) { + sym = sym_find(line + 9); + if (!sym) { + conf_warning("trying to assign nonexistent symbol %s", line + 9); + break; + } + } else { + sym = sym_lookup(line + 9, 0); + if (sym->type == S_UNKNOWN) + sym->type = S_BOOLEAN; + } + if (sym->flags & def_flags) { + conf_warning("override: reassigning to symbol %s", sym->name); } switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: - sym->user.tri = no; - sym->flags &= ~SYMBOL_NEW; + sym->def[def].tri = no; + sym->flags |= def_flags; break; default: ; @@ -171,64 +254,29 @@ int conf_read_simple(const char *name) continue; *p++ = 0; p2 = strchr(p, '\n'); - if (p2) - *p2 = 0; - sym = sym_find(line + 7); - if (!sym) { - conf_warning("trying to assign nonexistent symbol %s", line + 7); - break; - } else if (!(sym->flags & SYMBOL_NEW)) { - conf_warning("trying to reassign symbol %s", sym->name); - break; + if (p2) { + *p2-- = 0; + if (*p2 == '\r') + *p2 = 0; } - switch (sym->type) { - case S_TRISTATE: - if (p[0] == 'm') { - sym->user.tri = mod; - sym->flags &= ~SYMBOL_NEW; - break; - } - case S_BOOLEAN: - if (p[0] == 'y') { - sym->user.tri = yes; - sym->flags &= ~SYMBOL_NEW; - break; - } - if (p[0] == 'n') { - sym->user.tri = no; - sym->flags &= ~SYMBOL_NEW; - break; - } - conf_warning("symbol value '%s' invalid for %s", p, sym->name); - break; - case S_STRING: - if (*p++ != '"') + if (def == S_DEF_USER) { + sym = sym_find(line + 7); + if (!sym) { + conf_warning("trying to assign nonexistent symbol %s", line + 7); 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: - if (sym_string_valid(sym, p)) { - sym->user.val = strdup(p); - sym->flags &= ~SYMBOL_NEW; - } else { - conf_warning("symbol value '%s' invalid for %s", p, sym->name); - continue; - } - break; - default: - ; + } else { + sym = sym_lookup(line + 7, 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; + } + if (sym->flags & def_flags) { + 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': break; default: @@ -237,24 +285,22 @@ int conf_read_simple(const char *name) } if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - switch (sym->user.tri) { + switch (sym->def[def].tri) { case no: break; case mod: - if (cs->user.tri == yes) { + if (cs->def[def].tri == yes) { conf_warning("%s creates inconsistent choice state", sym->name); - cs->flags |= SYMBOL_NEW; + cs->flags &= ~def_flags; } break; case yes: - if (cs->user.tri != no) { - conf_warning("%s creates inconsistent choice state", sym->name); - cs->flags |= SYMBOL_NEW; - } else - cs->user.val = sym; + if (cs->def[def].tri != no) + conf_warning("override: %s changes choice state", sym->name); + cs->def[def].val = sym; break; } - cs->user.tri = E_OR(cs->user.tri, sym->user.tri); + cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); } } fclose(in); @@ -266,12 +312,14 @@ int conf_read_simple(const char *name) int conf_read(const char *name) { - struct symbol *sym; + struct symbol *sym, *choice_sym; struct property *prop; struct expr *e; - int i; + int i, flags; + + sym_set_change_count(0); - if (conf_read_simple(name)) + if (conf_read_simple(name, S_DEF_USER)) return 1; for_all_symbols(i, sym) { @@ -283,12 +331,12 @@ int conf_read(const char *name) switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: - if (sym->user.tri != sym_get_tristate_value(sym)) + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) break; if (!sym_is_choice(sym)) goto sym_ok; default: - if (!strcmp(sym->curr.val, sym->user.val)) + if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) goto sym_ok; break; } @@ -298,37 +346,52 @@ int conf_read(const char *name) 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) { if (sym_has_value(sym) && !sym_is_choice_value(sym)) { - if (sym->visible == no) - sym->flags |= SYMBOL_NEW; + /* Reset values of generates values, so they'll appear + * as new, if they should become visible, but that + * doesn't quite work if the Kconfig and the saved + * configuration disagree. + */ + if (sym->visible == no && !conf_unsaved) + sym->flags &= ~SYMBOL_DEF_USER; switch (sym->type) { case S_STRING: case S_INT: case S_HEX: - if (!sym_string_within_range(sym, sym->user.val)) { - sym->flags |= SYMBOL_NEW; - sym->flags &= ~SYMBOL_VALID; - } + /* Reset a string value if it's out of range */ + if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) + break; + sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); + conf_unsaved++; + break; default: break; } } - if (!sym_is_choice(sym)) - continue; - prop = sym_get_choice_prop(sym); - for (e = prop->expr; e; e = e->left.expr) - if (e->right.sym->visible != no) - sym->flags |= e->right.sym->flags & SYMBOL_NEW; } - sym_change_count = conf_warnings || conf_unsaved; + sym_add_change_count(conf_warnings || conf_unsaved); return 0; } int conf_write(const char *name) { - FILE *out, *out_h; + FILE *out; struct symbol *sym; struct menu *menu; const char *basename; @@ -347,7 +410,7 @@ int conf_write(const char *name) if (!stat(name, &st) && S_ISDIR(st.st_mode)) { strcpy(dirname, name); strcat(dirname, "/"); - basename = conf_def_filename; + basename = conf_get_configname(); } else if ((slash = strrchr(name, '/'))) { int size = slash - name + 1; memcpy(dirname, name, size); @@ -355,23 +418,24 @@ int conf_write(const char *name) if (slash[1]) basename = slash + 1; else - basename = conf_def_filename; + basename = conf_get_configname(); } else basename = name; } else - basename = conf_def_filename; + basename = conf_get_configname(); - sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid()); - out = fopen(newname, "w"); + 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 { + *tmpname = 0; + out = fopen(newname, "w"); + } if (!out) return 1; - out_h = NULL; - if (!name) { - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) - return 1; - file_write_dep(NULL); - } + sym = sym_lookup("KERNELVERSION", 0); sym_calc_value(sym); time(&now); @@ -381,38 +445,14 @@ int conf_write(const char *name) fprintf(out, _("#\n" "# Automatically generated make config: don't edit\n" - "# Libpayload version: %s\n" + "# libpayload version: %s\n" "%s%s" "#\n"), - sym_get_string_value(sym), + getenv("KERNELVERSION"), use_timestamp ? "# " : "", use_timestamp ? ctime(&now) : ""); - if (out_h) { - char buf[sizeof("#define AUTOCONF_TIMESTAMP " - "\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")]; - buf[0] = '\0'; - if (use_timestamp) { - size_t ret = \ - strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " - "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now)); - /* if user has Factory timezone or some other odd install, the - * %Z above will overflow the string leaving us with undefined - * results ... so let's try again without the timezone. - */ - if (ret == 0) - strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " - "\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now)); - } - fprintf(out_h, "/*\n" - " * Automatically generated C config: don't edit\n" - " * Libpayload version: %s\n" - " */\n" - "%s" - "\n", - sym_get_string_value(sym), - buf); - } - if (!sym_change_count) + + if (!conf_get_changed()) sym_clear_all_valid(); menu = rootmenu.list; @@ -426,17 +466,10 @@ int conf_write(const char *name) "#\n" "# %s\n" "#\n", str); - if (out_h) - fprintf(out_h, "\n" - "/*\n" - " * %s\n" - " */\n", str); } else if (!(sym->flags & SYMBOL_CHOICE)) { sym_calc_value(sym); -/* bbox: we want to all syms if (!(sym->flags & SYMBOL_WRITE)) goto next; -*/ sym->flags &= ~SYMBOL_WRITE; type = sym->type; if (type == S_TRISTATE) { @@ -450,84 +483,39 @@ int conf_write(const char *name) switch (sym_get_tristate_value(sym)) { case no: fprintf(out, "# CONFIG_%s is not set\n", sym->name); - if (out_h) { - fprintf(out_h, "#undef CONFIG_%s\n", sym->name); - /* bbox */ - fprintf(out_h, "#define ENABLE_%s 0\n", sym->name); - fprintf(out_h, "#define USE_%s(...)\n", sym->name); - fprintf(out_h, "#define SKIP_%s(...) __VA_ARGS__\n", sym->name); - } break; case mod: fprintf(out, "CONFIG_%s=m\n", sym->name); - if (out_h) - fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); break; case yes: fprintf(out, "CONFIG_%s=y\n", sym->name); - if (out_h) { - fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); - /* bbox */ - fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); - fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); - } break; } break; case S_STRING: - // fix me str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=\"", sym->name); - if (out_h) - fprintf(out_h, "#define CONFIG_%s \"", sym->name); - do { + while (1) { l = strcspn(str, "\"\\"); if (l) { fwrite(str, l, 1, out); - if (out_h) - fwrite(str, l, 1, out_h); + str += l; } - str += l; - while (*str == '\\' || *str == '"') { - fprintf(out, "\\%c", *str); - if (out_h) - fprintf(out_h, "\\%c", *str); - str++; - } - } while (*str); - fputs("\"\n", out); - if (out_h) { - fputs("\"\n", out_h); - /* bbox */ - fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); - fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); + 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); - if (out_h) { - fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); - /* bbox */ - fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); - fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); - } break; } case S_INT: str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - if (out_h) { - fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); - /* bbox */ - fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); - fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); - } break; } } @@ -547,21 +535,282 @@ int conf_write(const char *name) } } fclose(out); - if (out_h) { - fclose(out_h); - rename(".tmpconfig.h", "include/autoconf.h"); + + if (*tmpname) { + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) + return 1; } - if (!name || basename != conf_def_filename) { - if (!name) - name = conf_def_filename; - sprintf(tmpname, "%s.old", name); - rename(name, tmpname); + + printf(_("#\n" + "# configuration written to %s\n" + "#\n"), newname); + + sym_set_change_count(0); + + return 0; +} + +int conf_split_config(void) +{ + char *name, 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"; + conf_read_simple(name, S_DEF_AUTO); + + if (chdir("build")) + return 1; + + res = 0; + for_all_symbols(i, sym) { + sym_calc_value(sym); + if ((sym->flags & SYMBOL_AUTO) || !sym->name) + continue; + if (sym->flags & SYMBOL_WRITE) { + if (sym->flags & SYMBOL_DEF_AUTO) { + /* + * symbol has old and new value, + * so compare them... + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == + sym->def[S_DEF_AUTO].tri) + continue; + break; + case S_STRING: + case S_HEX: + case S_INT: + if (!strcmp(sym_get_string_value(sym), + sym->def[S_DEF_AUTO].val)) + continue; + break; + default: + break; + } + } else { + /* + * If there is no old value, only 'no' (unset) + * is allowed as new value. + */ + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + if (sym_get_tristate_value(sym) == no) + continue; + break; + default: + break; + } + } + } else if (!(sym->flags & SYMBOL_DEF_AUTO)) + /* There is neither an old nor a new value. */ + continue; + /* else + * There is an old value, but no new value ('no' (unset) + * isn't saved in auto.conf, so the old value is always + * 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); } - sprintf(tmpname, "%s%s", dirname, basename); - if (rename(newname, tmpname)) +out: + if (chdir("../..")) return 1; - sym_change_count = 0; + return res; +} + +int conf_write_autoconf(void) +{ + struct symbol *sym; + const char *str; + char *name; + FILE *out, *out_h; + time_t now; + int i, l; + + sym_clear_all_valid(); + + file_write_dep("build/auto.conf.cmd"); + +#if 0 + if (conf_split_config()) + return 1; +#endif + + out = fopen(".tmpconfig", "w"); + if (!out) + return 1; + + out_h = fopen(".tmpconfig.h", "w"); + if (!out_h) { + fclose(out); + return 1; + } + + sym = sym_lookup("KERNELVERSION", 0); + sym_calc_value(sym); + time(&now); + fprintf(out, "#\n" + "# Automatically generated make config: don't edit\n" + "# libpayload version: %s\n" + "# %s" + "#\n", + getenv("KERNELVERSION"), ctime(&now)); + fprintf(out_h, "/*\n" + " * Automatically generated C config: don't edit\n" + " * libpayload version: %s\n" + " * %s" + " */\n" + "#define AUTOCONF_INCLUDED\n", + getenv("KERNELVERSION"), ctime(&now)); + + 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, "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); + 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: + break; + } + } + fclose(out); + fclose(out_h); + + name = getenv("KCONFIG_AUTOHEADER"); + if (!name) + name = "include/linux/autoconf.h"; + if (rename(".tmpconfig.h", name)) + return 1; + name = getenv("KCONFIG_AUTOCONFIG"); + if (!name) + name = "include/config/auto.conf"; + /* + * 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)) + return 1; return 0; } + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ + int _sym_change_count = sym_change_count; + sym_change_count = count; + if (conf_changed_callback && + (bool)_sym_change_count != (bool)count) + conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ + sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ + return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ + conf_changed_callback = fn; +} |