1%{ 2/* 3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 4 * Released under the terms of the GNU GPL v2.0. 5 */ 6 7#include <ctype.h> 8#include <stdarg.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <stdbool.h> 13 14#define LKC_DIRECT_LINK 15#include "lkc.h" 16 17#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) 18 19#define PRINTD 0x0001 20#define DEBUG_PARSE 0x0002 21 22int cdebug = PRINTD; 23 24extern int zconflex(void); 25static void zconfprint(const char *err, ...); 26static void zconf_error(const char *err, ...); 27static void zconferror(const char *err); 28static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); 29 30struct symbol *symbol_hash[257]; 31 32static struct menu *current_menu, *current_entry; 33 34#define YYDEBUG 0 35#if YYDEBUG 36#define YYERROR_VERBOSE 37#endif 38%} 39%expect 26 40 41%union 42{ 43 char *string; 44 struct file *file; 45 struct symbol *symbol; 46 struct expr *expr; 47 struct menu *menu; 48 struct kconf_id *id; 49} 50 51%token <id>T_MAINMENU 52%token <id>T_MENU 53%token <id>T_ENDMENU 54%token <id>T_SOURCE 55%token <id>T_CHOICE 56%token <id>T_ENDCHOICE 57%token <id>T_COMMENT 58%token <id>T_CONFIG 59%token <id>T_MENUCONFIG 60%token <id>T_HELP 61%token <string> T_HELPTEXT 62%token <id>T_IF 63%token <id>T_ENDIF 64%token <id>T_DEPENDS 65%token <id>T_REQUIRES 66%token <id>T_OPTIONAL 67%token <id>T_PROMPT 68%token <id>T_TYPE 69%token <id>T_DEFAULT 70%token <id>T_SELECT 71%token <id>T_RANGE 72%token <id>T_ON 73%token <string> T_WORD 74%token <string> T_WORD_QUOTE 75%token T_UNEQUAL 76%token T_CLOSE_PAREN 77%token T_OPEN_PAREN 78%token T_EOL 79 80%left T_OR 81%left T_AND 82%left T_EQUAL T_UNEQUAL 83%nonassoc T_NOT 84 85%type <string> prompt 86%type <symbol> symbol 87%type <expr> expr 88%type <expr> if_expr 89%type <id> end 90%type <id> option_name 91%type <menu> if_entry menu_entry choice_entry 92 93%destructor { 94 fprintf(stderr, "%s:%d: missing end statement for this entry\n", 95 $$->file->name, $$->lineno); 96 if (current_menu == $$) 97 menu_end_menu(); 98} if_entry menu_entry choice_entry 99 100%{ 101#include "zconf.hash.c" 102%} 103 104%% 105input: stmt_list; 106 107stmt_list: 108 /* empty */ 109 | stmt_list common_stmt 110 | stmt_list choice_stmt 111 | stmt_list menu_stmt 112 | stmt_list T_MAINMENU prompt nl 113 | stmt_list end { zconf_error("unexpected end statement"); } 114 | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } 115 | stmt_list option_name error T_EOL 116{ 117 zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); 118} 119 | stmt_list error T_EOL { zconf_error("invalid statement"); } 120; 121 122option_name: 123 T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT 124; 125 126common_stmt: 127 T_EOL 128 | if_stmt 129 | comment_stmt 130 | config_stmt 131 | menuconfig_stmt 132 | source_stmt 133; 134 135option_error: 136 T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); } 137 | error T_EOL { zconf_error("invalid option"); } 138; 139 140 141/* config/menuconfig entry */ 142 143config_entry_start: T_CONFIG T_WORD T_EOL 144{ 145 struct symbol *sym = sym_lookup($2, 0); 146 sym->flags |= SYMBOL_OPTIONAL; 147 menu_add_entry(sym); 148 printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); 149}; 150 151config_stmt: config_entry_start config_option_list 152{ 153 menu_end_entry(); 154 printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); 155}; 156 157menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL 158{ 159 struct symbol *sym = sym_lookup($2, 0); 160 sym->flags |= SYMBOL_OPTIONAL; 161 menu_add_entry(sym); 162 printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); 163}; 164 165menuconfig_stmt: menuconfig_entry_start config_option_list 166{ 167 if (current_entry->prompt) 168 current_entry->prompt->type = P_MENU; 169 else 170 zconfprint("warning: menuconfig statement without prompt"); 171 menu_end_entry(); 172 printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); 173}; 174 175config_option_list: 176 /* empty */ 177 | config_option_list config_option 178 | config_option_list depends 179 | config_option_list help 180 | config_option_list option_error 181 | config_option_list T_EOL 182; 183 184config_option: T_TYPE prompt_stmt_opt T_EOL 185{ 186 menu_set_type($1->stype); 187 printd(DEBUG_PARSE, "%s:%d:type(%u)\n", 188 zconf_curname(), zconf_lineno(), 189 $1->stype); 190}; 191 192config_option: T_PROMPT prompt if_expr T_EOL 193{ 194 menu_add_prompt(P_PROMPT, $2, $3); 195 printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); 196}; 197 198config_option: T_DEFAULT expr if_expr T_EOL 199{ 200 menu_add_expr(P_DEFAULT, $2, $3); 201 if ($1->stype != S_UNKNOWN) 202 menu_set_type($1->stype); 203 printd(DEBUG_PARSE, "%s:%d:default(%u)\n", 204 zconf_curname(), zconf_lineno(), 205 $1->stype); 206}; 207 208config_option: T_SELECT T_WORD if_expr T_EOL 209{ 210 menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); 211 printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); 212}; 213 214config_option: T_RANGE symbol symbol if_expr T_EOL 215{ 216 menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); 217 printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); 218}; 219 220/* choice entry */ 221 222choice: T_CHOICE T_EOL 223{ 224 struct symbol *sym = sym_lookup(NULL, 0); 225 sym->flags |= SYMBOL_CHOICE; 226 menu_add_entry(sym); 227 menu_add_expr(P_CHOICE, NULL, NULL); 228 printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); 229}; 230 231choice_entry: choice choice_option_list 232{ 233 $$ = menu_add_menu(); 234}; 235 236choice_end: end 237{ 238 if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { 239 menu_end_menu(); 240 printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); 241 } 242}; 243 244choice_stmt: choice_entry choice_block choice_end 245; 246 247choice_option_list: 248 /* empty */ 249 | choice_option_list choice_option 250 | choice_option_list depends 251 | choice_option_list help 252 | choice_option_list T_EOL 253 | choice_option_list option_error 254; 255 256choice_option: T_PROMPT prompt if_expr T_EOL 257{ 258 menu_add_prompt(P_PROMPT, $2, $3); 259 printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); 260}; 261 262choice_option: T_TYPE prompt_stmt_opt T_EOL 263{ 264 if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { 265 menu_set_type($1->stype); 266 printd(DEBUG_PARSE, "%s:%d:type(%u)\n", 267 zconf_curname(), zconf_lineno(), 268 $1->stype); 269 } else 270 YYERROR; 271}; 272 273choice_option: T_OPTIONAL T_EOL 274{ 275 current_entry->sym->flags |= SYMBOL_OPTIONAL; 276 printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); 277}; 278 279choice_option: T_DEFAULT T_WORD if_expr T_EOL 280{ 281 if ($1->stype == S_UNKNOWN) { 282 menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); 283 printd(DEBUG_PARSE, "%s:%d:default\n", 284 zconf_curname(), zconf_lineno()); 285 } else 286 YYERROR; 287}; 288 289choice_block: 290 /* empty */ 291 | choice_block common_stmt 292; 293 294/* if entry */ 295 296if_entry: T_IF expr nl 297{ 298 printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); 299 menu_add_entry(NULL); 300 menu_add_dep($2); 301 $$ = menu_add_menu(); 302}; 303 304if_end: end 305{ 306 if (zconf_endtoken($1, T_IF, T_ENDIF)) { 307 menu_end_menu(); 308 printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); 309 } 310}; 311 312if_stmt: if_entry if_block if_end 313; 314 315if_block: 316 /* empty */ 317 | if_block common_stmt 318 | if_block menu_stmt 319 | if_block choice_stmt 320; 321 322/* menu entry */ 323 324menu: T_MENU prompt T_EOL 325{ 326 menu_add_entry(NULL); 327 menu_add_prompt(P_MENU, $2, NULL); 328 printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); 329}; 330 331menu_entry: menu depends_list 332{ 333 $$ = menu_add_menu(); 334}; 335 336menu_end: end 337{ 338 if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { 339 menu_end_menu(); 340 printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); 341 } 342}; 343 344menu_stmt: menu_entry menu_block menu_end 345; 346 347menu_block: 348 /* empty */ 349 | menu_block common_stmt 350 | menu_block menu_stmt 351 | menu_block choice_stmt 352; 353 354source_stmt: T_SOURCE prompt T_EOL 355{ 356 printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); 357 zconf_nextfile($2); 358}; 359 360/* comment entry */ 361 362comment: T_COMMENT prompt T_EOL 363{ 364 menu_add_entry(NULL); 365 menu_add_prompt(P_COMMENT, $2, NULL); 366 printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); 367}; 368 369comment_stmt: comment depends_list 370{ 371 menu_end_entry(); 372}; 373 374/* help option */ 375 376help_start: T_HELP T_EOL 377{ 378 printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); 379 zconf_starthelp(); 380}; 381 382help: help_start T_HELPTEXT 383{ 384 current_entry->sym->help = $2; 385}; 386 387/* depends option */ 388 389depends_list: 390 /* empty */ 391 | depends_list depends 392 | depends_list T_EOL 393 | depends_list option_error 394; 395 396depends: T_DEPENDS T_ON expr T_EOL 397{ 398 menu_add_dep($3); 399 printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); 400} 401 | T_DEPENDS expr T_EOL 402{ 403 menu_add_dep($2); 404 printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno()); 405} 406 | T_REQUIRES expr T_EOL 407{ 408 menu_add_dep($2); 409 printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno()); 410}; 411 412/* prompt statement */ 413 414prompt_stmt_opt: 415 /* empty */ 416 | prompt if_expr 417{ 418 menu_add_prompt(P_PROMPT, $1, $2); 419}; 420 421prompt: T_WORD 422 | T_WORD_QUOTE 423; 424 425end: T_ENDMENU T_EOL { $$ = $1; } 426 | T_ENDCHOICE T_EOL { $$ = $1; } 427 | T_ENDIF T_EOL { $$ = $1; } 428; 429 430nl: 431 T_EOL 432 | nl T_EOL 433; 434 435if_expr: /* empty */ { $$ = NULL; } 436 | T_IF expr { $$ = $2; } 437; 438 439expr: symbol { $$ = expr_alloc_symbol($1); } 440 | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } 441 | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } 442 | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } 443 | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } 444 | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } 445 | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } 446; 447 448symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); } 449 | T_WORD_QUOTE { $$ = sym_lookup($1, 1); free($1); } 450; 451 452%% 453 454void conf_parse(const char *name) 455{ 456 struct symbol *sym; 457 int i; 458 459 zconf_initscan(name); 460 461 sym_init(); 462 menu_init(); 463 modules_sym = sym_lookup("MODULES", 0); 464 rootmenu.prompt = menu_add_prompt(P_MENU, "Busybox Configuration", NULL); 465 466#if YYDEBUG 467 if (getenv("ZCONF_DEBUG")) 468 zconfdebug = 1; 469#endif 470 zconfparse(); 471 if (zconfnerrs) 472 exit(1); 473 menu_finalize(&rootmenu); 474 for_all_symbols(i, sym) { 475 sym_check_deps(sym); 476 } 477 478 sym_change_count = 1; 479} 480 481const char *zconf_tokenname(int token) 482{ 483 switch (token) { 484 case T_MENU: return "menu"; 485 case T_ENDMENU: return "endmenu"; 486 case T_CHOICE: return "choice"; 487 case T_ENDCHOICE: return "endchoice"; 488 case T_IF: return "if"; 489 case T_ENDIF: return "endif"; 490 case T_DEPENDS: return "depends"; 491 } 492 return "<token>"; 493} 494 495static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken) 496{ 497 if (id->token != endtoken) { 498 zconf_error("unexpected '%s' within %s block", 499 kconf_id_strings + id->name, zconf_tokenname(starttoken)); 500 zconfnerrs++; 501 return false; 502 } 503 if (current_menu->file != current_file) { 504 zconf_error("'%s' in different file than '%s'", 505 kconf_id_strings + id->name, zconf_tokenname(starttoken)); 506 fprintf(stderr, "%s:%d: location of the '%s'\n", 507 current_menu->file->name, current_menu->lineno, 508 zconf_tokenname(starttoken)); 509 zconfnerrs++; 510 return false; 511 } 512 return true; 513} 514 515static void zconfprint(const char *err, ...) 516{ 517 va_list ap; 518 519 fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); 520 va_start(ap, err); 521 vfprintf(stderr, err, ap); 522 va_end(ap); 523 fprintf(stderr, "\n"); 524} 525 526static void zconf_error(const char *err, ...) 527{ 528 va_list ap; 529 530 zconfnerrs++; 531 fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); 532 va_start(ap, err); 533 vfprintf(stderr, err, ap); 534 va_end(ap); 535 fprintf(stderr, "\n"); 536} 537 538static void zconferror(const char *err) 539{ 540#if YYDEBUG 541 fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); 542#endif 543} 544 545void print_quoted_string(FILE *out, const char *str) 546{ 547 const char *p; 548 int len; 549 550 putc('"', out); 551 while ((p = strchr(str, '"'))) { 552 len = p - str; 553 if (len) 554 fprintf(out, "%.*s", len, str); 555 fputs("\\\"", out); 556 str = p + 1; 557 } 558 fputs(str, out); 559 putc('"', out); 560} 561 562void print_symbol(FILE *out, struct menu *menu) 563{ 564 struct symbol *sym = menu->sym; 565 struct property *prop; 566 567 if (sym_is_choice(sym)) 568 fprintf(out, "choice\n"); 569 else 570 fprintf(out, "config %s\n", sym->name); 571 switch (sym->type) { 572 case S_BOOLEAN: 573 fputs(" boolean\n", out); 574 break; 575 case S_TRISTATE: 576 fputs(" tristate\n", out); 577 break; 578 case S_STRING: 579 fputs(" string\n", out); 580 break; 581 case S_INT: 582 fputs(" integer\n", out); 583 break; 584 case S_HEX: 585 fputs(" hex\n", out); 586 break; 587 default: 588 fputs(" ???\n", out); 589 break; 590 } 591 for (prop = sym->prop; prop; prop = prop->next) { 592 if (prop->menu != menu) 593 continue; 594 switch (prop->type) { 595 case P_PROMPT: 596 fputs(" prompt ", out); 597 print_quoted_string(out, prop->text); 598 if (!expr_is_yes(prop->visible.expr)) { 599 fputs(" if ", out); 600 expr_fprint(prop->visible.expr, out); 601 } 602 fputc('\n', out); 603 break; 604 case P_DEFAULT: 605 fputs( " default ", out); 606 expr_fprint(prop->expr, out); 607 if (!expr_is_yes(prop->visible.expr)) { 608 fputs(" if ", out); 609 expr_fprint(prop->visible.expr, out); 610 } 611 fputc('\n', out); 612 break; 613 case P_CHOICE: 614 fputs(" #choice value\n", out); 615 break; 616 default: 617 fprintf(out, " unknown prop %d!\n", prop->type); 618 break; 619 } 620 } 621 if (sym->help) { 622 int len = strlen(sym->help); 623 while (sym->help[--len] == '\n') 624 sym->help[len] = 0; 625 fprintf(out, " help\n%s\n", sym->help); 626 } 627 fputc('\n', out); 628} 629 630void zconfdump(FILE *out) 631{ 632 struct property *prop; 633 struct symbol *sym; 634 struct menu *menu; 635 636 menu = rootmenu.list; 637 while (menu) { 638 if ((sym = menu->sym)) 639 print_symbol(out, menu); 640 else if ((prop = menu->prompt)) { 641 switch (prop->type) { 642 case P_COMMENT: 643 fputs("\ncomment ", out); 644 print_quoted_string(out, prop->text); 645 fputs("\n", out); 646 break; 647 case P_MENU: 648 fputs("\nmenu ", out); 649 print_quoted_string(out, prop->text); 650 fputs("\n", out); 651 break; 652 default: 653 ; 654 } 655 if (!expr_is_yes(prop->visible.expr)) { 656 fputs(" depends ", out); 657 expr_fprint(prop->visible.expr, out); 658 fputc('\n', out); 659 } 660 fputs("\n", out); 661 } 662 663 if (menu->list) 664 menu = menu->list; 665 else if (menu->next) 666 menu = menu->next; 667 else while ((menu = menu->parent)) { 668 if (menu->prompt && menu->prompt->type == P_MENU) 669 fputs("\nendmenu\n", out); 670 if (menu->next) { 671 menu = menu->next; 672 break; 673 } 674 } 675 } 676} 677 678#include "lex.zconf.c" 679#include "util.c" 680#include "confdata.c" 681#include "expr.c" 682#include "symbol.c" 683#include "menu.c" 684