diff options
Diffstat (limited to 'scripts/kconfig/confdata.c')
-rw-r--r-- | scripts/kconfig/confdata.c | 979 |
1 files changed, 459 insertions, 520 deletions
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index a39d93e3c6ae..f53dcdd44597 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -5,11 +5,13 @@ #include <sys/mman.h> #include <sys/stat.h> +#include <sys/types.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <limits.h> #include <stdarg.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -32,7 +34,7 @@ static bool is_dir(const char *path) struct stat st; if (stat(path, &st)) - return 0; + return false; return S_ISDIR(st.st_mode); } @@ -128,46 +130,22 @@ static size_t depfile_prefix_len; /* touch depfile for symbol 'name' */ static int conf_touch_dep(const char *name) { - int fd, ret; - const char *s; - char *d, c; + int fd; - /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */ - if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path)) + /* check overflow: prefix + name + '\0' must fit in buffer. */ + if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path)) return -1; - d = depfile_path + depfile_prefix_len; - s = name; - - while ((c = *s++)) - *d++ = (c == '_') ? '/' : tolower(c); - strcpy(d, ".h"); + strcpy(depfile_path + depfile_prefix_len, name); - /* Assume directory path already exists. */ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) { - if (errno != ENOENT) - return -1; - - ret = make_parent_dir(depfile_path); - if (ret) - return ret; - - /* Try it again. */ - fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) - return -1; - } + if (fd == -1) + return -1; close(fd); return 0; } -struct conf_printer { - void (*print_symbol)(FILE *, struct symbol *, const char *, void *); - void (*print_comment)(FILE *, const char *, void *); -}; - static void conf_warning(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -177,6 +155,13 @@ static void conf_message(const char *fmt, ...) static const char *conf_filename; static int conf_lineno, conf_warnings; +bool conf_errors(void) +{ + if (conf_warnings) + return getenv("KCONFIG_WERROR"); + return false; +} + static void conf_warning(const char *fmt, ...) { va_list ap; @@ -231,6 +216,20 @@ static const char *conf_get_autoconfig_name(void) return name ? name : "include/config/auto.conf"; } +static const char *conf_get_autoheader_name(void) +{ + char *name = getenv("KCONFIG_AUTOHEADER"); + + return name ? name : "include/generated/autoconf.h"; +} + +static const char *conf_get_rustccfg_name(void) +{ + char *name = getenv("KCONFIG_RUSTCCFG"); + + return name ? name : "include/generated/rustc_cfg"; +} + static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) { char *p2; @@ -259,19 +258,21 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) p, sym->name); return 1; case S_STRING: - if (*p++ != '"') - break; - for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { - if (*p2 == '"') { - *p2 = 0; + /* No escaping for S_DEF_AUTO (include/config/auto.conf) */ + if (def != S_DEF_AUTO) { + if (*p++ != '"') break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); } - memmove(p2, p2 + 1, strlen(p2)); - } - if (!p2) { - if (def != S_DEF_AUTO) + if (!p2) { conf_warning("invalid string found"); - return 1; + return 1; + } } /* fall through */ case S_INT: @@ -295,16 +296,12 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) #define LINE_GROWTH 16 static int add_byte(int c, char **lineptr, size_t slen, size_t *n) { - char *nline; size_t new_size = slen + 1; + if (new_size > *n) { new_size += LINE_GROWTH - 1; new_size *= 2; - nline = xrealloc(*lineptr, new_size); - if (!nline) - return -1; - - *lineptr = nline; + *lineptr = xrealloc(*lineptr, new_size); *n = new_size; } @@ -347,40 +344,80 @@ e_out: return -1; } +/* like getline(), but the newline character is stripped away */ +static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream) +{ + ssize_t len; + + len = compat_getline(lineptr, n, stream); + + if (len > 0 && (*lineptr)[len - 1] == '\n') { + len--; + (*lineptr)[len] = '\0'; + + if (len > 0 && (*lineptr)[len - 1] == '\r') { + len--; + (*lineptr)[len] = '\0'; + } + } + + return len; +} + int conf_read_simple(const char *name, int def) { FILE *in = NULL; char *line = NULL; size_t line_asize = 0; - char *p, *p2; + char *p, *val; struct symbol *sym; int i, def_flags; + const char *warn_unknown, *sym_name; + warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS"); if (name) { in = zconf_fopen(name); } else { - struct property *prop; + char *env; name = conf_get_configname(); in = zconf_fopen(name); if (in) goto load; - sym_add_change_count(1); - if (!sym_defconfig_list) + conf_set_changed(true); + + env = getenv("KCONFIG_DEFCONFIG_LIST"); + if (!env) return 1; - for_all_defaults(sym_defconfig_list, prop) { - if (expr_calc_value(prop->visible.expr) == no || - prop->expr->type != E_SYMBOL) - continue; - sym_calc_value(prop->expr->left.sym); - name = sym_get_string_value(prop->expr->left.sym); - in = zconf_fopen(name); + while (1) { + bool is_last; + + while (isspace(*env)) + env++; + + if (!*env) + break; + + p = env; + while (*p && !isspace(*p)) + p++; + + is_last = (*p == '\0'); + + *p = '\0'; + + in = zconf_fopen(env); if (in) { conf_message("using defaults found in %s", - name); + env); goto load; } + + if (is_last) + break; + + env = p + 1; } } if (!in) @@ -401,8 +438,7 @@ load: case S_INT: case S_HEX: case S_STRING: - if (sym->def[def].val) - free(sym->def[def].val); + free(sym->def[def].val); /* fall through */ default: sym->def[def].val = NULL; @@ -410,81 +446,68 @@ load: } } - while (compat_getline(&line, &line_asize, in) != -1) { + while (getline_stripped(&line, &line_asize, in) != -1) { conf_lineno++; - sym = NULL; + + if (!line[0]) /* blank line */ + continue; + if (line[0] == '#') { - if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) + if (line[1] != ' ') + continue; + p = line + 2; + if (memcmp(p, CONFIG_, strlen(CONFIG_))) continue; - p = strchr(line + 2 + strlen(CONFIG_), ' '); + sym_name = p + strlen(CONFIG_); + p = strchr(sym_name, ' '); if (!p) continue; *p++ = 0; - if (strncmp(p, "is not set", 10)) + if (strcmp(p, "is not set")) continue; - if (def == S_DEF_USER) { - sym = sym_find(line + 2 + strlen(CONFIG_)); - if (!sym) { - sym_add_change_count(1); - continue; - } - } else { - sym = sym_lookup(line + 2 + strlen(CONFIG_), 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->def[def].tri = no; - sym->flags |= def_flags; - break; - default: - ; - } - } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { - p = strchr(line + strlen(CONFIG_), '='); - if (!p) + + val = "n"; + } else { + if (memcmp(line, CONFIG_, strlen(CONFIG_))) { + conf_warning("unexpected data: %s", line); continue; - *p++ = 0; - p2 = strchr(p, '\n'); - if (p2) { - *p2-- = 0; - if (*p2 == '\r') - *p2 = 0; } - sym = sym_find(line + strlen(CONFIG_)); - if (!sym) { - if (def == S_DEF_AUTO) - /* - * Reading from include/config/auto.conf - * If CONFIG_FOO previously existed in - * auto.conf but it is missing now, - * include/config/foo.h must be touched. - */ - conf_touch_dep(line + strlen(CONFIG_)); - else - sym_add_change_count(1); + sym_name = line + strlen(CONFIG_); + p = strchr(sym_name, '='); + if (!p) { + conf_warning("unexpected data: %s", line); continue; } + *p = 0; + val = p + 1; + } - 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; - } else { - if (line[0] != '\r' && line[0] != '\n') - conf_warning("unexpected data: %.*s", - (int)strcspn(line, "\r\n"), line); + sym = sym_find(sym_name); + if (!sym) { + if (def == S_DEF_AUTO) { + /* + * Reading from include/config/auto.conf. + * If CONFIG_FOO previously existed in auto.conf + * but it is missing now, include/config/FOO + * must be touched. + */ + conf_touch_dep(sym_name); + } else { + if (warn_unknown) + conf_warning("unknown symbol: %s", sym_name); + conf_set_changed(true); + } continue; } + if (sym->flags & def_flags) + conf_warning("override: reassigning to symbol %s", sym->name); + + if (conf_set_sym_val(sym, def, def_flags, val)) + continue; + if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); switch (sym->def[def].tri) { @@ -507,6 +530,7 @@ load: } free(line); fclose(in); + return 0; } @@ -516,7 +540,7 @@ int conf_read(const char *name) int conf_unsaved = 0; int i; - sym_set_change_count(0); + conf_set_changed(false); if (conf_read_simple(name, S_DEF_USER)) { sym_calc_value(modules_sym); @@ -565,7 +589,7 @@ int conf_read(const char *name) /* 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); + sym->flags &= ~SYMBOL_VALID; conf_unsaved++; break; default: @@ -574,174 +598,232 @@ int conf_read(const char *name) } } - sym_add_change_count(conf_warnings || conf_unsaved); + if (conf_warnings || conf_unsaved) + conf_set_changed(true); 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) +struct comment_style { + const char *decoration; + const char *prefix; + const char *postfix; +}; + +static const struct comment_style comment_style_pound = { + .decoration = "#", + .prefix = "#", + .postfix = "#", +}; + +static const struct comment_style comment_style_c = { + .decoration = " *", + .prefix = "/*", + .postfix = " */", +}; + +static void conf_write_heading(FILE *fp, const struct comment_style *cs) { + if (!cs) + return; - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (*value == 'n') { - bool skip_unset = (arg != NULL); + fprintf(fp, "%s\n", cs->prefix); - if (!skip_unset) - fprintf(fp, "# %s%s is not set\n", - CONFIG_, sym->name); - return; - } - break; - default: - break; - } + fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n", + cs->decoration); + + fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text); - fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); + fprintf(fp, "%s\n", cs->postfix); } -static void -kconfig_print_comment(FILE *fp, const char *value, void *arg) +/* The returned pointer must be freed on the caller side */ +static char *escape_string_value(const char *in) { - const char *p = value; - size_t l; + const char *p; + char *out; + size_t len; - for (;;) { - l = strcspn(p, "\n"); - fprintf(fp, "#"); - if (l) { - fprintf(fp, " "); - xfwrite(p, l, 1, fp); - p += l; - } - fprintf(fp, "\n"); - if (*p++ == '\0') + len = strlen(in) + strlen("\"\"") + 1; + + p = in; + while (1) { + p += strcspn(p, "\"\\"); + + if (p[0] == '\0') break; + + len++; + p++; + } + + out = xmalloc(len); + out[0] = '\0'; + + strcat(out, "\""); + + p = in; + while (1) { + len = strcspn(p, "\"\\"); + strncat(out, p, len); + p += len; + + if (p[0] == '\0') + break; + + strcat(out, "\\"); + strncat(out, p++, 1); } + + strcat(out, "\""); + + return out; } -static struct conf_printer kconfig_printer_cb = +enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE }; + +static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n, + bool escape_string) { - .print_symbol = kconfig_print_symbol, - .print_comment = kconfig_print_comment, -}; + const char *val; + char *escaped = NULL; -/* - * 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) + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); + + if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) && + output_n != OUTPUT_N && *val == 'n') { + if (output_n == OUTPUT_N_AS_UNSET) + fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name); + return; + } + + if (sym->type == S_STRING && escape_string) { + escaped = escape_string_value(val); + val = escaped; + } + + fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val); + + free(escaped); +} + +static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym) +{ + __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true); +} + +static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym) +{ + __print_symbol(fp, sym, OUTPUT_N_NONE, false); +} + +void print_symbol_for_listconfig(struct symbol *sym) +{ + __print_symbol(stdout, sym, OUTPUT_N, true); +} + +static void print_symbol_for_c(FILE *fp, struct symbol *sym) { + const char *val; + const char *sym_suffix = ""; + const char *val_prefix = ""; + char *escaped = NULL; + + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); switch (sym->type) { case S_BOOLEAN: - case S_TRISTATE: { - const char *suffix = ""; - - switch (*value) { + case S_TRISTATE: + switch (*val) { case 'n': - break; + return; case 'm': - suffix = "_MODULE"; + sym_suffix = "_MODULE"; /* fall through */ default: - fprintf(fp, "#define %s%s%s 1\n", - CONFIG_, sym->name, suffix); + val = "1"; } 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); + case S_HEX: + if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) + val_prefix = "0x"; break; - } case S_STRING: - case S_INT: - fprintf(fp, "#define %s%s %s\n", - CONFIG_, sym->name, value); - break; + escaped = escape_string_value(val); + val = escaped; default: break; } -} + fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix, + val_prefix, val); -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"); + free(escaped); } -static struct conf_printer header_printer_cb = +static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym) { - .print_symbol = header_print_symbol, - .print_comment = header_print_comment, -}; + const char *val; + const char *val_prefix = ""; + char *val_prefixed = NULL; + size_t val_prefixed_len; + char *escaped = NULL; -static void conf_write_symbol(FILE *fp, struct symbol *sym, - struct conf_printer *printer, void *printer_arg) -{ - const char *str; + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); switch (sym->type) { - case S_UNKNOWN: + case S_BOOLEAN: + case S_TRISTATE: + /* + * We do not care about disabled ones, i.e. no need for + * what otherwise are "comments" in other printers. + */ + if (*val == 'n') + return; + + /* + * To have similar functionality to the C macro `IS_ENABLED()` + * we provide an empty `--cfg CONFIG_X` here in both `y` + * and `m` cases. + * + * Then, the common `fprintf()` below will also give us + * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can + * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`. + */ + fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name); 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); + case S_HEX: + if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) + val_prefix = "0x"; break; default: - str = sym_get_string_value(sym); - printer->print_symbol(fp, sym, str, printer_arg); + break; } -} -static void -conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) -{ - char buf[256]; + if (strlen(val_prefix) > 0) { + val_prefixed_len = strlen(val) + strlen(val_prefix) + 1; + val_prefixed = xmalloc(val_prefixed_len); + snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val); + val = val_prefixed; + } - snprintf(buf, sizeof(buf), - "\n" - "Automatically generated file; DO NOT EDIT.\n" - "%s\n", - rootmenu.prompt->text); + /* All values get escaped: the `--cfg` option only takes strings */ + escaped = escape_string_value(val); + val = escaped; - printer->print_comment(fp, buf, printer_arg); + fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val); + + free(escaped); + free(val_prefixed); } /* @@ -800,7 +882,7 @@ int conf_write_defconfig(const char *filename) goto next_menu; } } - conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + print_symbol_for_dotconfig(out, sym); } next_menu: if (menu->list != NULL) { @@ -860,7 +942,7 @@ int conf_write(const char *name) if (!out) return 1; - conf_write_heading(out, &kconfig_printer_cb, NULL); + conf_write_heading(out, &comment_style_pound); if (!conf_get_changed()) sym_clear_all_valid(); @@ -887,7 +969,7 @@ int conf_write(const char *name) need_newline = false; } sym->flags |= SYMBOL_WRITTEN; - conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + print_symbol_for_dotconfig(out, sym); } next: @@ -895,19 +977,20 @@ next: menu = menu->list; continue; } - if (menu->next) + +end_check: + if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu && + menu->prompt->type == P_MENU) { + fprintf(out, "# end of %s\n", menu_get_prompt(menu)); + need_newline = true; + } + + if (menu->next) { menu = menu->next; - else while ((menu = menu->parent)) { - if (!menu->sym && menu_is_visible(menu) && - menu != &rootmenu) { - str = menu_get_prompt(menu); - fprintf(out, "# end of %s\n", str); - need_newline = true; - } - if (menu->next) { - menu = menu->next; - break; - } + } else { + menu = menu->parent; + if (menu) + goto end_check; } } fclose(out); @@ -919,7 +1002,7 @@ next: if (is_same(name, tmpname)) { conf_message("No change to %s", name); unlink(tmpname); - sym_set_change_count(0); + conf_set_changed(false); return 0; } @@ -931,51 +1014,75 @@ next: conf_message("configuration written to %s", name); - sym_set_change_count(0); + conf_set_changed(false); return 0; } /* write a dependency file as used by kbuild to track dependencies */ -static int conf_write_dep(const char *name) +static int conf_write_autoconf_cmd(const char *autoconf_name) { + char name[PATH_MAX], tmp[PATH_MAX]; struct file *file; FILE *out; + int ret; - out = fopen("..config.tmp", "w"); - if (!out) - return 1; - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) { - if (file->next) - fprintf(out, "\t%s \\\n", file->name); - else - fprintf(out, "\t%s\n", file->name); + ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name); + if (ret >= sizeof(name)) /* check truncation */ + return -1; + + if (make_parent_dir(name)) + return -1; + + ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name); + if (ret >= sizeof(tmp)) /* check truncation */ + return -1; + + out = fopen(tmp, "w"); + if (!out) { + perror("fopen"); + return -1; } - fprintf(out, "\n%s: \\\n" - "\t$(deps_config)\n\n", conf_get_autoconfig_name()); - env_write_dep(out, conf_get_autoconfig_name()); + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) + fprintf(out, "\t%s \\\n", file->name); + + fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name); + + env_write_dep(out, autoconf_name); fprintf(out, "\n$(deps_config): ;\n"); + + fflush(out); + ret = ferror(out); /* error check for all fprintf() calls */ fclose(out); + if (ret) + return -1; + + if (rename(tmp, name)) { + perror("rename"); + return -1; + } - if (make_parent_dir(name)) - return 1; - rename("..config.tmp", name); return 0; } static int conf_touch_deps(void) { - const char *name; + const char *name, *tmp; struct symbol *sym; int res, i; - strcpy(depfile_path, "include/config/"); - depfile_prefix_len = strlen(depfile_path); - name = conf_get_autoconfig_name(); + tmp = strrchr(name, '/'); + depfile_prefix_len = tmp ? tmp - name + 1 : 0; + if (depfile_prefix_len + 1 > sizeof(depfile_path)) + return -1; + + strncpy(depfile_path, name, depfile_prefix_len); + depfile_path[depfile_prefix_len] = 0; + conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); @@ -1038,87 +1145,110 @@ static int conf_touch_deps(void) return 0; } +static int __conf_write_autoconf(const char *filename, + void (*print_symbol)(FILE *, struct symbol *), + const struct comment_style *comment_style) +{ + char tmp[PATH_MAX]; + FILE *file; + struct symbol *sym; + int ret, i; + + if (make_parent_dir(filename)) + return -1; + + ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename); + if (ret >= sizeof(tmp)) /* check truncation */ + return -1; + + file = fopen(tmp, "w"); + if (!file) { + perror("fopen"); + return -1; + } + + conf_write_heading(file, comment_style); + + for_all_symbols(i, sym) + if ((sym->flags & SYMBOL_WRITE) && sym->name) + print_symbol(file, sym); + + fflush(file); + /* check possible errors in conf_write_heading() and print_symbol() */ + ret = ferror(file); + fclose(file); + if (ret) + return -1; + + if (rename(tmp, filename)) { + perror("rename"); + return -1; + } + + return 0; +} + int conf_write_autoconf(int overwrite) { struct symbol *sym; - const char *name; const char *autoconf_name = conf_get_autoconfig_name(); - FILE *out, *out_h; - int i; + int ret, i; if (!overwrite && is_present(autoconf_name)) return 0; - conf_write_dep("include/config/auto.conf.cmd"); + ret = conf_write_autoconf_cmd(autoconf_name); + if (ret) + return -1; if (conf_touch_deps()) return 1; - out = fopen(".tmpconfig", "w"); - if (!out) - return 1; - - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) { - fclose(out); - return 1; - } - - conf_write_heading(out, &kconfig_printer_cb, NULL); - conf_write_heading(out_h, &header_printer_cb, NULL); - - for_all_symbols(i, sym) { + for_all_symbols(i, sym) sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE) || !sym->name) - continue; - /* write symbols to auto.conf and autoconf.h */ - conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); - conf_write_symbol(out_h, sym, &header_printer_cb, NULL); - } - fclose(out); - fclose(out_h); + ret = __conf_write_autoconf(conf_get_autoheader_name(), + print_symbol_for_c, + &comment_style_c); + if (ret) + return ret; - name = getenv("KCONFIG_AUTOHEADER"); - if (!name) - name = "include/generated/autoconf.h"; - if (make_parent_dir(name)) - return 1; - if (rename(".tmpconfig.h", name)) - return 1; + ret = __conf_write_autoconf(conf_get_rustccfg_name(), + print_symbol_for_rustccfg, + NULL); + if (ret) + return ret; - if (make_parent_dir(autoconf_name)) - return 1; /* - * This must be the last step, kbuild has a dependency on auto.conf - * and this marks the successful completion of the previous steps. + * Create include/config/auto.conf. This must be the last step because + * Kbuild has a dependency on auto.conf and this marks the successful + * completion of the previous steps. */ - if (rename(".tmpconfig", autoconf_name)) - return 1; + ret = __conf_write_autoconf(conf_get_autoconfig_name(), + print_symbol_for_autoconf, + &comment_style_pound); + if (ret) + return ret; return 0; } -static int sym_change_count; +static bool conf_changed; static void (*conf_changed_callback)(void); -void sym_set_change_count(int count) +void conf_set_changed(bool val) { - int _sym_change_count = sym_change_count; - sym_change_count = count; - if (conf_changed_callback && - (bool)_sym_change_count != (bool)count) - conf_changed_callback(); -} + bool changed = conf_changed != val; -void sym_add_change_count(int count) -{ - sym_set_change_count(count + sym_change_count); + conf_changed = val; + + if (conf_changed_callback && changed) + conf_changed_callback(); } bool conf_get_changed(void) { - return sym_change_count; + return conf_changed; } void conf_set_changed_callback(void (*fn)(void)) @@ -1126,54 +1256,6 @@ 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); - - /* 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 property *prop; @@ -1193,146 +1275,3 @@ void set_all_choice_values(struct symbol *csym) /* 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 bool = y - * pty: probability of tristate = y - * ptm: probability of tristate = m - */ - - pby = 50; pty = ptm = 33; /* can't go as the default in switch-case - * below, otherwise gcc whines about - * -Wmaybe-uninitialized */ - if (mode == def_random) { - int n, p[3]; - char *env = getenv("KCONFIG_PROBABILITY"); - n = 0; - while( env && *env ) { - char *endp; - int tmp = strtol( env, &endp, 10 ); - if( tmp >= 0 && tmp <= 100 ) { - p[n++] = tmp; - } else { - errno = ERANGE; - perror( "KCONFIG_PROBABILITY" ); - exit( 1 ); - } - env = (*endp == ':') ? endp+1 : endp; - if( n >=3 ) { - break; - } - } - switch( n ) { - case 1: - pby = p[0]; ptm = pby/2; pty = pby-ptm; - break; - case 2: - pty = p[0]; ptm = p[1]; pby = pty + ptm; - break; - case 3: - pby = p[0]; pty = p[1]; ptm = p[2]; - break; - } - - if( pty+ptm > 100 ) { - errno = ERANGE; - perror( "KCONFIG_PROBABILITY" ); - exit( 1 ); - } - } - bool has_changed = false; - - for_all_symbols(i, sym) { - if (sym_has_value(sym) || (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; - break; - case def_mod: - sym->def[S_DEF_USER].tri = mod; - break; - case def_no: - if (sym->flags & SYMBOL_ALLNOCONFIG_Y) - sym->def[S_DEF_USER].tri = yes; - else - sym->def[S_DEF_USER].tri = no; - break; - case def_random: - 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; - } - 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 equals to mod then we can select several - * choice symbols in one block. - * In this case we do nothing. - * 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 (mode == def_random) - has_changed |= randomize_choice_values(csym); - else { - set_all_choice_values(csym); - has_changed = true; - } - } - - return has_changed; -} - -void conf_rewrite_mod_or_yes(enum conf_def_mode mode) -{ - struct symbol *sym; - int i; - tristate old_val = (mode == def_y2m) ? yes : mod; - tristate new_val = (mode == def_y2m) ? mod : yes; - - for_all_symbols(i, sym) { - if (sym_get_type(sym) == S_TRISTATE && - sym->def[S_DEF_USER].tri == old_val) - sym->def[S_DEF_USER].tri = new_val; - } - sym_clear_all_valid(); -} |