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