Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798/* SPDX-License-Identifier: GPL-2.0 *//* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> */%{
#include <ctype.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>
#include <xalloc.h>#include "lkc.h"#include "internal.h"#include "preprocess.h"
#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
#define PRINTD 0x0001#define DEBUG_PARSE 0x0002
int cdebug = PRINTD;
static void yyerror(const char *err);static void zconf_error(const char *err, ...);static bool zconf_endtoken(const char *tokenname, const char *expected_tokenname);
struct menu *current_menu, *current_entry, *current_choice;
%}
%union{ char *string; struct symbol *symbol; struct expr *expr; struct menu *menu; enum symbol_type type; enum variable_flavor flavor;}
%token <string> T_HELPTEXT%token <string> T_WORD%token <string> T_WORD_QUOTE%token T_BOOL%token T_CHOICE%token T_CLOSE_PAREN%token T_COLON_EQUAL%token T_COMMENT%token T_CONFIG%token T_DEFAULT%token T_DEF_BOOL%token T_DEF_TRISTATE%token T_DEPENDS%token T_ENDCHOICE%token T_ENDIF%token T_ENDMENU%token T_HELP%token T_HEX%token T_IF%token T_IMPLY%token T_INT%token T_MAINMENU%token T_MENU%token T_MENUCONFIG%token T_MODULES%token T_ON%token T_OPEN_PAREN%token T_PLUS_EQUAL%token T_PROMPT%token T_RANGE%token T_SELECT%token T_SOURCE%token T_STRING%token T_TRANSITIONAL%token T_TRISTATE%token T_VISIBLE%token T_EOL%token <string> T_ASSIGN_VAL
%left T_OR%left T_AND%left T_EQUAL T_UNEQUAL%left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL%nonassoc T_NOT
%type <symbol> nonconst_symbol%type <symbol> symbol%type <type> type default%type <expr> expr%type <expr> if_expr%type <string> end%type <menu> if_entry menu_entry choice_entry%type <string> assign_val%type <flavor> assign_op
%destructor { fprintf(stderr, "%s:%d: missing end statement for this entry\n", $$->filename, $$->lineno); if (current_menu == $$) menu_end_menu();} if_entry menu_entry choice_entry
%%input: mainmenu_stmt stmt_list | stmt_list;
/* mainmenu entry */
mainmenu_stmt: T_MAINMENU T_WORD_QUOTE T_EOL{ menu_add_prompt(P_MENU, $2, NULL);};
stmt_list: /* empty */ | stmt_list assignment_stmt | stmt_list choice_stmt | stmt_list comment_stmt | stmt_list config_stmt | stmt_list if_stmt | stmt_list menu_stmt | stmt_list menuconfig_stmt | stmt_list source_stmt | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } | stmt_list error T_EOL { zconf_error("invalid statement"); };
stmt_list_in_choice: /* empty */ | stmt_list_in_choice comment_stmt | stmt_list_in_choice config_stmt | stmt_list_in_choice if_stmt_in_choice | stmt_list_in_choice error T_EOL { zconf_error("invalid statement"); };
/* config/menuconfig entry */
config_entry_start: T_CONFIG nonconst_symbol T_EOL{ menu_add_entry($2, M_NORMAL); printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);};
config_stmt: config_entry_start config_option_list{ if (current_choice) { if (!current_entry->prompt) { fprintf(stderr, "%s:%d: error: choice member must have a prompt\n", current_entry->filename, current_entry->lineno); yynerrs++; }
if (current_entry->sym->type != S_BOOLEAN) { fprintf(stderr, "%s:%d: error: choice member must be bool\n", current_entry->filename, current_entry->lineno); yynerrs++; }
list_add_tail(¤t_entry->sym->choice_link, ¤t_choice->choice_members); }
printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);};
menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL{ menu_add_entry($2, M_MENU); printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);};
menuconfig_stmt: menuconfig_entry_start config_option_list{ if (current_entry->prompt) current_entry->prompt->type = P_MENU; else zconf_error("menuconfig statement without prompt"); printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);};
config_option_list: /* empty */ | config_option_list config_option | config_option_list depends | config_option_list help;
config_option: type prompt_stmt_opt T_EOL{ menu_set_type($1); printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);};
config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL{ menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);};
config_option: T_TRANSITIONAL T_EOL{ current_entry->sym->flags |= SYMBOL_TRANS; printd(DEBUG_PARSE, "%s:%d:transitional\n", cur_filename, cur_lineno);};
config_option: default expr if_expr T_EOL{ menu_add_expr(P_DEFAULT, $2, $3); if ($1 != S_UNKNOWN) menu_set_type($1); printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno, $1);};
config_option: T_SELECT nonconst_symbol if_expr T_EOL{ menu_add_symbol(P_SELECT, $2, $3); printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno);};
config_option: T_IMPLY nonconst_symbol if_expr T_EOL{ menu_add_symbol(P_IMPLY, $2, $3); printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno);};
config_option: T_RANGE symbol symbol if_expr T_EOL{ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno);};
config_option: T_MODULES T_EOL{ if (modules_sym) zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'", current_entry->sym->name, modules_sym->name); modules_sym = current_entry->sym;};
/* choice entry */
choice: T_CHOICE T_EOL{ struct symbol *sym = sym_lookup(NULL, 0);
menu_add_entry(sym, M_CHOICE); menu_set_type(S_BOOLEAN); INIT_LIST_HEAD(¤t_entry->choice_members);
printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);};
choice_entry: choice choice_option_list{ if (!current_entry->prompt) { fprintf(stderr, "%s:%d: error: choice must have a prompt\n", current_entry->filename, current_entry->lineno); yynerrs++; }
$$ = menu_add_menu();
current_choice = current_entry;};
choice_end: end{ current_choice = NULL;
if (zconf_endtoken($1, "choice")) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno); }};
choice_stmt: choice_entry stmt_list_in_choice choice_end;
choice_option_list: /* empty */ | choice_option_list choice_option | choice_option_list depends | choice_option_list help;
choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL{ menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);};
choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL{ menu_add_symbol(P_DEFAULT, $2, $3); printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno);};
type: T_BOOL { $$ = S_BOOLEAN; } | T_TRISTATE { $$ = S_TRISTATE; } | T_INT { $$ = S_INT; } | T_HEX { $$ = S_HEX; } | T_STRING { $$ = S_STRING; }
default: T_DEFAULT { $$ = S_UNKNOWN; } | T_DEF_BOOL { $$ = S_BOOLEAN; } | T_DEF_TRISTATE { $$ = S_TRISTATE; }
/* if entry */
if_entry: T_IF expr T_EOL{ printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno); menu_add_entry(NULL, M_IF); menu_add_dep($2, NULL); $$ = menu_add_menu();};
if_end: end{ if (zconf_endtoken($1, "if")) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno); }};
if_stmt: if_entry stmt_list if_end;
if_stmt_in_choice: if_entry stmt_list_in_choice if_end;
/* menu entry */
menu: T_MENU T_WORD_QUOTE T_EOL{ menu_add_entry(NULL, M_MENU); menu_add_prompt(P_MENU, $2, NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);};
menu_entry: menu menu_option_list{ $$ = menu_add_menu();};
menu_end: end{ if (zconf_endtoken($1, "menu")) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno); }};
menu_stmt: menu_entry stmt_list menu_end;
menu_option_list: /* empty */ | menu_option_list visible | menu_option_list depends;
source_stmt: T_SOURCE T_WORD_QUOTE T_EOL{ printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2); zconf_nextfile($2); free($2);};
/* comment entry */
comment: T_COMMENT T_WORD_QUOTE T_EOL{ menu_add_entry(NULL, M_COMMENT); menu_add_prompt(P_COMMENT, $2, NULL); printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);};
comment_stmt: comment comment_option_list;
comment_option_list: /* empty */ | comment_option_list depends;
/* help option */
help_start: T_HELP T_EOL{ printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno); zconf_starthelp();};
help: help_start T_HELPTEXT{ if (current_entry->help) { free(current_entry->help); zconf_error("'%s' defined with more than one help text", current_entry->sym->name ?: "<choice>"); }
/* Is the help text empty or all whitespace? */ if ($2[strspn($2, " \f\n\r\t\v")] == '\0') zconf_error("'%s' defined with blank help text", current_entry->sym->name ?: "<choice>");
current_entry->help = $2;};
/* depends option */
depends: T_DEPENDS T_ON expr if_expr T_EOL{ menu_add_dep($3, $4); printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);};
/* visibility option */visible: T_VISIBLE if_expr T_EOL{ menu_add_visibility($2);};
/* prompt statement */
prompt_stmt_opt: /* empty */ | T_WORD_QUOTE if_expr{ menu_add_prompt(P_PROMPT, $1, $2);};
end: T_ENDMENU T_EOL { $$ = "menu"; } | T_ENDCHOICE T_EOL { $$ = "choice"; } | T_ENDIF T_EOL { $$ = "if"; };
if_expr: /* empty */ { $$ = NULL; } | T_IF expr { $$ = $2; };
expr: symbol { $$ = expr_alloc_symbol($1); } | symbol T_LESS symbol { $$ = expr_alloc_comp(E_LTH, $1, $3); } | symbol T_LESS_EQUAL symbol { $$ = expr_alloc_comp(E_LEQ, $1, $3); } | symbol T_GREATER symbol { $$ = expr_alloc_comp(E_GTH, $1, $3); } | symbol T_GREATER_EQUAL symbol { $$ = expr_alloc_comp(E_GEQ, $1, $3); } | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); };
/* For symbol definitions, selects, etc., where quotes are not accepted */nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); };
symbol: nonconst_symbol | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); };
/* assignment statement */
assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); }
assign_op: T_EQUAL { $$ = VAR_RECURSIVE; } | T_COLON_EQUAL { $$ = VAR_SIMPLE; } | T_PLUS_EQUAL { $$ = VAR_APPEND; };
assign_val: /* empty */ { $$ = xstrdup(""); }; | T_ASSIGN_VAL;
%%
/** * transitional_check_sanity - check transitional symbols have no other * properties * * @menu: menu of the potentially transitional symbol * * Return: -1 if an error is found, 0 otherwise. */static int transitional_check_sanity(const struct menu *menu){ struct property *prop;
if (!menu->sym || !(menu->sym->flags & SYMBOL_TRANS)) return 0;
/* Check for depends and visible conditions. */ if ((menu->dep && !expr_is_yes(menu->dep)) || (menu->visibility && !expr_is_yes(menu->visibility))) { fprintf(stderr, "%s:%d: error: %s", menu->filename, menu->lineno, "transitional symbols can only have help sections\n"); return -1; }
/* Check for any property other than "help". */ for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->type != P_COMMENT) { fprintf(stderr, "%s:%d: error: %s", prop->filename, prop->lineno, "transitional symbols can only have help sections\n"); return -1; } }
return 0;}
/** * choice_check_sanity - check sanity of a choice member * * @menu: menu of the choice member * * Return: -1 if an error is found, 0 otherwise. */static int choice_check_sanity(const struct menu *menu){ struct property *prop; int ret = 0;
for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->type == P_DEFAULT) { fprintf(stderr, "%s:%d: error: %s", prop->filename, prop->lineno, "defaults for choice values not supported\n"); ret = -1; }
if (prop->menu != menu && prop->type == P_PROMPT) { fprintf(stderr, "%s:%d: error: %s", prop->filename, prop->lineno, "choice value must not have a prompt in another entry\n"); ret = -1; } }
return ret;}
void conf_parse(const char *name){ struct menu *menu;
autoconf_cmd = str_new();
str_printf(&autoconf_cmd, "\ndeps_config := \\\n");
zconf_initscan(name);
_menu_init();
if (getenv("ZCONF_DEBUG")) yydebug = 1; yyparse();
str_printf(&autoconf_cmd, "\n" "$(autoconfig): $(deps_config)\n" "$(deps_config): ;\n");
env_write_dep(&autoconf_cmd);
/* Variables are expanded in the parse phase. We can free them here. */ variable_all_del();
if (yynerrs) exit(1); if (!modules_sym) modules_sym = &symbol_no;
if (!menu_has_prompt(&rootmenu)) { current_entry = &rootmenu; menu_add_prompt(P_MENU, "Main menu", NULL); }
menu_finalize();
menu_for_each_entry(menu) { struct menu *child;
if (menu->sym && sym_check_deps(menu->sym)) yynerrs++;
if (transitional_check_sanity(menu)) yynerrs++;
if (menu->sym && sym_is_choice(menu->sym)) { menu_for_each_sub_entry(child, menu) if (child->sym && choice_check_sanity(child)) yynerrs++; } }
if (yynerrs) exit(1); conf_set_changed(true);}
static bool zconf_endtoken(const char *tokenname, const char *expected_tokenname){ if (strcmp(tokenname, expected_tokenname)) { zconf_error("unexpected '%s' within %s block", tokenname, expected_tokenname); yynerrs++; return false; } if (strcmp(current_menu->filename, cur_filename)) { zconf_error("'%s' in different file than '%s'", tokenname, expected_tokenname); fprintf(stderr, "%s:%d: location of the '%s'\n", current_menu->filename, current_menu->lineno, expected_tokenname); yynerrs++; return false; } return true;}
static void zconf_error(const char *err, ...){ va_list ap;
yynerrs++; fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); fprintf(stderr, "\n");}
static void yyerror(const char *err){ fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err);}
static void print_quoted_string(FILE *out, const char *str){ const char *p; int len;
putc('"', out); while ((p = strchr(str, '"'))) { len = p - str; if (len) fprintf(out, "%.*s", len, str); fputs("\\\"", out); str = p + 1; } fputs(str, out); putc('"', out);}
static void print_symbol(FILE *out, const struct menu *menu){ struct symbol *sym = menu->sym; struct property *prop;
if (sym_is_choice(sym)) fprintf(out, "\nchoice\n"); else fprintf(out, "\nconfig %s\n", sym->name); switch (sym->type) { case S_BOOLEAN: fputs(" bool\n", out); break; case S_TRISTATE: fputs(" tristate\n", out); break; case S_STRING: fputs(" string\n", out); break; case S_INT: fputs(" integer\n", out); break; case S_HEX: fputs(" hex\n", out); break; default: fputs(" ???\n", out); break; } for (prop = sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; switch (prop->type) { case P_PROMPT: fputs(" prompt ", out); print_quoted_string(out, prop->text); if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_DEFAULT: fputs( " default ", out); expr_fprint(prop->expr, out); if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_SELECT: fputs( " select ", out); expr_fprint(prop->expr, out); fputc('\n', out); break; case P_IMPLY: fputs( " imply ", out); expr_fprint(prop->expr, out); fputc('\n', out); break; case P_RANGE: fputs( " range ", out); expr_fprint(prop->expr, out); fputc('\n', out); break; case P_MENU: fputs( " menu ", out); print_quoted_string(out, prop->text); fputc('\n', out); break; default: fprintf(out, " unknown prop %d!\n", prop->type); break; } } if (menu->help) { int len = strlen(menu->help); while (menu->help[--len] == '\n') menu->help[len] = 0; fprintf(out, " help\n%s\n", menu->help); }}
void zconfdump(FILE *out){ struct property *prop; struct symbol *sym; struct menu *menu;
menu = rootmenu.list; while (menu) { if ((sym = menu->sym)) print_symbol(out, menu); else if ((prop = menu->prompt)) { switch (prop->type) { case P_COMMENT: fputs("\ncomment ", out); print_quoted_string(out, prop->text); fputs("\n", out); break; case P_MENU: fputs("\nmenu ", out); print_quoted_string(out, prop->text); fputs("\n", out); break; default: ; } if (!expr_is_yes(prop->visible.expr)) { fputs(" depends ", out); expr_fprint(prop->visible.expr, out); fputc('\n', out); } }
if (menu->list) menu = menu->list; else if (menu->next) menu = menu->next; else while ((menu = menu->parent)) { if (menu->prompt && menu->prompt->type == P_MENU) fputs("\nendmenu\n", out); if (menu->next) { menu = menu->next; break; } } }}