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