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