kconfig: introduce specialized printer
Make conf_write_symbol() grammar agnostic to be able to use it from different
code path. These path pass a printer callback which will print a symbol's name
and its value in different format.
conf_write_symbol()'s job become mostly only to prepare a string for the
printer. This avoid to have to pass specialized flag to generic
functions
Signed-off-by: Arnaud Lacombe <lacombar@gmail.com>
[mmarek: rebased on top of de12518
(kconfig: autogenerated config_is_xxx
macro)]
Signed-off-by: Michal Marek <mmarek@suse.cz>
This commit is contained in:
Родитель
ec6452a5ec
Коммит
e54e692ba6
|
@ -422,64 +422,228 @@ int conf_read(const char *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a S_STRING */
|
/*
|
||||||
static void conf_write_string(bool headerfile, const char *name,
|
* Kconfig configuration printer
|
||||||
const char *str, FILE *out)
|
*
|
||||||
|
* 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%s \"", CONFIG_, name);
|
|
||||||
else
|
|
||||||
fprintf(out, "%s%s=\"", CONFIG_, name);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
l = strcspn(str, "\"\\");
|
|
||||||
if (l) {
|
|
||||||
xfwrite(str, l, 1, out);
|
|
||||||
str += l;
|
|
||||||
}
|
|
||||||
if (!*str)
|
|
||||||
break;
|
|
||||||
fprintf(out, "\\%c", *str++);
|
|
||||||
}
|
|
||||||
fputs("\"\n", out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
|
|
||||||
{
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
switch (sym->type) {
|
switch (sym->type) {
|
||||||
case S_BOOLEAN:
|
case S_BOOLEAN:
|
||||||
case S_TRISTATE:
|
case S_TRISTATE:
|
||||||
switch (sym_get_tristate_value(sym)) {
|
if (*value == 'n') {
|
||||||
case no:
|
bool skip_unset = (arg != NULL);
|
||||||
if (write_no)
|
|
||||||
fprintf(out, "# %s%s is not set\n",
|
if (!skip_unset)
|
||||||
|
fprintf(fp, "# %s%s is not set\n",
|
||||||
CONFIG_, sym->name);
|
CONFIG_, sym->name);
|
||||||
break;
|
return;
|
||||||
case mod:
|
|
||||||
fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
|
|
||||||
break;
|
|
||||||
case yes:
|
|
||||||
fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case S_STRING:
|
default:
|
||||||
conf_write_string(false, sym->name, sym_get_string_value(sym), out);
|
|
||||||
break;
|
break;
|
||||||
case S_HEX:
|
}
|
||||||
case S_INT:
|
|
||||||
str = sym_get_string_value(sym);
|
fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
|
||||||
fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
fprintf(fp, " ");
|
||||||
|
fwrite(p, l, 1, fp);
|
||||||
|
p += l;
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
if (*p++ == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *suffix = "";
|
||||||
|
|
||||||
|
switch (sym->type) {
|
||||||
|
case S_BOOLEAN:
|
||||||
|
case S_TRISTATE:
|
||||||
|
switch (*value) {
|
||||||
|
case 'n':
|
||||||
|
return;
|
||||||
|
case 'm':
|
||||||
|
suffix = "_MODULE";
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
value = "1";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "#define %s%s%s %s\n",
|
||||||
|
CONFIG_, sym->name, suffix, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, " ");
|
||||||
|
fwrite(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,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function-style header printer
|
||||||
|
*
|
||||||
|
* This printer is used to generate the config_is_xxx() function-style macros
|
||||||
|
* in `include/generated/autoconf.h'
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
header_function_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
char c;
|
||||||
|
char *tmp, *d;
|
||||||
|
|
||||||
|
switch (sym->type) {
|
||||||
|
case S_BOOLEAN:
|
||||||
|
case S_TRISTATE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (*value == 'm')
|
||||||
|
val = 2;
|
||||||
|
else if (*value == 'y')
|
||||||
|
val = 1;
|
||||||
|
|
||||||
|
d = strdup(CONFIG_);
|
||||||
|
tmp = d;
|
||||||
|
while ((c = *d)) {
|
||||||
|
*d = tolower(c);
|
||||||
|
d++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "#define %sis_", tmp);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
d = strdup(sym->name);
|
||||||
|
tmp = d;
|
||||||
|
while ((c = *d)) {
|
||||||
|
*d = tolower(c);
|
||||||
|
d++;
|
||||||
|
}
|
||||||
|
fprintf(fp, "%s%s() %d\n", tmp, (val > 1) ? "_module" : "",
|
||||||
|
val ? 1 : 0);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct conf_printer header_function_printer_cb =
|
||||||
|
{
|
||||||
|
.print_symbol = header_function_print_symbol,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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%s=%c\n", CONFIG_, 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_OTHER:
|
||||||
case S_UNKNOWN:
|
case S_UNKNOWN:
|
||||||
break;
|
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.
|
* Write out a minimal config.
|
||||||
* All values that has default values are skipped as this is redundant.
|
* All values that has default values are skipped as this is redundant.
|
||||||
|
@ -536,7 +700,7 @@ int conf_write_defconfig(const char *filename)
|
||||||
goto next_menu;
|
goto next_menu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conf_write_symbol(sym, out, true);
|
conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
|
||||||
}
|
}
|
||||||
next_menu:
|
next_menu:
|
||||||
if (menu->list != NULL) {
|
if (menu->list != NULL) {
|
||||||
|
@ -601,11 +765,7 @@ int conf_write(const char *name)
|
||||||
if (!out)
|
if (!out)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
fprintf(out, _("#\n"
|
conf_write_heading(out, &kconfig_printer_cb, NULL);
|
||||||
"# Automatically generated make config: don't edit\n"
|
|
||||||
"# %s\n"
|
|
||||||
"#\n"),
|
|
||||||
rootmenu.prompt->text);
|
|
||||||
|
|
||||||
if (!conf_get_changed())
|
if (!conf_get_changed())
|
||||||
sym_clear_all_valid();
|
sym_clear_all_valid();
|
||||||
|
@ -626,8 +786,8 @@ int conf_write(const char *name)
|
||||||
if (!(sym->flags & SYMBOL_WRITE))
|
if (!(sym->flags & SYMBOL_WRITE))
|
||||||
goto next;
|
goto next;
|
||||||
sym->flags &= ~SYMBOL_WRITE;
|
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:
|
next:
|
||||||
|
@ -773,33 +933,9 @@ out:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conf_write_function_autoconf(FILE *out, char* conf, char* name,
|
|
||||||
int val)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
char *tmp, *d;
|
|
||||||
|
|
||||||
d = strdup(conf);
|
|
||||||
tmp = d;
|
|
||||||
while ((c = *conf++))
|
|
||||||
*d++ = tolower(c);
|
|
||||||
|
|
||||||
fprintf(out, "#define %sis_", tmp);
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
d = strdup(name);
|
|
||||||
tmp = d;
|
|
||||||
while ((c = *name++))
|
|
||||||
*d++ = tolower(c);
|
|
||||||
fprintf(out, "%s%s() %d\n", tmp, (val > 1) ? "_module" : "",
|
|
||||||
val ? 1 : 0);
|
|
||||||
free(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
int conf_write_autoconf(void)
|
int conf_write_autoconf(void)
|
||||||
{
|
{
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
const char *str;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
FILE *out, *tristate, *out_h;
|
FILE *out, *tristate, *out_h;
|
||||||
int i;
|
int i;
|
||||||
|
@ -828,72 +964,24 @@ int conf_write_autoconf(void)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(out, "#\n"
|
conf_write_heading(out, &kconfig_printer_cb, NULL);
|
||||||
"# Automatically generated make config: don't edit\n"
|
|
||||||
"# %s\n"
|
conf_write_heading(tristate, &tristate_printer_cb, NULL);
|
||||||
"#\n",
|
|
||||||
rootmenu.prompt->text);
|
conf_write_heading(out_h, &header_printer_cb, NULL);
|
||||||
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);
|
|
||||||
|
|
||||||
for_all_symbols(i, sym) {
|
for_all_symbols(i, sym) {
|
||||||
int fct_val = 0;
|
|
||||||
sym_calc_value(sym);
|
sym_calc_value(sym);
|
||||||
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
|
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* write symbol to config file */
|
/* write symbol to auto.conf, tristate and header files */
|
||||||
conf_write_symbol(sym, out, false);
|
conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
|
||||||
|
|
||||||
/* update autoconf and tristate files */
|
conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1);
|
||||||
switch (sym->type) {
|
|
||||||
case S_BOOLEAN:
|
conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
|
||||||
case S_TRISTATE:
|
conf_write_symbol(out_h, sym, &header_function_printer_cb, NULL);
|
||||||
switch (sym_get_tristate_value(sym)) {
|
|
||||||
case no:
|
|
||||||
break;
|
|
||||||
case mod:
|
|
||||||
fprintf(tristate, "%s%s=M\n",
|
|
||||||
CONFIG_, sym->name);
|
|
||||||
fprintf(out_h, "#define %s%s_MODULE 1\n",
|
|
||||||
CONFIG_, sym->name);
|
|
||||||
fct_val = 2;
|
|
||||||
break;
|
|
||||||
case yes:
|
|
||||||
if (sym->type == S_TRISTATE)
|
|
||||||
fprintf(tristate,"%s%s=Y\n",
|
|
||||||
CONFIG_, sym->name);
|
|
||||||
fprintf(out_h, "#define %s%s 1\n",
|
|
||||||
CONFIG_, sym->name);
|
|
||||||
fct_val = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
conf_write_function_autoconf(out_h, CONFIG_, sym->name, fct_val);
|
|
||||||
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%s 0x%s\n",
|
|
||||||
CONFIG_, sym->name, str);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case S_INT:
|
|
||||||
str = sym_get_string_value(sym);
|
|
||||||
fprintf(out_h, "#define %s%s %s\n",
|
|
||||||
CONFIG_, sym->name, str);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fclose(out);
|
fclose(out);
|
||||||
fclose(tristate);
|
fclose(tristate);
|
||||||
|
|
|
@ -87,6 +87,11 @@ void sym_set_change_count(int count);
|
||||||
void sym_add_change_count(int count);
|
void sym_add_change_count(int count);
|
||||||
void conf_set_all_new_symbols(enum conf_def_mode mode);
|
void conf_set_all_new_symbols(enum conf_def_mode mode);
|
||||||
|
|
||||||
|
struct conf_printer {
|
||||||
|
void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
|
||||||
|
void (*print_comment)(FILE *, const char *, void *);
|
||||||
|
};
|
||||||
|
|
||||||
/* confdata.c and expr.c */
|
/* confdata.c and expr.c */
|
||||||
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
|
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@ P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
|
||||||
P(sym_lookup,struct symbol *,(const char *name, int flags));
|
P(sym_lookup,struct symbol *,(const char *name, int flags));
|
||||||
P(sym_find,struct symbol *,(const char *name));
|
P(sym_find,struct symbol *,(const char *name));
|
||||||
P(sym_expand_string_value,const char *,(const char *in));
|
P(sym_expand_string_value,const char *,(const char *in));
|
||||||
|
P(sym_escape_string_value, const char *,(const char *in));
|
||||||
P(sym_re_search,struct symbol **,(const char *pattern));
|
P(sym_re_search,struct symbol **,(const char *pattern));
|
||||||
P(sym_type_name,const char *,(enum symbol_type type));
|
P(sym_type_name,const char *,(enum symbol_type type));
|
||||||
P(sym_calc_value,void,(struct symbol *sym));
|
P(sym_calc_value,void,(struct symbol *sym));
|
||||||
|
|
|
@ -750,7 +750,8 @@ const char *sym_get_string_value(struct symbol *sym)
|
||||||
case no:
|
case no:
|
||||||
return "n";
|
return "n";
|
||||||
case mod:
|
case mod:
|
||||||
return "m";
|
sym_calc_value(modules_sym);
|
||||||
|
return (modules_sym->curr.tri == no) ? "n" : "m";
|
||||||
case yes:
|
case yes:
|
||||||
return "y";
|
return "y";
|
||||||
}
|
}
|
||||||
|
@ -892,6 +893,49 @@ const char *sym_expand_string_value(const char *in)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *sym_escape_string_value(const char *in)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
size_t reslen;
|
||||||
|
char *res;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
reslen = strlen(in) + strlen("\"\"") + 1;
|
||||||
|
|
||||||
|
p = in;
|
||||||
|
for (;;) {
|
||||||
|
l = strcspn(p, "\"\\");
|
||||||
|
p += l;
|
||||||
|
|
||||||
|
if (p[0] == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
reslen++;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = malloc(reslen);
|
||||||
|
res[0] = '\0';
|
||||||
|
|
||||||
|
strcat(res, "\"");
|
||||||
|
|
||||||
|
p = in;
|
||||||
|
for (;;) {
|
||||||
|
l = strcspn(p, "\"\\");
|
||||||
|
strncat(res, p, l);
|
||||||
|
p += l;
|
||||||
|
|
||||||
|
if (p[0] == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
strcat(res, "\\");
|
||||||
|
strncat(res, p++, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(res, "\"");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
struct symbol **sym_re_search(const char *pattern)
|
struct symbol **sym_re_search(const char *pattern)
|
||||||
{
|
{
|
||||||
struct symbol *sym, **sym_arr = NULL;
|
struct symbol *sym, **sym_arr = NULL;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче