1769a1c02SMasahiro Yamada /* SPDX-License-Identifier: GPL-2.0 */
2769a1c02SMasahiro Yamada /*
3769a1c02SMasahiro Yamada * Copyright (C) 2002 Roman Zippel <[email protected]>
4769a1c02SMasahiro Yamada */
5769a1c02SMasahiro Yamada %{
6769a1c02SMasahiro Yamada
7769a1c02SMasahiro Yamada #include <ctype.h>
8769a1c02SMasahiro Yamada #include <stdarg.h>
9769a1c02SMasahiro Yamada #include <stdio.h>
10769a1c02SMasahiro Yamada #include <stdlib.h>
11769a1c02SMasahiro Yamada #include <string.h>
12769a1c02SMasahiro Yamada #include <stdbool.h>
13769a1c02SMasahiro Yamada
14a9d83d74SMasahiro Yamada #include <xalloc.h>
15769a1c02SMasahiro Yamada #include "lkc.h"
16a77a05dcSMasahiro Yamada #include "internal.h"
17d3d16228SMasahiro Yamada #include "preprocess.h"
18769a1c02SMasahiro Yamada
19769a1c02SMasahiro Yamada #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
20769a1c02SMasahiro Yamada
21769a1c02SMasahiro Yamada #define PRINTD 0x0001
22769a1c02SMasahiro Yamada #define DEBUG_PARSE 0x0002
23769a1c02SMasahiro Yamada
24769a1c02SMasahiro Yamada int cdebug = PRINTD;
25769a1c02SMasahiro Yamada
26769a1c02SMasahiro Yamada static void yyerror(const char *err);
27769a1c02SMasahiro Yamada static void zconf_error(const char *err, ...);
28769a1c02SMasahiro Yamada static bool zconf_endtoken(const char *tokenname,
29769a1c02SMasahiro Yamada const char *expected_tokenname);
30769a1c02SMasahiro Yamada
319b114520SMasahiro Yamada struct menu *current_menu, *current_entry, *current_choice;
32700e7a8dSMasahiro Yamada
33769a1c02SMasahiro Yamada %}
34769a1c02SMasahiro Yamada
35769a1c02SMasahiro Yamada %union
36769a1c02SMasahiro Yamada {
37769a1c02SMasahiro Yamada char *string;
38769a1c02SMasahiro Yamada struct symbol *symbol;
39769a1c02SMasahiro Yamada struct expr *expr;
40769a1c02SMasahiro Yamada struct menu *menu;
41769a1c02SMasahiro Yamada enum symbol_type type;
42769a1c02SMasahiro Yamada enum variable_flavor flavor;
43769a1c02SMasahiro Yamada }
44769a1c02SMasahiro Yamada
45769a1c02SMasahiro Yamada %token <string> T_HELPTEXT
46769a1c02SMasahiro Yamada %token <string> T_WORD
47769a1c02SMasahiro Yamada %token <string> T_WORD_QUOTE
48769a1c02SMasahiro Yamada %token T_BOOL
49769a1c02SMasahiro Yamada %token T_CHOICE
50769a1c02SMasahiro Yamada %token T_CLOSE_PAREN
51769a1c02SMasahiro Yamada %token T_COLON_EQUAL
52769a1c02SMasahiro Yamada %token T_COMMENT
53769a1c02SMasahiro Yamada %token T_CONFIG
54769a1c02SMasahiro Yamada %token T_DEFAULT
55769a1c02SMasahiro Yamada %token T_DEF_BOOL
56769a1c02SMasahiro Yamada %token T_DEF_TRISTATE
57769a1c02SMasahiro Yamada %token T_DEPENDS
58769a1c02SMasahiro Yamada %token T_ENDCHOICE
59769a1c02SMasahiro Yamada %token T_ENDIF
60769a1c02SMasahiro Yamada %token T_ENDMENU
61769a1c02SMasahiro Yamada %token T_HELP
62769a1c02SMasahiro Yamada %token T_HEX
63769a1c02SMasahiro Yamada %token T_IF
64769a1c02SMasahiro Yamada %token T_IMPLY
65769a1c02SMasahiro Yamada %token T_INT
66769a1c02SMasahiro Yamada %token T_MAINMENU
67769a1c02SMasahiro Yamada %token T_MENU
68769a1c02SMasahiro Yamada %token T_MENUCONFIG
69769a1c02SMasahiro Yamada %token T_MODULES
70769a1c02SMasahiro Yamada %token T_ON
71769a1c02SMasahiro Yamada %token T_OPEN_PAREN
72769a1c02SMasahiro Yamada %token T_PLUS_EQUAL
73769a1c02SMasahiro Yamada %token T_PROMPT
74769a1c02SMasahiro Yamada %token T_RANGE
75769a1c02SMasahiro Yamada %token T_SELECT
76769a1c02SMasahiro Yamada %token T_SOURCE
77769a1c02SMasahiro Yamada %token T_STRING
78769a1c02SMasahiro Yamada %token T_TRISTATE
79769a1c02SMasahiro Yamada %token T_VISIBLE
80769a1c02SMasahiro Yamada %token T_EOL
81769a1c02SMasahiro Yamada %token <string> T_ASSIGN_VAL
82769a1c02SMasahiro Yamada
83769a1c02SMasahiro Yamada %left T_OR
84769a1c02SMasahiro Yamada %left T_AND
85769a1c02SMasahiro Yamada %left T_EQUAL T_UNEQUAL
86769a1c02SMasahiro Yamada %left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL
87769a1c02SMasahiro Yamada %nonassoc T_NOT
88769a1c02SMasahiro Yamada
89769a1c02SMasahiro Yamada %type <symbol> nonconst_symbol
90769a1c02SMasahiro Yamada %type <symbol> symbol
91fde19251SMasahiro Yamada %type <type> type default
92769a1c02SMasahiro Yamada %type <expr> expr
93769a1c02SMasahiro Yamada %type <expr> if_expr
94769a1c02SMasahiro Yamada %type <string> end
95769a1c02SMasahiro Yamada %type <menu> if_entry menu_entry choice_entry
96c83f0209SMasahiro Yamada %type <string> assign_val
97769a1c02SMasahiro Yamada %type <flavor> assign_op
98769a1c02SMasahiro Yamada
99769a1c02SMasahiro Yamada %destructor {
100769a1c02SMasahiro Yamada fprintf(stderr, "%s:%d: missing end statement for this entry\n",
10140bab83aSMasahiro Yamada $$->filename, $$->lineno);
102769a1c02SMasahiro Yamada if (current_menu == $$)
103769a1c02SMasahiro Yamada menu_end_menu();
104769a1c02SMasahiro Yamada } if_entry menu_entry choice_entry
105769a1c02SMasahiro Yamada
106769a1c02SMasahiro Yamada %%
107769a1c02SMasahiro Yamada input: mainmenu_stmt stmt_list | stmt_list;
108769a1c02SMasahiro Yamada
109769a1c02SMasahiro Yamada /* mainmenu entry */
110769a1c02SMasahiro Yamada
1111be6e791SMasahiro Yamada mainmenu_stmt: T_MAINMENU T_WORD_QUOTE T_EOL
112769a1c02SMasahiro Yamada {
113769a1c02SMasahiro Yamada menu_add_prompt(P_MENU, $2, NULL);
114769a1c02SMasahiro Yamada };
115769a1c02SMasahiro Yamada
116769a1c02SMasahiro Yamada stmt_list:
117769a1c02SMasahiro Yamada /* empty */
11809d5873eSMasahiro Yamada | stmt_list assignment_stmt
119769a1c02SMasahiro Yamada | stmt_list choice_stmt
12009d5873eSMasahiro Yamada | stmt_list comment_stmt
12109d5873eSMasahiro Yamada | stmt_list config_stmt
12209d5873eSMasahiro Yamada | stmt_list if_stmt
123769a1c02SMasahiro Yamada | stmt_list menu_stmt
12409d5873eSMasahiro Yamada | stmt_list menuconfig_stmt
12509d5873eSMasahiro Yamada | stmt_list source_stmt
126769a1c02SMasahiro Yamada | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
127769a1c02SMasahiro Yamada | stmt_list error T_EOL { zconf_error("invalid statement"); }
128769a1c02SMasahiro Yamada ;
129769a1c02SMasahiro Yamada
13009d5873eSMasahiro Yamada stmt_list_in_choice:
13109d5873eSMasahiro Yamada /* empty */
13209d5873eSMasahiro Yamada | stmt_list_in_choice comment_stmt
13309d5873eSMasahiro Yamada | stmt_list_in_choice config_stmt
13409d5873eSMasahiro Yamada | stmt_list_in_choice if_stmt_in_choice
13509d5873eSMasahiro Yamada | stmt_list_in_choice error T_EOL { zconf_error("invalid statement"); }
136769a1c02SMasahiro Yamada ;
137769a1c02SMasahiro Yamada
138769a1c02SMasahiro Yamada /* config/menuconfig entry */
139769a1c02SMasahiro Yamada
140769a1c02SMasahiro Yamada config_entry_start: T_CONFIG nonconst_symbol T_EOL
141769a1c02SMasahiro Yamada {
142769a1c02SMasahiro Yamada menu_add_entry($2);
1431d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:config %s\n", cur_filename, cur_lineno, $2->name);
144769a1c02SMasahiro Yamada };
145769a1c02SMasahiro Yamada
146769a1c02SMasahiro Yamada config_stmt: config_entry_start config_option_list
147769a1c02SMasahiro Yamada {
1489b114520SMasahiro Yamada if (current_choice) {
149700e7a8dSMasahiro Yamada if (!current_entry->prompt) {
150700e7a8dSMasahiro Yamada fprintf(stderr, "%s:%d: error: choice member must have a prompt\n",
151700e7a8dSMasahiro Yamada current_entry->filename, current_entry->lineno);
152700e7a8dSMasahiro Yamada yynerrs++;
153700e7a8dSMasahiro Yamada }
154fde19251SMasahiro Yamada
155fde19251SMasahiro Yamada if (current_entry->sym->type != S_BOOLEAN) {
156fde19251SMasahiro Yamada fprintf(stderr, "%s:%d: error: choice member must be bool\n",
157fde19251SMasahiro Yamada current_entry->filename, current_entry->lineno);
158fde19251SMasahiro Yamada yynerrs++;
159fde19251SMasahiro Yamada }
160f79dc03fSMasahiro Yamada
1614d46b5b6SMasahiro Yamada /*
1624d46b5b6SMasahiro Yamada * If the same symbol appears twice in a choice block, the list
1634d46b5b6SMasahiro Yamada * node would be added twice, leading to a broken linked list.
1644d46b5b6SMasahiro Yamada * list_empty() ensures that this symbol has not yet added.
1654d46b5b6SMasahiro Yamada */
1664d46b5b6SMasahiro Yamada if (list_empty(¤t_entry->sym->choice_link))
167f79dc03fSMasahiro Yamada list_add_tail(¤t_entry->sym->choice_link,
168f79dc03fSMasahiro Yamada ¤t_choice->choice_members);
169700e7a8dSMasahiro Yamada }
170700e7a8dSMasahiro Yamada
1711d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
172769a1c02SMasahiro Yamada };
173769a1c02SMasahiro Yamada
174769a1c02SMasahiro Yamada menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
175769a1c02SMasahiro Yamada {
176769a1c02SMasahiro Yamada menu_add_entry($2);
1771d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", cur_filename, cur_lineno, $2->name);
178769a1c02SMasahiro Yamada };
179769a1c02SMasahiro Yamada
180769a1c02SMasahiro Yamada menuconfig_stmt: menuconfig_entry_start config_option_list
181769a1c02SMasahiro Yamada {
182769a1c02SMasahiro Yamada if (current_entry->prompt)
183769a1c02SMasahiro Yamada current_entry->prompt->type = P_MENU;
184769a1c02SMasahiro Yamada else
185*6971f719SMasahiro Yamada zconf_error("menuconfig statement without prompt");
1861d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno);
187769a1c02SMasahiro Yamada };
188769a1c02SMasahiro Yamada
189769a1c02SMasahiro Yamada config_option_list:
190769a1c02SMasahiro Yamada /* empty */
191769a1c02SMasahiro Yamada | config_option_list config_option
192769a1c02SMasahiro Yamada | config_option_list depends
193769a1c02SMasahiro Yamada | config_option_list help
194769a1c02SMasahiro Yamada ;
195769a1c02SMasahiro Yamada
196769a1c02SMasahiro Yamada config_option: type prompt_stmt_opt T_EOL
197769a1c02SMasahiro Yamada {
198769a1c02SMasahiro Yamada menu_set_type($1);
1991d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:type(%u)\n", cur_filename, cur_lineno, $1);
200769a1c02SMasahiro Yamada };
201769a1c02SMasahiro Yamada
2021be6e791SMasahiro Yamada config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
203769a1c02SMasahiro Yamada {
204769a1c02SMasahiro Yamada menu_add_prompt(P_PROMPT, $2, $3);
2051d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
206769a1c02SMasahiro Yamada };
207769a1c02SMasahiro Yamada
208769a1c02SMasahiro Yamada config_option: default expr if_expr T_EOL
209769a1c02SMasahiro Yamada {
210769a1c02SMasahiro Yamada menu_add_expr(P_DEFAULT, $2, $3);
211769a1c02SMasahiro Yamada if ($1 != S_UNKNOWN)
212769a1c02SMasahiro Yamada menu_set_type($1);
2131d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:default(%u)\n", cur_filename, cur_lineno,
214769a1c02SMasahiro Yamada $1);
215769a1c02SMasahiro Yamada };
216769a1c02SMasahiro Yamada
217769a1c02SMasahiro Yamada config_option: T_SELECT nonconst_symbol if_expr T_EOL
218769a1c02SMasahiro Yamada {
219769a1c02SMasahiro Yamada menu_add_symbol(P_SELECT, $2, $3);
2201d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:select\n", cur_filename, cur_lineno);
221769a1c02SMasahiro Yamada };
222769a1c02SMasahiro Yamada
223769a1c02SMasahiro Yamada config_option: T_IMPLY nonconst_symbol if_expr T_EOL
224769a1c02SMasahiro Yamada {
225769a1c02SMasahiro Yamada menu_add_symbol(P_IMPLY, $2, $3);
2261d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:imply\n", cur_filename, cur_lineno);
227769a1c02SMasahiro Yamada };
228769a1c02SMasahiro Yamada
229769a1c02SMasahiro Yamada config_option: T_RANGE symbol symbol if_expr T_EOL
230769a1c02SMasahiro Yamada {
231769a1c02SMasahiro Yamada menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
2321d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:range\n", cur_filename, cur_lineno);
233769a1c02SMasahiro Yamada };
234769a1c02SMasahiro Yamada
2356dd85ff1SMasahiro Yamada config_option: T_MODULES T_EOL
236769a1c02SMasahiro Yamada {
2376dd85ff1SMasahiro Yamada if (modules_sym)
2386dd85ff1SMasahiro Yamada zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
2396dd85ff1SMasahiro Yamada current_entry->sym->name, modules_sym->name);
2406dd85ff1SMasahiro Yamada modules_sym = current_entry->sym;
241769a1c02SMasahiro Yamada };
242769a1c02SMasahiro Yamada
243769a1c02SMasahiro Yamada /* choice entry */
244769a1c02SMasahiro Yamada
245c83f0209SMasahiro Yamada choice: T_CHOICE T_EOL
246769a1c02SMasahiro Yamada {
2471da251c6SMasahiro Yamada struct symbol *sym = sym_lookup(NULL, 0);
248a7c79cf3SMasahiro Yamada
249769a1c02SMasahiro Yamada menu_add_entry(sym);
250fde19251SMasahiro Yamada menu_set_type(S_BOOLEAN);
251f79dc03fSMasahiro Yamada INIT_LIST_HEAD(¤t_entry->choice_members);
252fde19251SMasahiro Yamada
2531d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:choice\n", cur_filename, cur_lineno);
254769a1c02SMasahiro Yamada };
255769a1c02SMasahiro Yamada
256769a1c02SMasahiro Yamada choice_entry: choice choice_option_list
257769a1c02SMasahiro Yamada {
2584957515bSMasahiro Yamada if (!current_entry->prompt) {
2594957515bSMasahiro Yamada fprintf(stderr, "%s:%d: error: choice must have a prompt\n",
2604957515bSMasahiro Yamada current_entry->filename, current_entry->lineno);
2614957515bSMasahiro Yamada yynerrs++;
2624957515bSMasahiro Yamada }
2634957515bSMasahiro Yamada
264769a1c02SMasahiro Yamada $$ = menu_add_menu();
265700e7a8dSMasahiro Yamada
2669b114520SMasahiro Yamada current_choice = current_entry;
267769a1c02SMasahiro Yamada };
268769a1c02SMasahiro Yamada
269769a1c02SMasahiro Yamada choice_end: end
270769a1c02SMasahiro Yamada {
2719b114520SMasahiro Yamada current_choice = NULL;
272700e7a8dSMasahiro Yamada
273769a1c02SMasahiro Yamada if (zconf_endtoken($1, "choice")) {
274769a1c02SMasahiro Yamada menu_end_menu();
2751d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:endchoice\n", cur_filename, cur_lineno);
276769a1c02SMasahiro Yamada }
277769a1c02SMasahiro Yamada };
278769a1c02SMasahiro Yamada
27909d5873eSMasahiro Yamada choice_stmt: choice_entry stmt_list_in_choice choice_end
280769a1c02SMasahiro Yamada ;
281769a1c02SMasahiro Yamada
282769a1c02SMasahiro Yamada choice_option_list:
283769a1c02SMasahiro Yamada /* empty */
284769a1c02SMasahiro Yamada | choice_option_list choice_option
285769a1c02SMasahiro Yamada | choice_option_list depends
286769a1c02SMasahiro Yamada | choice_option_list help
287769a1c02SMasahiro Yamada ;
288769a1c02SMasahiro Yamada
2891be6e791SMasahiro Yamada choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL
290769a1c02SMasahiro Yamada {
291769a1c02SMasahiro Yamada menu_add_prompt(P_PROMPT, $2, $3);
2921d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno);
293769a1c02SMasahiro Yamada };
294769a1c02SMasahiro Yamada
295769a1c02SMasahiro Yamada choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
296769a1c02SMasahiro Yamada {
297769a1c02SMasahiro Yamada menu_add_symbol(P_DEFAULT, $2, $3);
2981d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:default\n", cur_filename, cur_lineno);
299769a1c02SMasahiro Yamada };
300769a1c02SMasahiro Yamada
301769a1c02SMasahiro Yamada type:
302fde19251SMasahiro Yamada T_BOOL { $$ = S_BOOLEAN; }
303fde19251SMasahiro Yamada | T_TRISTATE { $$ = S_TRISTATE; }
304769a1c02SMasahiro Yamada | T_INT { $$ = S_INT; }
305769a1c02SMasahiro Yamada | T_HEX { $$ = S_HEX; }
306769a1c02SMasahiro Yamada | T_STRING { $$ = S_STRING; }
307769a1c02SMasahiro Yamada
308769a1c02SMasahiro Yamada default:
309769a1c02SMasahiro Yamada T_DEFAULT { $$ = S_UNKNOWN; }
310769a1c02SMasahiro Yamada | T_DEF_BOOL { $$ = S_BOOLEAN; }
311769a1c02SMasahiro Yamada | T_DEF_TRISTATE { $$ = S_TRISTATE; }
312769a1c02SMasahiro Yamada
313769a1c02SMasahiro Yamada /* if entry */
314769a1c02SMasahiro Yamada
315769a1c02SMasahiro Yamada if_entry: T_IF expr T_EOL
316769a1c02SMasahiro Yamada {
3171d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:if\n", cur_filename, cur_lineno);
318769a1c02SMasahiro Yamada menu_add_entry(NULL);
319769a1c02SMasahiro Yamada menu_add_dep($2);
320769a1c02SMasahiro Yamada $$ = menu_add_menu();
321769a1c02SMasahiro Yamada };
322769a1c02SMasahiro Yamada
323769a1c02SMasahiro Yamada if_end: end
324769a1c02SMasahiro Yamada {
325769a1c02SMasahiro Yamada if (zconf_endtoken($1, "if")) {
326769a1c02SMasahiro Yamada menu_end_menu();
3271d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:endif\n", cur_filename, cur_lineno);
328769a1c02SMasahiro Yamada }
329769a1c02SMasahiro Yamada };
330769a1c02SMasahiro Yamada
331769a1c02SMasahiro Yamada if_stmt: if_entry stmt_list if_end
332769a1c02SMasahiro Yamada ;
333769a1c02SMasahiro Yamada
33409d5873eSMasahiro Yamada if_stmt_in_choice: if_entry stmt_list_in_choice if_end
33509d5873eSMasahiro Yamada ;
33609d5873eSMasahiro Yamada
337769a1c02SMasahiro Yamada /* menu entry */
338769a1c02SMasahiro Yamada
3391be6e791SMasahiro Yamada menu: T_MENU T_WORD_QUOTE T_EOL
340769a1c02SMasahiro Yamada {
341769a1c02SMasahiro Yamada menu_add_entry(NULL);
342769a1c02SMasahiro Yamada menu_add_prompt(P_MENU, $2, NULL);
3431d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:menu\n", cur_filename, cur_lineno);
344769a1c02SMasahiro Yamada };
345769a1c02SMasahiro Yamada
346769a1c02SMasahiro Yamada menu_entry: menu menu_option_list
347769a1c02SMasahiro Yamada {
348769a1c02SMasahiro Yamada $$ = menu_add_menu();
349769a1c02SMasahiro Yamada };
350769a1c02SMasahiro Yamada
351769a1c02SMasahiro Yamada menu_end: end
352769a1c02SMasahiro Yamada {
353769a1c02SMasahiro Yamada if (zconf_endtoken($1, "menu")) {
354769a1c02SMasahiro Yamada menu_end_menu();
3551d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:endmenu\n", cur_filename, cur_lineno);
356769a1c02SMasahiro Yamada }
357769a1c02SMasahiro Yamada };
358769a1c02SMasahiro Yamada
359769a1c02SMasahiro Yamada menu_stmt: menu_entry stmt_list menu_end
360769a1c02SMasahiro Yamada ;
361769a1c02SMasahiro Yamada
362769a1c02SMasahiro Yamada menu_option_list:
363769a1c02SMasahiro Yamada /* empty */
364769a1c02SMasahiro Yamada | menu_option_list visible
365769a1c02SMasahiro Yamada | menu_option_list depends
366769a1c02SMasahiro Yamada ;
367769a1c02SMasahiro Yamada
3681be6e791SMasahiro Yamada source_stmt: T_SOURCE T_WORD_QUOTE T_EOL
369769a1c02SMasahiro Yamada {
3701d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:source %s\n", cur_filename, cur_lineno, $2);
371769a1c02SMasahiro Yamada zconf_nextfile($2);
372769a1c02SMasahiro Yamada free($2);
373769a1c02SMasahiro Yamada };
374769a1c02SMasahiro Yamada
375769a1c02SMasahiro Yamada /* comment entry */
376769a1c02SMasahiro Yamada
3771be6e791SMasahiro Yamada comment: T_COMMENT T_WORD_QUOTE T_EOL
378769a1c02SMasahiro Yamada {
379769a1c02SMasahiro Yamada menu_add_entry(NULL);
380769a1c02SMasahiro Yamada menu_add_prompt(P_COMMENT, $2, NULL);
3811d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:comment\n", cur_filename, cur_lineno);
382769a1c02SMasahiro Yamada };
383769a1c02SMasahiro Yamada
384769a1c02SMasahiro Yamada comment_stmt: comment comment_option_list
385769a1c02SMasahiro Yamada ;
386769a1c02SMasahiro Yamada
387769a1c02SMasahiro Yamada comment_option_list:
388769a1c02SMasahiro Yamada /* empty */
389769a1c02SMasahiro Yamada | comment_option_list depends
390769a1c02SMasahiro Yamada ;
391769a1c02SMasahiro Yamada
392769a1c02SMasahiro Yamada /* help option */
393769a1c02SMasahiro Yamada
394769a1c02SMasahiro Yamada help_start: T_HELP T_EOL
395769a1c02SMasahiro Yamada {
3961d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:help\n", cur_filename, cur_lineno);
397769a1c02SMasahiro Yamada zconf_starthelp();
398769a1c02SMasahiro Yamada };
399769a1c02SMasahiro Yamada
400769a1c02SMasahiro Yamada help: help_start T_HELPTEXT
401769a1c02SMasahiro Yamada {
402769a1c02SMasahiro Yamada if (current_entry->help) {
403769a1c02SMasahiro Yamada free(current_entry->help);
404*6971f719SMasahiro Yamada zconf_error("'%s' defined with more than one help text",
405769a1c02SMasahiro Yamada current_entry->sym->name ?: "<choice>");
406769a1c02SMasahiro Yamada }
407769a1c02SMasahiro Yamada
408769a1c02SMasahiro Yamada /* Is the help text empty or all whitespace? */
409769a1c02SMasahiro Yamada if ($2[strspn($2, " \f\n\r\t\v")] == '\0')
410*6971f719SMasahiro Yamada zconf_error("'%s' defined with blank help text",
411769a1c02SMasahiro Yamada current_entry->sym->name ?: "<choice>");
412769a1c02SMasahiro Yamada
413769a1c02SMasahiro Yamada current_entry->help = $2;
414769a1c02SMasahiro Yamada };
415769a1c02SMasahiro Yamada
416769a1c02SMasahiro Yamada /* depends option */
417769a1c02SMasahiro Yamada
418769a1c02SMasahiro Yamada depends: T_DEPENDS T_ON expr T_EOL
419769a1c02SMasahiro Yamada {
420769a1c02SMasahiro Yamada menu_add_dep($3);
4211d7c4f10SMasahiro Yamada printd(DEBUG_PARSE, "%s:%d:depends on\n", cur_filename, cur_lineno);
422769a1c02SMasahiro Yamada };
423769a1c02SMasahiro Yamada
424769a1c02SMasahiro Yamada /* visibility option */
425769a1c02SMasahiro Yamada visible: T_VISIBLE if_expr T_EOL
426769a1c02SMasahiro Yamada {
427769a1c02SMasahiro Yamada menu_add_visibility($2);
428769a1c02SMasahiro Yamada };
429769a1c02SMasahiro Yamada
430769a1c02SMasahiro Yamada /* prompt statement */
431769a1c02SMasahiro Yamada
432769a1c02SMasahiro Yamada prompt_stmt_opt:
433769a1c02SMasahiro Yamada /* empty */
4341be6e791SMasahiro Yamada | T_WORD_QUOTE if_expr
435769a1c02SMasahiro Yamada {
436769a1c02SMasahiro Yamada menu_add_prompt(P_PROMPT, $1, $2);
437769a1c02SMasahiro Yamada };
438769a1c02SMasahiro Yamada
439769a1c02SMasahiro Yamada end: T_ENDMENU T_EOL { $$ = "menu"; }
440769a1c02SMasahiro Yamada | T_ENDCHOICE T_EOL { $$ = "choice"; }
441769a1c02SMasahiro Yamada | T_ENDIF T_EOL { $$ = "if"; }
442769a1c02SMasahiro Yamada ;
443769a1c02SMasahiro Yamada
444769a1c02SMasahiro Yamada if_expr: /* empty */ { $$ = NULL; }
445769a1c02SMasahiro Yamada | T_IF expr { $$ = $2; }
446769a1c02SMasahiro Yamada ;
447769a1c02SMasahiro Yamada
448769a1c02SMasahiro Yamada expr: symbol { $$ = expr_alloc_symbol($1); }
449769a1c02SMasahiro Yamada | symbol T_LESS symbol { $$ = expr_alloc_comp(E_LTH, $1, $3); }
450769a1c02SMasahiro Yamada | symbol T_LESS_EQUAL symbol { $$ = expr_alloc_comp(E_LEQ, $1, $3); }
451769a1c02SMasahiro Yamada | symbol T_GREATER symbol { $$ = expr_alloc_comp(E_GTH, $1, $3); }
452769a1c02SMasahiro Yamada | symbol T_GREATER_EQUAL symbol { $$ = expr_alloc_comp(E_GEQ, $1, $3); }
453769a1c02SMasahiro Yamada | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
454769a1c02SMasahiro Yamada | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
455769a1c02SMasahiro Yamada | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
456769a1c02SMasahiro Yamada | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
457769a1c02SMasahiro Yamada | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
458769a1c02SMasahiro Yamada | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
459769a1c02SMasahiro Yamada ;
460769a1c02SMasahiro Yamada
461769a1c02SMasahiro Yamada /* For symbol definitions, selects, etc., where quotes are not accepted */
462769a1c02SMasahiro Yamada nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); };
463769a1c02SMasahiro Yamada
464769a1c02SMasahiro Yamada symbol: nonconst_symbol
465769a1c02SMasahiro Yamada | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
466769a1c02SMasahiro Yamada ;
467769a1c02SMasahiro Yamada
468769a1c02SMasahiro Yamada /* assignment statement */
469769a1c02SMasahiro Yamada
470769a1c02SMasahiro Yamada assignment_stmt: T_WORD assign_op assign_val T_EOL { variable_add($1, $3, $2); free($1); free($3); }
471769a1c02SMasahiro Yamada
472769a1c02SMasahiro Yamada assign_op:
473769a1c02SMasahiro Yamada T_EQUAL { $$ = VAR_RECURSIVE; }
474769a1c02SMasahiro Yamada | T_COLON_EQUAL { $$ = VAR_SIMPLE; }
475769a1c02SMasahiro Yamada | T_PLUS_EQUAL { $$ = VAR_APPEND; }
476769a1c02SMasahiro Yamada ;
477769a1c02SMasahiro Yamada
478769a1c02SMasahiro Yamada assign_val:
479769a1c02SMasahiro Yamada /* empty */ { $$ = xstrdup(""); };
480769a1c02SMasahiro Yamada | T_ASSIGN_VAL
481769a1c02SMasahiro Yamada ;
482769a1c02SMasahiro Yamada
483769a1c02SMasahiro Yamada %%
484769a1c02SMasahiro Yamada
4858a22f867SMasahiro Yamada /**
4868a22f867SMasahiro Yamada * choice_check_sanity - check sanity of a choice member
4878a22f867SMasahiro Yamada *
4888a22f867SMasahiro Yamada * @menu: menu of the choice member
4898a22f867SMasahiro Yamada *
4908a22f867SMasahiro Yamada * Return: -1 if an error is found, 0 otherwise.
4918a22f867SMasahiro Yamada */
4926425e3b2SMasahiro Yamada static int choice_check_sanity(const struct menu *menu)
4938a22f867SMasahiro Yamada {
4948a22f867SMasahiro Yamada struct property *prop;
4958a22f867SMasahiro Yamada int ret = 0;
4968a22f867SMasahiro Yamada
4978a22f867SMasahiro Yamada for (prop = menu->sym->prop; prop; prop = prop->next) {
4988a22f867SMasahiro Yamada if (prop->type == P_DEFAULT) {
4998a22f867SMasahiro Yamada fprintf(stderr, "%s:%d: error: %s",
5008a22f867SMasahiro Yamada prop->filename, prop->lineno,
5018a22f867SMasahiro Yamada "defaults for choice values not supported\n");
5028a22f867SMasahiro Yamada ret = -1;
5038a22f867SMasahiro Yamada }
5048a22f867SMasahiro Yamada
5058a22f867SMasahiro Yamada if (prop->menu != menu && prop->type == P_PROMPT &&
5068a22f867SMasahiro Yamada prop->menu->parent != menu->parent) {
5078a22f867SMasahiro Yamada fprintf(stderr, "%s:%d: error: %s",
5088a22f867SMasahiro Yamada prop->filename, prop->lineno,
5098a22f867SMasahiro Yamada "choice value has a prompt outside its choice group\n");
5108a22f867SMasahiro Yamada ret = -1;
5118a22f867SMasahiro Yamada }
5128a22f867SMasahiro Yamada }
5138a22f867SMasahiro Yamada
5148a22f867SMasahiro Yamada return ret;
5158a22f867SMasahiro Yamada }
5168a22f867SMasahiro Yamada
conf_parse(const char * name)517769a1c02SMasahiro Yamada void conf_parse(const char *name)
518769a1c02SMasahiro Yamada {
519cc25cfc5SMasahiro Yamada struct menu *menu;
520769a1c02SMasahiro Yamada
521526396b7SMasahiro Yamada autoconf_cmd = str_new();
522526396b7SMasahiro Yamada
52356e634b0SMasahiro Yamada str_printf(&autoconf_cmd, "\ndeps_config := \\\n");
524526396b7SMasahiro Yamada
525769a1c02SMasahiro Yamada zconf_initscan(name);
526769a1c02SMasahiro Yamada
527769a1c02SMasahiro Yamada _menu_init();
528769a1c02SMasahiro Yamada
529769a1c02SMasahiro Yamada if (getenv("ZCONF_DEBUG"))
530769a1c02SMasahiro Yamada yydebug = 1;
531769a1c02SMasahiro Yamada yyparse();
532769a1c02SMasahiro Yamada
53356e634b0SMasahiro Yamada str_printf(&autoconf_cmd,
53456e634b0SMasahiro Yamada "\n"
53556e634b0SMasahiro Yamada "$(autoconfig): $(deps_config)\n"
53656e634b0SMasahiro Yamada "$(deps_config): ;\n");
53756e634b0SMasahiro Yamada
53856e634b0SMasahiro Yamada env_write_dep(&autoconf_cmd);
53956e634b0SMasahiro Yamada
540769a1c02SMasahiro Yamada /* Variables are expanded in the parse phase. We can free them here. */
541769a1c02SMasahiro Yamada variable_all_del();
542769a1c02SMasahiro Yamada
543769a1c02SMasahiro Yamada if (yynerrs)
544769a1c02SMasahiro Yamada exit(1);
545769a1c02SMasahiro Yamada if (!modules_sym)
54673a6afc5SMasahiro Yamada modules_sym = &symbol_no;
547769a1c02SMasahiro Yamada
548769a1c02SMasahiro Yamada if (!menu_has_prompt(&rootmenu)) {
549769a1c02SMasahiro Yamada current_entry = &rootmenu;
550769a1c02SMasahiro Yamada menu_add_prompt(P_MENU, "Main menu", NULL);
551769a1c02SMasahiro Yamada }
552769a1c02SMasahiro Yamada
5537e3465f6SMasahiro Yamada menu_finalize();
554cc25cfc5SMasahiro Yamada
55503c4ecaaSMasahiro Yamada menu_for_each_entry(menu) {
5568a22f867SMasahiro Yamada struct menu *child;
5578a22f867SMasahiro Yamada
558cc25cfc5SMasahiro Yamada if (menu->sym && sym_check_deps(menu->sym))
559769a1c02SMasahiro Yamada yynerrs++;
5608a22f867SMasahiro Yamada
5618a22f867SMasahiro Yamada if (menu->sym && sym_is_choice(menu->sym)) {
5628a22f867SMasahiro Yamada menu_for_each_sub_entry(child, menu)
5638a22f867SMasahiro Yamada if (child->sym && choice_check_sanity(child))
5648a22f867SMasahiro Yamada yynerrs++;
5658a22f867SMasahiro Yamada }
566cc25cfc5SMasahiro Yamada }
567cc25cfc5SMasahiro Yamada
568769a1c02SMasahiro Yamada if (yynerrs)
569769a1c02SMasahiro Yamada exit(1);
5705ee54659SMasahiro Yamada conf_set_changed(true);
571769a1c02SMasahiro Yamada }
572769a1c02SMasahiro Yamada
zconf_endtoken(const char * tokenname,const char * expected_tokenname)573769a1c02SMasahiro Yamada static bool zconf_endtoken(const char *tokenname,
574769a1c02SMasahiro Yamada const char *expected_tokenname)
575769a1c02SMasahiro Yamada {
576769a1c02SMasahiro Yamada if (strcmp(tokenname, expected_tokenname)) {
577769a1c02SMasahiro Yamada zconf_error("unexpected '%s' within %s block",
578769a1c02SMasahiro Yamada tokenname, expected_tokenname);
579769a1c02SMasahiro Yamada yynerrs++;
580769a1c02SMasahiro Yamada return false;
581769a1c02SMasahiro Yamada }
58240bab83aSMasahiro Yamada if (strcmp(current_menu->filename, cur_filename)) {
583769a1c02SMasahiro Yamada zconf_error("'%s' in different file than '%s'",
584769a1c02SMasahiro Yamada tokenname, expected_tokenname);
585769a1c02SMasahiro Yamada fprintf(stderr, "%s:%d: location of the '%s'\n",
58640bab83aSMasahiro Yamada current_menu->filename, current_menu->lineno,
587769a1c02SMasahiro Yamada expected_tokenname);
588769a1c02SMasahiro Yamada yynerrs++;
589769a1c02SMasahiro Yamada return false;
590769a1c02SMasahiro Yamada }
591769a1c02SMasahiro Yamada return true;
592769a1c02SMasahiro Yamada }
593769a1c02SMasahiro Yamada
zconf_error(const char * err,...)594769a1c02SMasahiro Yamada static void zconf_error(const char *err, ...)
595769a1c02SMasahiro Yamada {
596769a1c02SMasahiro Yamada va_list ap;
597769a1c02SMasahiro Yamada
598769a1c02SMasahiro Yamada yynerrs++;
5991d7c4f10SMasahiro Yamada fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno);
600769a1c02SMasahiro Yamada va_start(ap, err);
601769a1c02SMasahiro Yamada vfprintf(stderr, err, ap);
602769a1c02SMasahiro Yamada va_end(ap);
603769a1c02SMasahiro Yamada fprintf(stderr, "\n");
604769a1c02SMasahiro Yamada }
605769a1c02SMasahiro Yamada
yyerror(const char * err)606769a1c02SMasahiro Yamada static void yyerror(const char *err)
607769a1c02SMasahiro Yamada {
6081d7c4f10SMasahiro Yamada fprintf(stderr, "%s:%d: %s\n", cur_filename, cur_lineno, err);
609769a1c02SMasahiro Yamada }
610769a1c02SMasahiro Yamada
print_quoted_string(FILE * out,const char * str)611769a1c02SMasahiro Yamada static void print_quoted_string(FILE *out, const char *str)
612769a1c02SMasahiro Yamada {
613769a1c02SMasahiro Yamada const char *p;
614769a1c02SMasahiro Yamada int len;
615769a1c02SMasahiro Yamada
616769a1c02SMasahiro Yamada putc('"', out);
617769a1c02SMasahiro Yamada while ((p = strchr(str, '"'))) {
618769a1c02SMasahiro Yamada len = p - str;
619769a1c02SMasahiro Yamada if (len)
620769a1c02SMasahiro Yamada fprintf(out, "%.*s", len, str);
621769a1c02SMasahiro Yamada fputs("\\\"", out);
622769a1c02SMasahiro Yamada str = p + 1;
623769a1c02SMasahiro Yamada }
624769a1c02SMasahiro Yamada fputs(str, out);
625769a1c02SMasahiro Yamada putc('"', out);
626769a1c02SMasahiro Yamada }
627769a1c02SMasahiro Yamada
print_symbol(FILE * out,const struct menu * menu)6286425e3b2SMasahiro Yamada static void print_symbol(FILE *out, const struct menu *menu)
629769a1c02SMasahiro Yamada {
630769a1c02SMasahiro Yamada struct symbol *sym = menu->sym;
631769a1c02SMasahiro Yamada struct property *prop;
632769a1c02SMasahiro Yamada
633769a1c02SMasahiro Yamada if (sym_is_choice(sym))
634769a1c02SMasahiro Yamada fprintf(out, "\nchoice\n");
635769a1c02SMasahiro Yamada else
636769a1c02SMasahiro Yamada fprintf(out, "\nconfig %s\n", sym->name);
637769a1c02SMasahiro Yamada switch (sym->type) {
638769a1c02SMasahiro Yamada case S_BOOLEAN:
639769a1c02SMasahiro Yamada fputs(" bool\n", out);
640769a1c02SMasahiro Yamada break;
641769a1c02SMasahiro Yamada case S_TRISTATE:
642769a1c02SMasahiro Yamada fputs(" tristate\n", out);
643769a1c02SMasahiro Yamada break;
644769a1c02SMasahiro Yamada case S_STRING:
645769a1c02SMasahiro Yamada fputs(" string\n", out);
646769a1c02SMasahiro Yamada break;
647769a1c02SMasahiro Yamada case S_INT:
648769a1c02SMasahiro Yamada fputs(" integer\n", out);
649769a1c02SMasahiro Yamada break;
650769a1c02SMasahiro Yamada case S_HEX:
651769a1c02SMasahiro Yamada fputs(" hex\n", out);
652769a1c02SMasahiro Yamada break;
653769a1c02SMasahiro Yamada default:
654769a1c02SMasahiro Yamada fputs(" ???\n", out);
655769a1c02SMasahiro Yamada break;
656769a1c02SMasahiro Yamada }
657769a1c02SMasahiro Yamada for (prop = sym->prop; prop; prop = prop->next) {
658769a1c02SMasahiro Yamada if (prop->menu != menu)
659769a1c02SMasahiro Yamada continue;
660769a1c02SMasahiro Yamada switch (prop->type) {
661769a1c02SMasahiro Yamada case P_PROMPT:
662769a1c02SMasahiro Yamada fputs(" prompt ", out);
663769a1c02SMasahiro Yamada print_quoted_string(out, prop->text);
664769a1c02SMasahiro Yamada if (!expr_is_yes(prop->visible.expr)) {
665769a1c02SMasahiro Yamada fputs(" if ", out);
666769a1c02SMasahiro Yamada expr_fprint(prop->visible.expr, out);
667769a1c02SMasahiro Yamada }
668769a1c02SMasahiro Yamada fputc('\n', out);
669769a1c02SMasahiro Yamada break;
670769a1c02SMasahiro Yamada case P_DEFAULT:
671769a1c02SMasahiro Yamada fputs( " default ", out);
672769a1c02SMasahiro Yamada expr_fprint(prop->expr, out);
673769a1c02SMasahiro Yamada if (!expr_is_yes(prop->visible.expr)) {
674769a1c02SMasahiro Yamada fputs(" if ", out);
675769a1c02SMasahiro Yamada expr_fprint(prop->visible.expr, out);
676769a1c02SMasahiro Yamada }
677769a1c02SMasahiro Yamada fputc('\n', out);
678769a1c02SMasahiro Yamada break;
679769a1c02SMasahiro Yamada case P_SELECT:
680769a1c02SMasahiro Yamada fputs( " select ", out);
681769a1c02SMasahiro Yamada expr_fprint(prop->expr, out);
682769a1c02SMasahiro Yamada fputc('\n', out);
683769a1c02SMasahiro Yamada break;
684769a1c02SMasahiro Yamada case P_IMPLY:
685769a1c02SMasahiro Yamada fputs( " imply ", out);
686769a1c02SMasahiro Yamada expr_fprint(prop->expr, out);
687769a1c02SMasahiro Yamada fputc('\n', out);
688769a1c02SMasahiro Yamada break;
689769a1c02SMasahiro Yamada case P_RANGE:
690769a1c02SMasahiro Yamada fputs( " range ", out);
691769a1c02SMasahiro Yamada expr_fprint(prop->expr, out);
692769a1c02SMasahiro Yamada fputc('\n', out);
693769a1c02SMasahiro Yamada break;
694769a1c02SMasahiro Yamada case P_MENU:
695769a1c02SMasahiro Yamada fputs( " menu ", out);
696769a1c02SMasahiro Yamada print_quoted_string(out, prop->text);
697769a1c02SMasahiro Yamada fputc('\n', out);
698769a1c02SMasahiro Yamada break;
699769a1c02SMasahiro Yamada default:
700769a1c02SMasahiro Yamada fprintf(out, " unknown prop %d!\n", prop->type);
701769a1c02SMasahiro Yamada break;
702769a1c02SMasahiro Yamada }
703769a1c02SMasahiro Yamada }
704769a1c02SMasahiro Yamada if (menu->help) {
705769a1c02SMasahiro Yamada int len = strlen(menu->help);
706769a1c02SMasahiro Yamada while (menu->help[--len] == '\n')
707769a1c02SMasahiro Yamada menu->help[len] = 0;
708769a1c02SMasahiro Yamada fprintf(out, " help\n%s\n", menu->help);
709769a1c02SMasahiro Yamada }
710769a1c02SMasahiro Yamada }
711769a1c02SMasahiro Yamada
zconfdump(FILE * out)712769a1c02SMasahiro Yamada void zconfdump(FILE *out)
713769a1c02SMasahiro Yamada {
714769a1c02SMasahiro Yamada struct property *prop;
715769a1c02SMasahiro Yamada struct symbol *sym;
716769a1c02SMasahiro Yamada struct menu *menu;
717769a1c02SMasahiro Yamada
718769a1c02SMasahiro Yamada menu = rootmenu.list;
719769a1c02SMasahiro Yamada while (menu) {
720769a1c02SMasahiro Yamada if ((sym = menu->sym))
721769a1c02SMasahiro Yamada print_symbol(out, menu);
722769a1c02SMasahiro Yamada else if ((prop = menu->prompt)) {
723769a1c02SMasahiro Yamada switch (prop->type) {
724769a1c02SMasahiro Yamada case P_COMMENT:
725769a1c02SMasahiro Yamada fputs("\ncomment ", out);
726769a1c02SMasahiro Yamada print_quoted_string(out, prop->text);
727769a1c02SMasahiro Yamada fputs("\n", out);
728769a1c02SMasahiro Yamada break;
729769a1c02SMasahiro Yamada case P_MENU:
730769a1c02SMasahiro Yamada fputs("\nmenu ", out);
731769a1c02SMasahiro Yamada print_quoted_string(out, prop->text);
732769a1c02SMasahiro Yamada fputs("\n", out);
733769a1c02SMasahiro Yamada break;
734769a1c02SMasahiro Yamada default:
735769a1c02SMasahiro Yamada ;
736769a1c02SMasahiro Yamada }
737769a1c02SMasahiro Yamada if (!expr_is_yes(prop->visible.expr)) {
738769a1c02SMasahiro Yamada fputs(" depends ", out);
739769a1c02SMasahiro Yamada expr_fprint(prop->visible.expr, out);
740769a1c02SMasahiro Yamada fputc('\n', out);
741769a1c02SMasahiro Yamada }
742769a1c02SMasahiro Yamada }
743769a1c02SMasahiro Yamada
744769a1c02SMasahiro Yamada if (menu->list)
745769a1c02SMasahiro Yamada menu = menu->list;
746769a1c02SMasahiro Yamada else if (menu->next)
747769a1c02SMasahiro Yamada menu = menu->next;
748769a1c02SMasahiro Yamada else while ((menu = menu->parent)) {
749769a1c02SMasahiro Yamada if (menu->prompt && menu->prompt->type == P_MENU)
750769a1c02SMasahiro Yamada fputs("\nendmenu\n", out);
751769a1c02SMasahiro Yamada if (menu->next) {
752769a1c02SMasahiro Yamada menu = menu->next;
753769a1c02SMasahiro Yamada break;
754769a1c02SMasahiro Yamada }
755769a1c02SMasahiro Yamada }
756769a1c02SMasahiro Yamada }
757769a1c02SMasahiro Yamada }
758