Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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