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