1 | /*␊ |
2 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>␊ |
3 | * Released under the terms of the GNU GPL v2.0.␊ |
4 | */␊ |
5 | #include <stdlib.h>␊ |
6 | #include <string.h>␊ |
7 | ␊ |
8 | #define LKC_DIRECT_LINK␊ |
9 | #include "lkc.h"␊ |
10 | ␊ |
11 | static const char nohelp_text[] = N_(␊ |
12 | ␉"There is no help available for this option.\n");␊ |
13 | ␊ |
14 | struct menu rootmenu;␊ |
15 | static struct menu **last_entry_ptr;␊ |
16 | ␊ |
17 | struct file *file_list;␊ |
18 | struct file *current_file;␊ |
19 | ␊ |
20 | void menu_warn(struct menu *menu, const char *fmt, ...)␊ |
21 | {␊ |
22 | ␉va_list ap;␊ |
23 | ␉va_start(ap, fmt);␊ |
24 | ␉fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);␊ |
25 | ␉vfprintf(stderr, fmt, ap);␊ |
26 | ␉fprintf(stderr, "\n");␊ |
27 | ␉va_end(ap);␊ |
28 | }␊ |
29 | ␊ |
30 | static void prop_warn(struct property *prop, const char *fmt, ...)␊ |
31 | {␊ |
32 | ␉va_list ap;␊ |
33 | ␉va_start(ap, fmt);␊ |
34 | ␉fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);␊ |
35 | ␉vfprintf(stderr, fmt, ap);␊ |
36 | ␉fprintf(stderr, "\n");␊ |
37 | ␉va_end(ap);␊ |
38 | }␊ |
39 | ␊ |
40 | void _menu_init(void)␊ |
41 | {␊ |
42 | ␉current_entry = current_menu = &rootmenu;␊ |
43 | ␉last_entry_ptr = &rootmenu.list;␊ |
44 | }␊ |
45 | ␊ |
46 | void menu_add_entry(struct symbol *sym)␊ |
47 | {␊ |
48 | ␉struct menu *menu;␊ |
49 | ␊ |
50 | ␉menu = malloc(sizeof(*menu));␊ |
51 | ␉memset(menu, 0, sizeof(*menu));␊ |
52 | ␉menu->sym = sym;␊ |
53 | ␉menu->parent = current_menu;␊ |
54 | ␉menu->file = current_file;␊ |
55 | ␉menu->lineno = zconf_lineno();␊ |
56 | ␊ |
57 | ␉*last_entry_ptr = menu;␊ |
58 | ␉last_entry_ptr = &menu->next;␊ |
59 | ␉current_entry = menu;␊ |
60 | ␉if (sym)␊ |
61 | ␉␉menu_add_symbol(P_SYMBOL, sym, NULL);␊ |
62 | }␊ |
63 | ␊ |
64 | void menu_end_entry(void)␊ |
65 | {␊ |
66 | }␊ |
67 | ␊ |
68 | struct menu *menu_add_menu(void)␊ |
69 | {␊ |
70 | ␉menu_end_entry();␊ |
71 | ␉last_entry_ptr = ¤t_entry->list;␊ |
72 | ␉return current_menu = current_entry;␊ |
73 | }␊ |
74 | ␊ |
75 | void menu_end_menu(void)␊ |
76 | {␊ |
77 | ␉last_entry_ptr = ¤t_menu->next;␊ |
78 | ␉current_menu = current_menu->parent;␊ |
79 | }␊ |
80 | ␊ |
81 | static struct expr *menu_check_dep(struct expr *e)␊ |
82 | {␊ |
83 | ␉if (!e)␊ |
84 | ␉␉return e;␊ |
85 | ␊ |
86 | ␉switch (e->type) {␊ |
87 | ␉case E_NOT:␊ |
88 | ␉␉e->left.expr = menu_check_dep(e->left.expr);␊ |
89 | ␉␉break;␊ |
90 | ␉case E_OR:␊ |
91 | ␉case E_AND:␊ |
92 | ␉␉e->left.expr = menu_check_dep(e->left.expr);␊ |
93 | ␉␉e->right.expr = menu_check_dep(e->right.expr);␊ |
94 | ␉␉break;␊ |
95 | ␉case E_SYMBOL:␊ |
96 | ␉␉/* change 'm' into 'm' && MODULES */␊ |
97 | ␉␉if (e->left.sym == &symbol_mod)␊ |
98 | ␉␉␉return expr_alloc_and(e, expr_alloc_symbol(modules_sym));␊ |
99 | ␉␉break;␊ |
100 | ␉default:␊ |
101 | ␉␉break;␊ |
102 | ␉}␊ |
103 | ␉return e;␊ |
104 | }␊ |
105 | ␊ |
106 | void menu_add_dep(struct expr *dep)␊ |
107 | {␊ |
108 | ␉current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));␊ |
109 | }␊ |
110 | ␊ |
111 | void menu_set_type(int type)␊ |
112 | {␊ |
113 | ␉struct symbol *sym = current_entry->sym;␊ |
114 | ␊ |
115 | ␉if (sym->type == type)␊ |
116 | ␉␉return;␊ |
117 | ␉if (sym->type == S_UNKNOWN) {␊ |
118 | ␉␉sym->type = type;␊ |
119 | ␉␉return;␊ |
120 | ␉}␊ |
121 | ␉menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",␊ |
122 | ␉ sym->name ? sym->name : "<choice>",␊ |
123 | ␉ sym_type_name(sym->type), sym_type_name(type));␊ |
124 | }␊ |
125 | ␊ |
126 | struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)␊ |
127 | {␊ |
128 | ␉struct property *prop = prop_alloc(type, current_entry->sym);␊ |
129 | ␊ |
130 | ␉prop->menu = current_entry;␊ |
131 | ␉prop->expr = expr;␊ |
132 | ␉prop->visible.expr = menu_check_dep(dep);␊ |
133 | ␊ |
134 | ␉if (prompt) {␊ |
135 | ␉␉if (isspace(*prompt)) {␊ |
136 | ␉␉␉prop_warn(prop, "leading whitespace ignored");␊ |
137 | ␉␉␉while (isspace(*prompt))␊ |
138 | ␉␉␉␉prompt++;␊ |
139 | ␉␉}␊ |
140 | ␉␉if (current_entry->prompt && current_entry != &rootmenu)␊ |
141 | ␉␉␉prop_warn(prop, "prompt redefined");␊ |
142 | ␊ |
143 | ␉␉/* Apply all upper menus' visibilities to actual prompts. */␊ |
144 | ␉␉if(type == P_PROMPT) {␊ |
145 | ␉␉␉struct menu *menu = current_entry;␊ |
146 | ␊ |
147 | ␉␉␉while ((menu = menu->parent) != NULL) {␊ |
148 | ␉␉␉␉if (!menu->visibility)␊ |
149 | ␉␉␉␉␉continue;␊ |
150 | ␉␉␉␉prop->visible.expr␊ |
151 | ␉␉␉␉␉= expr_alloc_and(prop->visible.expr,␊ |
152 | ␉␉␉␉␉␉␉ menu->visibility);␊ |
153 | ␉␉␉}␊ |
154 | ␉␉}␊ |
155 | ␊ |
156 | ␉␉current_entry->prompt = prop;␊ |
157 | ␉}␊ |
158 | ␉prop->text = prompt;␊ |
159 | ␊ |
160 | ␉return prop;␊ |
161 | }␊ |
162 | ␊ |
163 | struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)␊ |
164 | {␊ |
165 | ␉return menu_add_prop(type, prompt, NULL, dep);␊ |
166 | }␊ |
167 | ␊ |
168 | void menu_add_visibility(struct expr *expr)␊ |
169 | {␊ |
170 | ␉current_entry->visibility = expr_alloc_and(current_entry->visibility,␊ |
171 | ␉ expr);␊ |
172 | }␊ |
173 | ␊ |
174 | void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)␊ |
175 | {␊ |
176 | ␉menu_add_prop(type, NULL, expr, dep);␊ |
177 | }␊ |
178 | ␊ |
179 | void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)␊ |
180 | {␊ |
181 | ␉menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);␊ |
182 | }␊ |
183 | ␊ |
184 | void menu_add_option(int token, char *arg)␊ |
185 | {␊ |
186 | ␉struct property *prop;␊ |
187 | ␊ |
188 | ␉switch (token) {␊ |
189 | ␉case T_OPT_MODULES:␊ |
190 | ␉␉prop = prop_alloc(P_DEFAULT, modules_sym);␊ |
191 | ␉␉prop->expr = expr_alloc_symbol(current_entry->sym);␊ |
192 | ␉␉break;␊ |
193 | ␉case T_OPT_DEFCONFIG_LIST:␊ |
194 | ␉␉if (!sym_defconfig_list)␊ |
195 | ␉␉␉sym_defconfig_list = current_entry->sym;␊ |
196 | ␉␉else if (sym_defconfig_list != current_entry->sym)␊ |
197 | ␉␉␉zconf_error("trying to redefine defconfig symbol");␊ |
198 | ␉␉break;␊ |
199 | ␉case T_OPT_ENV:␊ |
200 | ␉␉//prop_add_env(arg);␊ |
201 | ␉␉break;␊ |
202 | ␉}␊ |
203 | }␊ |
204 | ␊ |
205 | static int menu_validate_number(struct symbol *sym, struct symbol *sym2)␊ |
206 | {␊ |
207 | ␉return sym2->type == S_INT || sym2->type == S_HEX ||␊ |
208 | ␉ (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));␊ |
209 | }␊ |
210 | ␊ |
211 | static void sym_check_prop(struct symbol *sym)␊ |
212 | {␊ |
213 | ␉struct property *prop;␊ |
214 | ␉struct symbol *sym2;␊ |
215 | ␉for (prop = sym->prop; prop; prop = prop->next) {␊ |
216 | ␉␉switch (prop->type) {␊ |
217 | ␉␉case P_DEFAULT:␊ |
218 | ␉␉␉if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&␊ |
219 | ␉␉␉ prop->expr->type != E_SYMBOL)␊ |
220 | ␉␉␉␉prop_warn(prop,␊ |
221 | ␉␉␉␉ "default for config symbol '%s'"␊ |
222 | ␉␉␉␉ " must be a single symbol", sym->name);␊ |
223 | ␉␉␉if (prop->expr->type != E_SYMBOL)␊ |
224 | ␉␉␉␉break;␊ |
225 | ␉␉␉sym2 = prop_get_symbol(prop);␊ |
226 | ␉␉␉if (sym->type == S_HEX || sym->type == S_INT) {␊ |
227 | ␉␉␉␉if (!menu_validate_number(sym, sym2))␊ |
228 | ␉␉␉␉␉prop_warn(prop,␊ |
229 | ␉␉␉␉␉ "'%s': number is invalid",␊ |
230 | ␉␉␉␉␉ sym->name);␊ |
231 | ␉␉␉}␊ |
232 | ␉␉␉break;␊ |
233 | ␉␉case P_SELECT:␊ |
234 | ␉␉␉sym2 = prop_get_symbol(prop);␊ |
235 | ␉␉␉if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)␊ |
236 | ␉␉␉␉prop_warn(prop,␊ |
237 | ␉␉␉␉ "config symbol '%s' uses select, but is "␊ |
238 | ␉␉␉␉ "not boolean or tristate", sym->name);␊ |
239 | ␉␉␉else if (sym2->type != S_UNKNOWN &&␊ |
240 | ␉␉␉ sym2->type != S_BOOLEAN &&␊ |
241 | ␉␉␉ sym2->type != S_TRISTATE)␊ |
242 | ␉␉␉␉prop_warn(prop,␊ |
243 | ␉␉␉␉ "'%s' has wrong type. 'select' only "␊ |
244 | ␉␉␉␉ "accept arguments of boolean and "␊ |
245 | ␉␉␉␉ "tristate type", sym2->name);␊ |
246 | ␉␉␉break;␊ |
247 | ␉␉case P_RANGE:␊ |
248 | ␉␉␉if (sym->type != S_INT && sym->type != S_HEX)␊ |
249 | ␉␉␉␉prop_warn(prop, "range is only allowed "␊ |
250 | ␉␉␉␉ "for int or hex symbols");␊ |
251 | ␉␉␉if (!menu_validate_number(sym, prop->expr->left.sym) ||␊ |
252 | ␉␉␉ !menu_validate_number(sym, prop->expr->right.sym))␊ |
253 | ␉␉␉␉prop_warn(prop, "range is invalid");␊ |
254 | ␉␉␉break;␊ |
255 | ␉␉default:␊ |
256 | ␉␉␉;␊ |
257 | ␉␉}␊ |
258 | ␉}␊ |
259 | }␊ |
260 | ␊ |
261 | void menu_finalize(struct menu *parent)␊ |
262 | {␊ |
263 | ␉struct menu *menu, *last_menu;␊ |
264 | ␉struct symbol *sym;␊ |
265 | ␉struct property *prop;␊ |
266 | ␉struct expr *parentdep, *basedep, *dep, *dep2, **ep;␊ |
267 | ␊ |
268 | ␉sym = parent->sym;␊ |
269 | ␉if (parent->list) {␊ |
270 | ␉␉if (sym && sym_is_choice(sym)) {␊ |
271 | ␉␉␉if (sym->type == S_UNKNOWN) {␊ |
272 | ␉␉␉␉/* find the first choice value to find out choice type */␊ |
273 | ␉␉␉␉current_entry = parent;␊ |
274 | ␉␉␉␉for (menu = parent->list; menu; menu = menu->next) {␊ |
275 | ␉␉␉␉␉if (menu->sym && menu->sym->type != S_UNKNOWN) {␊ |
276 | ␉␉␉␉␉␉menu_set_type(menu->sym->type);␊ |
277 | ␉␉␉␉␉␉break;␊ |
278 | ␉␉␉␉␉}␊ |
279 | ␉␉␉␉}␊ |
280 | ␉␉␉}␊ |
281 | ␉␉␉/* set the type of the remaining choice values */␊ |
282 | ␉␉␉for (menu = parent->list; menu; menu = menu->next) {␊ |
283 | ␉␉␉␉current_entry = menu;␊ |
284 | ␉␉␉␉if (menu->sym && menu->sym->type == S_UNKNOWN)␊ |
285 | ␉␉␉␉␉menu_set_type(sym->type);␊ |
286 | ␉␉␉}␊ |
287 | ␉␉␉parentdep = expr_alloc_symbol(sym);␊ |
288 | ␉␉} else if (parent->prompt)␊ |
289 | ␉␉␉parentdep = parent->prompt->visible.expr;␊ |
290 | ␉␉else␊ |
291 | ␉␉␉parentdep = parent->dep;␊ |
292 | ␊ |
293 | ␉␉for (menu = parent->list; menu; menu = menu->next) {␊ |
294 | ␉␉␉basedep = expr_transform(menu->dep);␊ |
295 | ␉␉␉basedep = expr_alloc_and(expr_copy(parentdep), basedep);␊ |
296 | ␉␉␉basedep = expr_eliminate_dups(basedep);␊ |
297 | ␉␉␉menu->dep = basedep;␊ |
298 | ␉␉␉if (menu->sym)␊ |
299 | ␉␉␉␉prop = menu->sym->prop;␊ |
300 | ␉␉␉else␊ |
301 | ␉␉␉␉prop = menu->prompt;␊ |
302 | ␉␉␉for (; prop; prop = prop->next) {␊ |
303 | ␉␉␉␉if (prop->menu != menu)␊ |
304 | ␉␉␉␉␉continue;␊ |
305 | ␉␉␉␉dep = expr_transform(prop->visible.expr);␊ |
306 | ␉␉␉␉dep = expr_alloc_and(expr_copy(basedep), dep);␊ |
307 | ␉␉␉␉dep = expr_eliminate_dups(dep);␊ |
308 | ␉␉␉␉if (menu->sym && menu->sym->type != S_TRISTATE)␊ |
309 | ␉␉␉␉␉dep = expr_trans_bool(dep);␊ |
310 | ␉␉␉␉prop->visible.expr = dep;␊ |
311 | ␉␉␉␉if (prop->type == P_SELECT) {␊ |
312 | ␉␉␉␉␉struct symbol *es = prop_get_symbol(prop);␊ |
313 | ␉␉␉␉␉es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,␊ |
314 | ␉␉␉␉␉␉␉expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));␊ |
315 | ␉␉␉␉}␊ |
316 | ␉␉␉}␊ |
317 | ␉␉}␊ |
318 | ␉␉for (menu = parent->list; menu; menu = menu->next)␊ |
319 | ␉␉␉menu_finalize(menu);␊ |
320 | ␉} else if (sym) {␊ |
321 | ␉␉basedep = parent->prompt ? parent->prompt->visible.expr : NULL;␊ |
322 | ␉␉basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);␊ |
323 | ␉␉basedep = expr_eliminate_dups(expr_transform(basedep));␊ |
324 | ␉␉last_menu = NULL;␊ |
325 | ␉␉for (menu = parent->next; menu; menu = menu->next) {␊ |
326 | ␉␉␉dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;␊ |
327 | ␉␉␉if (!expr_contains_symbol(dep, sym))␊ |
328 | ␉␉␉␉break;␊ |
329 | ␉␉␉if (expr_depends_symbol(dep, sym))␊ |
330 | ␉␉␉␉goto next;␊ |
331 | ␉␉␉dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);␊ |
332 | ␉␉␉dep = expr_eliminate_dups(expr_transform(dep));␊ |
333 | ␉␉␉dep2 = expr_copy(basedep);␊ |
334 | ␉␉␉expr_eliminate_eq(&dep, &dep2);␊ |
335 | ␉␉␉expr_free(dep);␊ |
336 | ␉␉␉if (!expr_is_yes(dep2)) {␊ |
337 | ␉␉␉␉expr_free(dep2);␊ |
338 | ␉␉␉␉break;␊ |
339 | ␉␉␉}␊ |
340 | ␉␉␉expr_free(dep2);␊ |
341 | ␉␉next:␊ |
342 | ␉␉␉menu_finalize(menu);␊ |
343 | ␉␉␉menu->parent = parent;␊ |
344 | ␉␉␉last_menu = menu;␊ |
345 | ␉␉}␊ |
346 | ␉␉if (last_menu) {␊ |
347 | ␉␉␉parent->list = parent->next;␊ |
348 | ␉␉␉parent->next = last_menu->next;␊ |
349 | ␉␉␉last_menu->next = NULL;␊ |
350 | ␉␉}␊ |
351 | ␊ |
352 | ␉␉sym->dir_dep.expr = parent->dep;␊ |
353 | ␉}␊ |
354 | ␉for (menu = parent->list; menu; menu = menu->next) {␊ |
355 | ␉␉if (sym && sym_is_choice(sym) &&␊ |
356 | ␉␉ menu->sym && !sym_is_choice_value(menu->sym)) {␊ |
357 | ␉␉␉current_entry = menu;␊ |
358 | ␉␉␉menu->sym->flags |= SYMBOL_CHOICEVAL;␊ |
359 | ␉␉␉if (!menu->prompt)␊ |
360 | ␉␉␉␉menu_warn(menu, "choice value must have a prompt");␊ |
361 | ␉␉␉for (prop = menu->sym->prop; prop; prop = prop->next) {␊ |
362 | ␉␉␉␉if (prop->type == P_DEFAULT)␊ |
363 | ␉␉␉␉␉prop_warn(prop, "defaults for choice "␊ |
364 | ␉␉␉␉␉␉ "values not supported");␊ |
365 | ␉␉␉␉if (prop->menu == menu)␊ |
366 | ␉␉␉␉␉continue;␊ |
367 | ␉␉␉␉if (prop->type == P_PROMPT &&␊ |
368 | ␉␉␉␉ prop->menu->parent->sym != sym)␊ |
369 | ␉␉␉␉␉prop_warn(prop, "choice value used outside its choice group");␊ |
370 | ␉␉␉}␊ |
371 | ␉␉␉/* Non-tristate choice values of tristate choices must␊ |
372 | ␉␉␉ * depend on the choice being set to Y. The choice␊ |
373 | ␉␉␉ * values' dependencies were propagated to their␊ |
374 | ␉␉␉ * properties above, so the change here must be re-␊ |
375 | ␉␉␉ * propagated.␊ |
376 | ␉␉␉ */␊ |
377 | ␉␉␉if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {␊ |
378 | ␉␉␉␉basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);␊ |
379 | ␉␉␉␉menu->dep = expr_alloc_and(basedep, menu->dep);␊ |
380 | ␉␉␉␉for (prop = menu->sym->prop; prop; prop = prop->next) {␊ |
381 | ␉␉␉␉␉if (prop->menu != menu)␊ |
382 | ␉␉␉␉␉␉continue;␊ |
383 | ␉␉␉␉␉prop->visible.expr = expr_alloc_and(expr_copy(basedep),␊ |
384 | ␉␉␉␉␉␉␉␉␉ prop->visible.expr);␊ |
385 | ␉␉␉␉}␊ |
386 | ␉␉␉}␊ |
387 | ␉␉␉menu_add_symbol(P_CHOICE, sym, NULL);␊ |
388 | ␉␉␉prop = sym_get_choice_prop(sym);␊ |
389 | ␉␉␉for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)␊ |
390 | ␉␉␉␉;␊ |
391 | ␉␉␉*ep = expr_alloc_one(E_LIST, NULL);␊ |
392 | ␉␉␉(*ep)->right.sym = menu->sym;␊ |
393 | ␉␉}␊ |
394 | ␉␉if (menu->list && (!menu->prompt || !menu->prompt->text)) {␊ |
395 | ␉␉␉for (last_menu = menu->list; ; last_menu = last_menu->next) {␊ |
396 | ␉␉␉␉last_menu->parent = parent;␊ |
397 | ␉␉␉␉if (!last_menu->next)␊ |
398 | ␉␉␉␉␉break;␊ |
399 | ␉␉␉}␊ |
400 | ␉␉␉last_menu->next = menu->next;␊ |
401 | ␉␉␉menu->next = menu->list;␊ |
402 | ␉␉␉menu->list = NULL;␊ |
403 | ␉␉}␊ |
404 | ␉}␊ |
405 | ␊ |
406 | ␉if (sym && !(sym->flags & SYMBOL_WARNED)) {␊ |
407 | ␉␉if (sym->type == S_UNKNOWN)␊ |
408 | ␉␉␉menu_warn(parent, "config symbol defined without type");␊ |
409 | ␊ |
410 | ␉␉if (sym_is_choice(sym) && !parent->prompt)␊ |
411 | ␉␉␉menu_warn(parent, "choice must have a prompt");␊ |
412 | ␊ |
413 | ␉␉/* Check properties connected to this symbol */␊ |
414 | ␉␉sym_check_prop(sym);␊ |
415 | ␉␉sym->flags |= SYMBOL_WARNED;␊ |
416 | ␉}␊ |
417 | ␊ |
418 | ␉if (sym && !sym_is_optional(sym) && parent->prompt) {␊ |
419 | ␉␉sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,␊ |
420 | ␉␉␉␉expr_alloc_and(parent->prompt->visible.expr,␊ |
421 | ␉␉␉␉␉expr_alloc_symbol(&symbol_mod)));␊ |
422 | ␉}␊ |
423 | }␊ |
424 | ␊ |
425 | bool menu_has_prompt(struct menu *menu)␊ |
426 | {␊ |
427 | ␉if (!menu->prompt)␊ |
428 | ␉␉return false;␊ |
429 | ␉return true;␊ |
430 | }␊ |
431 | ␊ |
432 | bool menu_is_visible(struct menu *menu)␊ |
433 | {␊ |
434 | ␉struct menu *child;␊ |
435 | ␉struct symbol *sym;␊ |
436 | ␉tristate visible;␊ |
437 | ␊ |
438 | ␉if (!menu->prompt)␊ |
439 | ␉␉return false;␊ |
440 | ␊ |
441 | ␉if (menu->visibility) {␊ |
442 | ␉␉if (expr_calc_value(menu->visibility) == no)␊ |
443 | ␉␉␉return no;␊ |
444 | ␉}␊ |
445 | ␊ |
446 | ␉sym = menu->sym;␊ |
447 | ␉if (sym) {␊ |
448 | ␉␉sym_calc_value(sym);␊ |
449 | ␉␉visible = menu->prompt->visible.tri;␊ |
450 | ␉} else␊ |
451 | ␉␉visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);␊ |
452 | ␊ |
453 | ␉if (visible != no)␊ |
454 | ␉␉return true;␊ |
455 | ␊ |
456 | ␉if (!sym || sym_get_tristate_value(menu->sym) == no)␊ |
457 | ␉␉return false;␊ |
458 | ␊ |
459 | ␉for (child = menu->list; child; child = child->next) {␊ |
460 | ␉␉if (menu_is_visible(child)) {␊ |
461 | ␉␉␉if (sym)␊ |
462 | ␉␉␉␉sym->flags |= SYMBOL_DEF_USER;␊ |
463 | ␉␉␉return true;␊ |
464 | ␉␉}␊ |
465 | ␉}␊ |
466 | ␊ |
467 | ␉return false;␊ |
468 | }␊ |
469 | ␊ |
470 | const char *menu_get_prompt(struct menu *menu)␊ |
471 | {␊ |
472 | ␉if (menu->prompt)␊ |
473 | ␉␉return menu->prompt->text;␊ |
474 | ␉else if (menu->sym)␊ |
475 | ␉␉return menu->sym->name;␊ |
476 | ␉return NULL;␊ |
477 | }␊ |
478 | ␊ |
479 | struct menu *menu_get_root_menu(struct menu *menu)␊ |
480 | {␊ |
481 | ␉return &rootmenu;␊ |
482 | }␊ |
483 | ␊ |
484 | struct menu *menu_get_parent_menu(struct menu *menu)␊ |
485 | {␊ |
486 | ␉enum prop_type type;␊ |
487 | ␊ |
488 | ␉for (; menu != &rootmenu; menu = menu->parent) {␊ |
489 | ␉␉type = menu->prompt ? menu->prompt->type : 0;␊ |
490 | ␉␉if (type == P_MENU)␊ |
491 | ␉␉␉break;␊ |
492 | ␉}␊ |
493 | ␉return menu;␊ |
494 | }␊ |
495 | ␊ |
496 | bool menu_has_help(struct menu *menu)␊ |
497 | {␊ |
498 | ␉return menu->help != NULL;␊ |
499 | }␊ |
500 | ␊ |
501 | const char *menu_get_help(struct menu *menu)␊ |
502 | {␊ |
503 | ␉if (menu->help)␊ |
504 | ␉␉return menu->help;␊ |
505 | ␉else␊ |
506 | ␉␉return "";␊ |
507 | }␊ |
508 | ␊ |
509 | static void get_prompt_str(struct gstr *r, struct property *prop)␊ |
510 | {␊ |
511 | ␉int i, j;␊ |
512 | ␉struct menu *submenu[8], *menu;␊ |
513 | ␊ |
514 | ␉str_printf(r, _("Prompt: %s\n"), _(prop->text));␊ |
515 | ␉str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,␊ |
516 | ␉␉prop->menu->lineno);␊ |
517 | ␉if (!expr_is_yes(prop->visible.expr)) {␊ |
518 | ␉␉str_append(r, _(" Depends on: "));␊ |
519 | ␉␉expr_gstr_print(prop->visible.expr, r);␊ |
520 | ␉␉str_append(r, "\n");␊ |
521 | ␉}␊ |
522 | ␉menu = prop->menu->parent;␊ |
523 | ␉for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)␊ |
524 | ␉␉submenu[i++] = menu;␊ |
525 | ␉if (i > 0) {␊ |
526 | ␉␉str_printf(r, _(" Location:\n"));␊ |
527 | ␉␉for (j = 4; --i >= 0; j += 2) {␊ |
528 | ␉␉␉menu = submenu[i];␊ |
529 | ␉␉␉str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));␊ |
530 | ␉␉␉if (menu->sym) {␊ |
531 | ␉␉␉␉str_printf(r, " (%s [=%s])", menu->sym->name ?␊ |
532 | ␉␉␉␉␉menu->sym->name : _("<choice>"),␊ |
533 | ␉␉␉␉␉sym_get_string_value(menu->sym));␊ |
534 | ␉␉␉}␊ |
535 | ␉␉␉str_append(r, "\n");␊ |
536 | ␉␉}␊ |
537 | ␉}␊ |
538 | }␊ |
539 | ␊ |
540 | void get_symbol_str(struct gstr *r, struct symbol *sym)␊ |
541 | {␊ |
542 | ␉bool hit;␊ |
543 | ␉struct property *prop;␊ |
544 | ␊ |
545 | ␉if (sym && sym->name) {␊ |
546 | ␉␉str_printf(r, "Symbol: %s [=%s]\n", sym->name,␊ |
547 | ␉␉␉ sym_get_string_value(sym));␊ |
548 | ␉␉str_printf(r, "Type : %s\n", sym_type_name(sym->type));␊ |
549 | ␉␉if (sym->type == S_INT || sym->type == S_HEX) {␊ |
550 | ␉␉␉prop = sym_get_range_prop(sym);␊ |
551 | ␉␉␉if (prop) {␊ |
552 | ␉␉␉␉str_printf(r, "Range : ");␊ |
553 | ␉␉␉␉expr_gstr_print(prop->expr, r);␊ |
554 | ␉␉␉␉str_append(r, "\n");␊ |
555 | ␉␉␉}␊ |
556 | ␉␉}␊ |
557 | ␉}␊ |
558 | ␉for_all_prompts(sym, prop)␊ |
559 | ␉␉get_prompt_str(r, prop);␊ |
560 | ␉hit = false;␊ |
561 | ␉for_all_properties(sym, prop, P_SELECT) {␊ |
562 | ␉␉if (!hit) {␊ |
563 | ␉␉␉str_append(r, " Selects: ");␊ |
564 | ␉␉␉hit = true;␊ |
565 | ␉␉} else␊ |
566 | ␉␉␉str_printf(r, " && ");␊ |
567 | ␉␉expr_gstr_print(prop->expr, r);␊ |
568 | ␉}␊ |
569 | ␉if (hit)␊ |
570 | ␉␉str_append(r, "\n");␊ |
571 | ␉if (sym->rev_dep.expr) {␊ |
572 | ␉␉str_append(r, _(" Selected by: "));␊ |
573 | ␉␉expr_gstr_print(sym->rev_dep.expr, r);␊ |
574 | ␉␉str_append(r, "\n");␊ |
575 | ␉}␊ |
576 | ␉str_append(r, "\n\n");␊ |
577 | }␊ |
578 | ␊ |
579 | struct gstr get_relations_str(struct symbol **sym_arr)␊ |
580 | {␊ |
581 | ␉struct symbol *sym;␊ |
582 | ␉struct gstr res = str_new();␊ |
583 | ␉int i;␊ |
584 | ␊ |
585 | ␉for (i = 0; sym_arr && (sym = sym_arr[i]); i++)␊ |
586 | ␉␉get_symbol_str(&res, sym);␊ |
587 | ␉if (!i)␊ |
588 | ␉␉str_append(&res, _("No matches found.\n"));␊ |
589 | ␉return res;␊ |
590 | }␊ |
591 | ␊ |
592 | ␊ |
593 | void menu_get_ext_help(struct menu *menu, struct gstr *help)␊ |
594 | {␊ |
595 | ␉struct symbol *sym = menu->sym;␊ |
596 | ␊ |
597 | ␉if (menu_has_help(menu)) {␊ |
598 | ␉␉if (sym->name) {␊ |
599 | ␉␉␉str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);␊ |
600 | ␉␉␉str_append(help, _(menu_get_help(menu)));␊ |
601 | ␉␉␉str_append(help, "\n");␊ |
602 | ␉␉}␊ |
603 | ␉} else {␊ |
604 | ␉␉str_append(help, nohelp_text);␊ |
605 | ␉}␊ |
606 | ␉if (sym)␊ |
607 | ␉␉get_symbol_str(help, sym);␊ |
608 | }␊ |
609 | |