1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 4 */ 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 #include <xalloc.h> 15 #include "lkc.h" 16 #include "internal.h" 17 #include "preprocess.h" 18 19 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) 20 21 #define PRINTD 0x0001 22 #define DEBUG_PARSE 0x0002 23 24 int cdebug = PRINTD; 25 26 static void yyerror(const char *err); 27 static void zconf_error(const char *err, ...); 28 static bool zconf_endtoken(const char *tokenname, 29 const char *expected_tokenname); 30 31 struct menu *current_menu, *current_entry, *current_choice; 32 33 %} 34 35 %union 36 { 37 char *string; 38 struct symbol *symbol; 39 struct expr *expr; 40 struct menu *menu; 41 enum symbol_type type; 42 enum variable_flavor flavor; 43 } 44 45 %token <string> T_HELPTEXT 46 %token <string> T_WORD 47 %token <string> T_WORD_QUOTE 48 %token T_BOOL 49 %token T_CHOICE 50 %token T_CLOSE_PAREN 51 %token T_COLON_EQUAL 52 %token T_COMMENT 53 %token T_CONFIG 54 %token T_DEFAULT 55 %token T_DEF_BOOL 56 %token T_DEF_HEX 57 %token T_DEF_INT 58 %token T_DEF_STRING 59 %token T_DEF_TRISTATE 60 %token T_DEPENDS 61 %token T_ENDCHOICE 62 %token T_ENDIF 63 %token T_ENDMENU 64 %token T_HELP 65 %token T_HEX 66 %token T_IF 67 %token T_IMPLY 68 %token T_INT 69 %token T_MAINMENU 70 %token T_MENU 71 %token T_MENUCONFIG 72 %token T_MODULES 73 %token T_ON 74 %token T_OPEN_PAREN 75 %token T_PLUS_EQUAL 76 %token T_PROMPT 77 %token T_RANGE 78 %token T_SELECT 79 %token T_SOURCE 80 %token T_STRING 81 %token T_TRANSITIONAL 82 %token T_TRISTATE 83 %token T_VISIBLE 84 %token T_EOL 85 %token <string> T_ASSIGN_VAL 86 87 %left T_OR 88 %left T_AND 89 %left T_EQUAL T_UNEQUAL 90 %left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL 91 %nonassoc T_NOT 92 93 %type <symbol> nonconst_symbol 94 %type <symbol> symbol 95 %type <type> type default 96 %type <expr> expr 97 %type <expr> if_expr 98 %type <string> end 99 %type <menu> if_entry menu_entry choice_entry 100 %type <string> assign_val 101 %type <flavor> assign_op 102 103 %destructor { 104 fprintf(stderr, "%s:%d: missing end statement for this entry\n", 105 $$->filename, $$->lineno); 106 if (current_menu == $$) 107 menu_end_menu(); 108 } if_entry menu_entry choice_entry 109 110 %% 111 input: mainmenu_stmt stmt_list | stmt_list; 112 113 /* mainmenu entry */ 114 115 mainmenu_stmt: T_MAINMENU T_WORD_QUOTE T_EOL 116 { 117 menu_add_prompt(P_MENU, $2, NULL); 118 }; 119 120 stmt_list: 121 /* empty */ 122 | stmt_list assignment_stmt 123 | stmt_list choice_stmt 124 | stmt_list comment_stmt 125 | stmt_list config_stmt 126 | stmt_list if_stmt 127 | stmt_list menu_stmt 128 | stmt_list menuconfig_stmt 129 | stmt_list source_stmt 130 | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } 131 | stmt_list error T_EOL { zconf_error("invalid statement"); } 132 ; 133 134 stmt_list_in_choice: 135 /* empty */ 136 | stmt_list_in_choice comment_stmt 137 | stmt_list_in_choice config_stmt 138 | stmt_list_in_choice if_stmt_in_choice 139 | stmt_list_in_choice error T_EOL { zconf_error("invalid statement"); } 140 ; 141 142 /* config/menuconfig entry */ 143 144 config_entry_start: T_CONFIG nonconst_symbol T_EOL 145 { 146 menu_add_entry($2, M_NORMAL); 147 printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name); 148 }; 149 150 config_stmt: config_entry_start config_option_list 151 { 152 if (current_choice) { 153 if (!current_entry->prompt) { 154 fprintf(stderr, "%s:%d: error: choice member must have a prompt\n", 155 current_entry->filename, current_entry->lineno); 156 yynerrs++; 157 } 158 159 if (current_entry->sym->type != S_BOOLEAN) { 160 fprintf(stderr, "%s:%d: error: choice member must be bool\n", 161 current_entry->filename, current_entry->lineno); 162 yynerrs++; 163 } 164 165 list_add_tail(¤t_entry->sym->choice_link, 166 ¤t_choice->choice_members); 167 } 168 169 printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); 170 }; 171 172 menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL 173 { 174 menu_add_entry($2, M_MENU); 175 printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name); 176 }; 177 178 menuconfig_stmt: menuconfig_entry_start config_option_list 179 { 180 if (current_entry->prompt) 181 current_entry->prompt->type = P_MENU; 182 else 183 zconf_error("menuconfig statement without prompt"); 184 printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); 185 }; 186 187 config_option_list: 188 /* empty */ 189 | config_option_list config_option 190 | config_option_list depends 191 | config_option_list help 192 ; 193 194 config_option: type prompt_stmt_opt T_EOL 195 { 196 menu_set_type($1); 197 printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1); 198 }; 199 200 config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL 201 { 202 menu_add_prompt(P_PROMPT, $2, $3); 203 printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); 204 }; 205 206 config_option: T_TRANSITIONAL T_EOL 207 { 208 current_entry->sym->flags |= SYMBOL_TRANS; 209 printd(DEBUG_PARSE, "%s:%d:transitional\n", cur_filename, cur_lineno); 210 }; 211 212 config_option: default expr if_expr T_EOL 213 { 214 menu_add_expr(P_DEFAULT, $2, $3); 215 if ($1 != S_UNKNOWN) 216 menu_set_type($1); 217 printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno, 218 $1); 219 }; 220 221 config_option: T_SELECT nonconst_symbol if_expr T_EOL 222 { 223 menu_add_symbol(P_SELECT, $2, $3); 224 printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno); 225 }; 226 227 config_option: T_IMPLY nonconst_symbol if_expr T_EOL 228 { 229 menu_add_symbol(P_IMPLY, $2, $3); 230 printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno); 231 }; 232 233 config_option: T_RANGE symbol symbol if_expr T_EOL 234 { 235 menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); 236 printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno); 237 }; 238 239 config_option: T_MODULES T_EOL 240 { 241 if (modules_sym) 242 zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'", 243 current_entry->sym->name, modules_sym->name); 244 modules_sym = current_entry->sym; 245 }; 246 247 /* choice entry */ 248 249 choice: T_CHOICE T_EOL 250 { 251 struct symbol *sym = sym_lookup(NULL, 0); 252 253 menu_add_entry(sym, M_CHOICE); 254 menu_set_type(S_BOOLEAN); 255 INIT_LIST_HEAD(¤t_entry->choice_members); 256 257 printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno); 258 }; 259 260 choice_entry: choice choice_option_list 261 { 262 if (!current_entry->prompt) { 263 fprintf(stderr, "%s:%d: error: choice must have a prompt\n", 264 current_entry->filename, current_entry->lineno); 265 yynerrs++; 266 } 267 268 $$ = menu_add_menu(); 269 270 current_choice = current_entry; 271 }; 272 273 choice_end: end 274 { 275 current_choice = NULL; 276 277 if (zconf_endtoken($1, "choice")) { 278 menu_end_menu(); 279 printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno); 280 } 281 }; 282 283 choice_stmt: choice_entry stmt_list_in_choice choice_end 284 ; 285 286 choice_option_list: 287 /* empty */ 288 | choice_option_list choice_option 289 | choice_option_list depends 290 | choice_option_list help 291 ; 292 293 choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL 294 { 295 menu_add_prompt(P_PROMPT, $2, $3); 296 printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); 297 }; 298 299 choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL 300 { 301 menu_add_symbol(P_DEFAULT, $2, $3); 302 printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno); 303 }; 304 305 type: 306 T_BOOL { $$ = S_BOOLEAN; } 307 | T_TRISTATE { $$ = S_TRISTATE; } 308 | T_INT { $$ = S_INT; } 309 | T_HEX { $$ = S_HEX; } 310 | T_STRING { $$ = S_STRING; } 311 312 default: 313 T_DEFAULT { $$ = S_UNKNOWN; } 314 | T_DEF_BOOL { $$ = S_BOOLEAN; } 315 | T_DEF_HEX { $$ = S_HEX; } 316 | T_DEF_INT { $$ = S_INT; } 317 | T_DEF_STRING { $$ = S_STRING; } 318 | T_DEF_TRISTATE { $$ = S_TRISTATE; } 319 320 /* if entry */ 321 322 if_entry: T_IF expr T_EOL 323 { 324 printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno); 325 menu_add_entry(NULL, M_IF); 326 menu_add_dep($2, NULL); 327 $$ = menu_add_menu(); 328 }; 329 330 if_end: end 331 { 332 if (zconf_endtoken($1, "if")) { 333 menu_end_menu(); 334 printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno); 335 } 336 }; 337 338 if_stmt: if_entry stmt_list if_end 339 ; 340 341 if_stmt_in_choice: if_entry stmt_list_in_choice if_end 342 ; 343 344 /* menu entry */ 345 346 menu: T_MENU T_WORD_QUOTE T_EOL 347 { 348 menu_add_entry(NULL, M_MENU); 349 menu_add_prompt(P_MENU, $2, NULL); 350 printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno); 351 }; 352 353 menu_entry: menu menu_option_list 354 { 355 $$ = menu_add_menu(); 356 }; 357 358 menu_end: end 359 { 360 if (zconf_endtoken($1, "menu")) { 361 menu_end_menu(); 362 printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno); 363 } 364 }; 365 366 menu_stmt: menu_entry stmt_list menu_end 367 ; 368 369 menu_option_list: 370 /* empty */ 371 | menu_option_list visible 372 | menu_option_list depends 373 ; 374 375 source_stmt: T_SOURCE T_WORD_QUOTE T_EOL 376 { 377 printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2); 378 zconf_nextfile($2); 379 free($2); 380 }; 381 382 /* comment entry */ 383 384 comment: T_COMMENT T_WORD_QUOTE T_EOL 385 { 386 menu_add_entry(NULL, M_COMMENT); 387 menu_add_prompt(P_COMMENT, $2, NULL); 388 printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno); 389 }; 390 391 comment_stmt: comment comment_option_list 392 ; 393 394 comment_option_list: 395 /* empty */ 396 | comment_option_list depends 397 ; 398 399 /* help option */ 400 401 help_start: T_HELP T_EOL 402 { 403 printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno); 404 zconf_starthelp(); 405 }; 406 407 help: help_start T_HELPTEXT 408 { 409 if (current_entry->help) { 410 free(current_entry->help); 411 zconf_error("'%s' defined with more than one help text", 412 current_entry->sym->name ?: "<choice>"); 413 } 414 415 /* Is the help text empty or all whitespace? */ 416 if ($2[strspn($2, " \f\n\r\t\v")] == '\0') 417 zconf_error("'%s' defined with blank help text", 418 current_entry->sym->name ?: "<choice>"); 419 420 current_entry->help = $2; 421 }; 422 423 /* depends option */ 424 425 depends: T_DEPENDS T_ON expr if_expr T_EOL 426 { 427 menu_add_dep($3, $4); 428 printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno); 429 }; 430 431 /* visibility option */ 432 visible: T_VISIBLE if_expr T_EOL 433 { 434 menu_add_visibility($2); 435 }; 436 437 /* prompt statement */ 438 439 prompt_stmt_opt: 440 /* empty */ 441 | T_WORD_QUOTE if_expr 442 { 443 menu_add_prompt(P_PROMPT, $1, $2); 444 }; 445 446 end: T_ENDMENU T_EOL { $$ = "menu"; } 447 | T_ENDCHOICE T_EOL { $$ = "choice"; } 448 | T_ENDIF T_EOL { $$ = "if"; } 449 ; 450 451 if_expr: /* empty */ { $$ = NULL; } 452 | T_IF expr { $$ = $2; } 453 ; 454 455 expr: symbol { $$ = expr_alloc_symbol($1); } 456 | symbol T_LESS symbol { $$ = expr_alloc_comp(E_LTH, $1, $3); } 457 | symbol T_LESS_EQUAL symbol { $$ = expr_alloc_comp(E_LEQ, $1, $3); } 458 | symbol T_GREATER symbol { $$ = expr_alloc_comp(E_GTH, $1, $3); } 459 | symbol T_GREATER_EQUAL symbol { $$ = expr_alloc_comp(E_GEQ, $1, $3); } 460 | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); } 461 | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } 462 | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; } 463 | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); } 464 | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); } 465 | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); } 466 ; 467 468 /* For symbol definitions, selects, etc., where quotes are not accepted */ 469 nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }; 470 471 symbol: nonconst_symbol 472 | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); } 473 ; 474 475 /* assignment statement */ 476 477 assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); } 478 479 assign_op: 480 T_EQUAL { $$ = VAR_RECURSIVE; } 481 | T_COLON_EQUAL { $$ = VAR_SIMPLE; } 482 | T_PLUS_EQUAL { $$ = VAR_APPEND; } 483 ; 484 485 assign_val: 486 /* empty */ { $$ = xstrdup(""); }; 487 | T_ASSIGN_VAL 488 ; 489 490 %% 491 492 /** 493 * transitional_check_sanity - check transitional symbols have no other 494 * properties 495 * 496 * @menu: menu of the potentially transitional symbol 497 * 498 * Return: -1 if an error is found, 0 otherwise. 499 */ 500 static int transitional_check_sanity(const struct menu *menu) 501 { 502 struct property *prop; 503 504 if (!menu->sym || !(menu->sym->flags & SYMBOL_TRANS)) 505 return 0; 506 507 /* Check for depends and visible conditions. */ 508 if ((menu->dep && !expr_is_yes(menu->dep)) || 509 (menu->visibility && !expr_is_yes(menu->visibility))) { 510 fprintf(stderr, "%s:%d: error: %s", 511 menu->filename, menu->lineno, 512 "transitional symbols can only have help sections\n"); 513 return -1; 514 } 515 516 /* Check for any property other than "help". */ 517 for (prop = menu->sym->prop; prop; prop = prop->next) { 518 if (prop->type != P_COMMENT) { 519 fprintf(stderr, "%s:%d: error: %s", 520 prop->filename, prop->lineno, 521 "transitional symbols can only have help sections\n"); 522 return -1; 523 } 524 } 525 526 return 0; 527 } 528 529 /** 530 * choice_check_sanity - check sanity of a choice member 531 * 532 * @menu: menu of the choice member 533 * 534 * Return: -1 if an error is found, 0 otherwise. 535 */ 536 static int choice_check_sanity(const struct menu *menu) 537 { 538 struct property *prop; 539 int ret = 0; 540 541 for (prop = menu->sym->prop; prop; prop = prop->next) { 542 if (prop->type == P_DEFAULT) { 543 fprintf(stderr, "%s:%d: error: %s", 544 prop->filename, prop->lineno, 545 "defaults for choice values not supported\n"); 546 ret = -1; 547 } 548 549 if (prop->menu != menu && prop->type == P_PROMPT) { 550 fprintf(stderr, "%s:%d: error: %s", 551 prop->filename, prop->lineno, 552 "choice value must not have a prompt in another entry\n"); 553 ret = -1; 554 } 555 } 556 557 return ret; 558 } 559 560 void conf_parse(const char *name) 561 { 562 struct menu *menu; 563 564 autoconf_cmd = str_new(); 565 566 str_printf(&autoconf_cmd, "\ndeps_config := \\\n"); 567 568 zconf_initscan(name); 569 570 _menu_init(); 571 572 if (getenv("ZCONF_DEBUG")) 573 yydebug = 1; 574 yyparse(); 575 576 str_printf(&autoconf_cmd, 577 "\n" 578 "$(autoconfig): $(deps_config)\n" 579 "$(deps_config): ;\n"); 580 581 env_write_dep(&autoconf_cmd); 582 583 /* Variables are expanded in the parse phase. We can free them here. */ 584 variable_all_del(); 585 586 if (yynerrs) 587 exit(1); 588 if (!modules_sym) 589 modules_sym = &symbol_no; 590 591 if (!menu_has_prompt(&rootmenu)) { 592 current_entry = &rootmenu; 593 menu_add_prompt(P_MENU, "Main menu", NULL); 594 } 595 596 yynerrs += menu_finalize(); 597 598 menu_for_each_entry(menu) { 599 struct menu *child; 600 601 if (menu->sym && sym_check_deps(menu->sym)) 602 yynerrs++; 603 604 if (transitional_check_sanity(menu)) 605 yynerrs++; 606 607 if (menu->sym && sym_is_choice(menu->sym)) { 608 menu_for_each_sub_entry(child, menu) 609 if (child->sym && choice_check_sanity(child)) 610 yynerrs++; 611 } 612 } 613 614 if (yynerrs) 615 exit(1); 616 conf_set_changed(true); 617 } 618 619 static bool zconf_endtoken(const char *tokenname, 620 const char *expected_tokenname) 621 { 622 if (strcmp(tokenname, expected_tokenname)) { 623 zconf_error("unexpected '%s' within %s block", 624 tokenname, expected_tokenname); 625 yynerrs++; 626 return false; 627 } 628 if (strcmp(current_menu->filename, cur_filename)) { 629 zconf_error("'%s' in different file than '%s'", 630 tokenname, expected_tokenname); 631 fprintf(stderr, "%s:%d: location of the '%s'\n", 632 current_menu->filename, current_menu->lineno, 633 expected_tokenname); 634 yynerrs++; 635 return false; 636 } 637 return true; 638 } 639 640 static void zconf_error(const char *err, ...) 641 { 642 va_list ap; 643 644 yynerrs++; 645 fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno); 646 va_start(ap, err); 647 vfprintf(stderr, err, ap); 648 va_end(ap); 649 fprintf(stderr, "\n"); 650 } 651 652 static void yyerror(const char *err) 653 { 654 fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err); 655 } 656 657 static void print_quoted_string(FILE *out, const char *str) 658 { 659 const char *p; 660 int len; 661 662 putc('"', out); 663 while ((p = strchr(str, '"'))) { 664 len = p - str; 665 if (len) 666 fprintf(out, "%.*s", len, str); 667 fputs("\\\"", out); 668 str = p + 1; 669 } 670 fputs(str, out); 671 putc('"', out); 672 } 673 674 static void print_symbol(FILE *out, const struct menu *menu) 675 { 676 struct symbol *sym = menu->sym; 677 struct property *prop; 678 679 if (sym_is_choice(sym)) 680 fprintf(out, "\nchoice\n"); 681 else 682 fprintf(out, "\nconfig %s\n", sym->name); 683 switch (sym->type) { 684 case S_BOOLEAN: 685 fputs(" bool\n", out); 686 break; 687 case S_TRISTATE: 688 fputs(" tristate\n", out); 689 break; 690 case S_STRING: 691 fputs(" string\n", out); 692 break; 693 case S_INT: 694 fputs(" integer\n", out); 695 break; 696 case S_HEX: 697 fputs(" hex\n", out); 698 break; 699 default: 700 fputs(" ???\n", out); 701 break; 702 } 703 for (prop = sym->prop; prop; prop = prop->next) { 704 if (prop->menu != menu) 705 continue; 706 switch (prop->type) { 707 case P_PROMPT: 708 fputs(" prompt ", out); 709 print_quoted_string(out, prop->text); 710 if (!expr_is_yes(prop->visible.expr)) { 711 fputs(" if ", out); 712 expr_fprint(prop->visible.expr, out); 713 } 714 fputc('\n', out); 715 break; 716 case P_DEFAULT: 717 fputs( " default ", out); 718 expr_fprint(prop->expr, out); 719 if (!expr_is_yes(prop->visible.expr)) { 720 fputs(" if ", out); 721 expr_fprint(prop->visible.expr, out); 722 } 723 fputc('\n', out); 724 break; 725 case P_SELECT: 726 fputs( " select ", out); 727 expr_fprint(prop->expr, out); 728 fputc('\n', out); 729 break; 730 case P_IMPLY: 731 fputs( " imply ", out); 732 expr_fprint(prop->expr, out); 733 fputc('\n', out); 734 break; 735 case P_RANGE: 736 fputs( " range ", out); 737 expr_fprint(prop->expr, out); 738 fputc('\n', out); 739 break; 740 case P_MENU: 741 fputs( " menu ", out); 742 print_quoted_string(out, prop->text); 743 fputc('\n', out); 744 break; 745 default: 746 fprintf(out, " unknown prop %d!\n", prop->type); 747 break; 748 } 749 } 750 if (menu->help) { 751 int len = strlen(menu->help); 752 while (menu->help[--len] == '\n') 753 menu->help[len] = 0; 754 fprintf(out, " help\n%s\n", menu->help); 755 } 756 } 757 758 void zconfdump(FILE *out) 759 { 760 struct property *prop; 761 struct symbol *sym; 762 struct menu *menu; 763 764 menu = rootmenu.list; 765 while (menu) { 766 if ((sym = menu->sym)) 767 print_symbol(out, menu); 768 else if ((prop = menu->prompt)) { 769 switch (prop->type) { 770 case P_COMMENT: 771 fputs("\ncomment ", out); 772 print_quoted_string(out, prop->text); 773 fputs("\n", out); 774 break; 775 case P_MENU: 776 fputs("\nmenu ", out); 777 print_quoted_string(out, prop->text); 778 fputs("\n", out); 779 break; 780 default: 781 ; 782 } 783 if (!expr_is_yes(prop->visible.expr)) { 784 fputs(" depends ", out); 785 expr_fprint(prop->visible.expr, out); 786 fputc('\n', out); 787 } 788 } 789 790 if (menu->list) 791 menu = menu->list; 792 else if (menu->next) 793 menu = menu->next; 794 else while ((menu = menu->parent)) { 795 if (menu->prompt && menu->prompt->type == P_MENU) 796 fputs("\nendmenu\n", out); 797 if (menu->next) { 798 menu = menu->next; 799 break; 800 } 801 } 802 } 803 } 804