summaryrefslogtreecommitdiffstats
path: root/support/kconfig/confdata.c
diff options
context:
space:
mode:
Diffstat (limited to 'support/kconfig/confdata.c')
-rw-r--r--support/kconfig/confdata.c369
1 files changed, 247 insertions, 122 deletions
diff --git a/support/kconfig/confdata.c b/support/kconfig/confdata.c
index 54f20ca96..b7df92f9b 100644
--- a/support/kconfig/confdata.c
+++ b/support/kconfig/confdata.c
@@ -7,6 +7,7 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -14,7 +15,6 @@
#include <unistd.h>
#include <libgen.h>
-#define LKC_DIRECT_LINK
#include "lkc.h"
static void conf_warning(const char *fmt, ...)
@@ -127,6 +127,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
sym->flags |= def_flags;
break;
}
+ /* fall through */
case S_BOOLEAN:
if (p[0] == 'y') {
sym->def[def].tri = yes;
@@ -139,7 +140,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
break;
}
conf_warning("symbol value '%s' invalid for %s", p, sym->name);
- break;
+ return 1;
case S_OTHER:
if (*p != '"') {
for (p2 = p; *p2 && !isspace(*p2); p2++)
@@ -147,6 +148,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
sym->type = S_STRING;
goto done;
}
+ /* fall through */
case S_STRING:
if (*p++ != '"')
break;
@@ -161,6 +163,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
conf_warning("invalid string found");
return 1;
}
+ /* fall through */
case S_INT:
case S_HEX:
done:
@@ -178,10 +181,66 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
return 0;
}
+#define LINE_GROWTH 16
+static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
+{
+ char *nline;
+ size_t new_size = slen + 1;
+ if (new_size > *n) {
+ new_size += LINE_GROWTH - 1;
+ new_size *= 2;
+ nline = realloc(*lineptr, new_size);
+ if (!nline)
+ return -1;
+
+ *lineptr = nline;
+ *n = new_size;
+ }
+
+ (*lineptr)[slen] = c;
+
+ return 0;
+}
+
+static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
+{
+ char *line = *lineptr;
+ size_t slen = 0;
+
+ for (;;) {
+ int c = getc(stream);
+
+ switch (c) {
+ case '\n':
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ /* fall through */
+ case EOF:
+ if (add_byte('\0', &line, slen, n) < 0)
+ goto e_out;
+ *lineptr = line;
+ if (slen == 0)
+ return -1;
+ return slen;
+ default:
+ if (add_byte(c, &line, slen, n) < 0)
+ goto e_out;
+ slen++;
+ }
+ }
+
+e_out:
+ line[slen-1] = '\0';
+ *lineptr = line;
+ return -1;
+}
+
int conf_read_simple(const char *name, int def)
{
FILE *in = NULL;
- char line[1024];
+ char *line = NULL;
+ size_t line_asize = 0;
char *p, *p2;
struct symbol *sym;
int i, def_flags;
@@ -236,13 +295,14 @@ load:
case S_STRING:
if (sym->def[def].val)
free(sym->def[def].val);
+ /* fall through */
default:
sym->def[def].val = NULL;
sym->def[def].tri = no;
}
}
- while (fgets(line, sizeof(line), in)) {
+ while (compat_getline(&line, &line_asize, in) != -1) {
conf_lineno++;
sym = NULL;
if (line[0] == '#') {
@@ -330,6 +390,7 @@ setsym:
cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
}
}
+ free(line);
fclose(in);
if (modules_sym)
@@ -339,10 +400,8 @@ setsym:
int conf_read(const char *name)
{
- struct symbol *sym, *choice_sym;
- struct property *prop;
- struct expr *e;
- int i, flags;
+ struct symbol *sym;
+ int i;
sym_set_change_count(0);
@@ -352,7 +411,7 @@ int conf_read(const char *name)
for_all_symbols(i, sym) {
sym_calc_value(sym);
if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
- goto sym_ok;
+ continue;
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
/* check that calculated value agrees with saved value */
switch (sym->type) {
@@ -361,29 +420,18 @@ int conf_read(const char *name)
if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
break;
if (!sym_is_choice(sym))
- goto sym_ok;
+ continue;
+ /* fall through */
default:
if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
- goto sym_ok;
+ continue;
break;
}
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
/* no previous value and not saved */
- goto sym_ok;
+ continue;
conf_unsaved++;
/* maybe print value in verbose mode... */
- sym_ok:
- if (!sym_is_choice(sym))
- continue;
- /* The choice symbol only has a set value (and thus is not new)
- * if all its visible childs have values.
- */
- prop = sym_get_choice_prop(sym);
- flags = sym->flags;
- expr_list_for_each_sym(prop->expr, e, choice_sym)
- if (choice_sym->visible != no)
- flags &= choice_sym->flags;
- sym->flags &= flags | ~SYMBOL_DEF_USER;
}
for_all_symbols(i, sym) {
@@ -416,64 +464,191 @@ 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)
+/*
+ * 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)
{
- int l;
- if (headerfile)
- fprintf(out, "#define %s \"", name);
- else
- fprintf(out, "%s=\"", name);
- while (1) {
- l = strcspn(str, "\"\\");
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (*value == 'n') {
+ bool skip_unset = (arg != NULL);
+
+ if (!skip_unset)
+ fprintf(fp, "# %s is not set\n",
+ sym->name);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ fprintf(fp, "%s=%s\n", sym->name, value);
+}
+
+static void
+kconfig_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, "#");
if (l) {
- xfwrite(str, l, 1, out);
- str += l;
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
}
- if (!*str)
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
break;
- fprintf(out, "\\%c", *str++);
}
- fputs("\"\n", out);
}
-static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
+static struct conf_printer kconfig_printer_cb =
+{
+ .print_symbol = kconfig_print_symbol,
+ .print_comment = kconfig_print_comment,
+};
+
+/*
+ * Header printer
+ *
+ * This printer is used when generating the `include/generated/autoconf.h' file.
+ */
+static void
+header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
{
- const char *str;
switch (sym->type) {
case S_BOOLEAN:
- case S_TRISTATE:
- switch (sym_get_tristate_value(sym)) {
- case no:
- if (write_no)
- fprintf(out, "# %s is not set\n",
- sym->name);
- break;
- case mod:
- fprintf(out, "%s=m\n", sym->name);
- break;
- case yes:
- fprintf(out, "%s=y\n", sym->name);
+ case S_TRISTATE: {
+ const char *suffix = "";
+
+ switch (*value) {
+ case 'n':
break;
+ case 'm':
+ suffix = "_MODULE";
+ /* fall through */
+ default:
+ fprintf(fp, "#define %s%s 1\n",
+ sym->name, suffix);
}
break;
- case S_STRING:
- conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+ }
+ case S_HEX: {
+ const char *prefix = "";
+
+ if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
+ prefix = "0x";
+ fprintf(fp, "#define %s %s%s\n",
+ sym->name, prefix, value);
break;
- case S_HEX:
+ }
+ case S_STRING:
case S_INT:
- str = sym_get_string_value(sym);
- fprintf(out, "%s=%s\n", sym->name, str);
+ fprintf(fp, "#define %s %s\n",
+ sym->name, value);
break;
+ default:
+ break;
+ }
+
+}
+
+static void
+header_print_comment(FILE *fp, const char *value, void *arg)
+{
+ const char *p = value;
+ size_t l;
+
+ fprintf(fp, "/*\n");
+ for (;;) {
+ l = strcspn(p, "\n");
+ fprintf(fp, " *");
+ if (l) {
+ fprintf(fp, " ");
+ xfwrite(p, l, 1, fp);
+ p += l;
+ }
+ fprintf(fp, "\n");
+ if (*p++ == '\0')
+ break;
+ }
+ fprintf(fp, " */\n");
+}
+
+static struct conf_printer header_printer_cb =
+{
+ .print_symbol = header_print_symbol,
+ .print_comment = header_print_comment,
+};
+
+/*
+ * Tristate printer
+ *
+ * This printer is used when generating the `include/config/tristate.conf' file.
+ */
+static void
+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
+{
+
+ if (sym->type == S_TRISTATE && *value != 'n')
+ fprintf(fp, "%s=%c\n", sym->name, (char)toupper(*value));
+}
+
+static struct conf_printer tristate_printer_cb =
+{
+ .print_symbol = tristate_print_symbol,
+ .print_comment = kconfig_print_comment,
+};
+
+static void conf_write_symbol(FILE *fp, struct symbol *sym,
+ struct conf_printer *printer, void *printer_arg)
+{
+ const char *str;
+
+ switch (sym->type) {
case S_OTHER:
case S_UNKNOWN:
break;
+ case S_STRING:
+ str = sym_get_string_value(sym);
+ str = sym_escape_string_value(str);
+ printer->print_symbol(fp, sym, str, printer_arg);
+ free((void *)str);
+ break;
+ default:
+ str = sym_get_string_value(sym);
+ printer->print_symbol(fp, sym, str, printer_arg);
}
}
+static void
+conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
+{
+ char buf[256];
+
+ snprintf(buf, sizeof(buf),
+ "\n"
+ "Automatically generated file; DO NOT EDIT.\n"
+ "%s\n",
+ rootmenu.prompt->text);
+
+ printer->print_comment(fp, buf, printer_arg);
+}
+
/*
* Write out a minimal config.
* All values that has default values are skipped as this is redundant.
@@ -530,7 +705,7 @@ int conf_write_defconfig(const char *filename)
goto next_menu;
}
}
- conf_write_symbol(sym, out, true);
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
}
next_menu:
if (menu->list != NULL) {
@@ -598,11 +773,7 @@ int conf_write(const char *name)
if (!out)
return 1;
- fprintf(out, _("#\n"
- "# Automatically generated make config: don't edit\n"
- "# %s\n"
- "#\n"),
- rootmenu.prompt->text);
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
if (!conf_get_changed())
sym_clear_all_valid();
@@ -623,8 +794,8 @@ int conf_write(const char *name)
if (!(sym->flags & SYMBOL_WRITE))
goto next;
sym->flags &= ~SYMBOL_WRITE;
- /* Write config symbol to file */
- conf_write_symbol(sym, out, true);
+
+ conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
}
next:
@@ -788,7 +959,6 @@ err:
int conf_write_autoconf(void)
{
struct symbol *sym;
- const char *str;
const char *name;
FILE *out, *tristate, *out_h;
int i;
@@ -830,68 +1000,23 @@ int conf_write_autoconf(void)
return 1;
}
- fprintf(out, "#\n"
- "# Automatically generated make config: don't edit\n"
- "# %s\n"
- "#\n",
- rootmenu.prompt->text);
- fprintf(tristate, "#\n"
- "# Automatically generated - do not edit\n"
- "\n");
- fprintf(out_h, "/*\n"
- " * Automatically generated C config: don't edit\n"
- " * %s\n"
- " */\n",
- rootmenu.prompt->text);
+ conf_write_heading(out, &kconfig_printer_cb, NULL);
+
+ conf_write_heading(tristate, &tristate_printer_cb, NULL);
+
+ conf_write_heading(out_h, &header_printer_cb, NULL);
for_all_symbols(i, sym) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
continue;
- /* write symbol to config file */
- conf_write_symbol(sym, out, false);
+ /* write symbol to auto.conf, tristate and header files */
+ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
- /* update autoconf and tristate files */
- switch (sym->type) {
- case S_BOOLEAN:
- case S_TRISTATE:
- switch (sym_get_tristate_value(sym)) {
- case no:
- break;
- case mod:
- fprintf(tristate, "%s=M\n",
- sym->name);
- fprintf(out_h, "#define %s_MODULE 1\n",
- sym->name);
- break;
- case yes:
- if (sym->type == S_TRISTATE)
- fprintf(tristate,"%s=Y\n",
- sym->name);
- fprintf(out_h, "#define %s 1\n",
- sym->name);
- break;
- }
- break;
- case S_STRING:
- 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_h, "#define %s 0x%s\n",
- sym->name, str);
- break;
- }
- case S_INT:
- str = sym_get_string_value(sym);
- fprintf(out_h, "#define %s %s\n",
- sym->name, str);
- break;
- default:
- break;
- }
+ conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
+
+ conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
}
fclose(out);
fclose(tristate);