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