kconfig: use sym_get_choice_menu() in sym_check_prop()
[linux-2.6-block.git] / scripts / kconfig / menu.c
CommitLineData
0c874100 1// SPDX-License-Identifier: GPL-2.0
1da177e4
LT
2/*
3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
1da177e4
LT
4 */
5
dd003306 6#include <ctype.h>
10a4b277 7#include <stdarg.h>
1da177e4
LT
8#include <stdlib.h>
9#include <string.h>
10
1da177e4 11#include "lkc.h"
a77a05dc 12#include "internal.h"
4dae9cf5 13#include "list.h"
1da177e4 14
57e6292d 15static const char nohelp_text[] = "There is no help available for this option.";
6bd5999d 16
1da177e4
LT
17struct menu rootmenu;
18static struct menu **last_entry_ptr;
19
7284b4fb
MY
20/**
21 * menu_next - return the next menu entry with depth-first traversal
22 * @menu: pointer to the current menu
23 * @root: root of the sub-tree to traverse. If NULL is given, the traveral
24 * continues until it reaches the end of the entire menu tree.
25 * return: the menu to visit next, or NULL when it reaches the end.
26 */
27struct menu *menu_next(struct menu *menu, struct menu *root)
28{
29 if (menu->list)
30 return menu->list;
31
32 while (menu != root && !menu->next)
33 menu = menu->parent;
34
35 if (menu == root)
36 return NULL;
37
38 return menu->next;
39}
40
93449082 41void menu_warn(struct menu *menu, const char *fmt, ...)
1da177e4
LT
42{
43 va_list ap;
44 va_start(ap, fmt);
40bab83a 45 fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
1da177e4
LT
46 vfprintf(stderr, fmt, ap);
47 fprintf(stderr, "\n");
48 va_end(ap);
49}
50
51static void prop_warn(struct property *prop, const char *fmt, ...)
52{
53 va_list ap;
54 va_start(ap, fmt);
1a90b0cd 55 fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
1da177e4
LT
56 vfprintf(stderr, fmt, ap);
57 fprintf(stderr, "\n");
58 va_end(ap);
59}
60
692d97c3 61void _menu_init(void)
1da177e4
LT
62{
63 current_entry = current_menu = &rootmenu;
64 last_entry_ptr = &rootmenu.list;
65}
66
67void menu_add_entry(struct symbol *sym)
68{
69 struct menu *menu;
70
177acf78 71 menu = xmalloc(sizeof(*menu));
1da177e4
LT
72 memset(menu, 0, sizeof(*menu));
73 menu->sym = sym;
74 menu->parent = current_menu;
40bab83a 75 menu->filename = cur_filename;
1d7c4f10 76 menu->lineno = cur_lineno;
1da177e4
LT
77
78 *last_entry_ptr = menu;
79 last_entry_ptr = &menu->next;
80 current_entry = menu;
e0492219 81 if (sym) {
59e89e3d 82 menu_add_symbol(P_SYMBOL, sym, NULL);
e0492219
MY
83 list_add_tail(&menu->link, &sym->menus);
84 }
1da177e4
LT
85}
86
a02f0570 87struct menu *menu_add_menu(void)
1da177e4 88{
1da177e4 89 last_entry_ptr = &current_entry->list;
644a4b6c
MY
90 current_menu = current_entry;
91 return current_menu;
1da177e4
LT
92}
93
94void menu_end_menu(void)
95{
96 last_entry_ptr = &current_menu->next;
97 current_menu = current_menu->parent;
98}
99
9a826842
UM
100/*
101 * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
102 * without modules
103 */
104static struct expr *rewrite_m(struct expr *e)
1da177e4
LT
105{
106 if (!e)
107 return e;
108
109 switch (e->type) {
110 case E_NOT:
9a826842 111 e->left.expr = rewrite_m(e->left.expr);
1da177e4
LT
112 break;
113 case E_OR:
114 case E_AND:
9a826842
UM
115 e->left.expr = rewrite_m(e->left.expr);
116 e->right.expr = rewrite_m(e->right.expr);
1da177e4
LT
117 break;
118 case E_SYMBOL:
119 /* change 'm' into 'm' && MODULES */
120 if (e->left.sym == &symbol_mod)
121 return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
122 break;
123 default:
124 break;
125 }
126 return e;
127}
128
129void menu_add_dep(struct expr *dep)
130{
f77850d3 131 current_entry->dep = expr_alloc_and(current_entry->dep, dep);
1da177e4
LT
132}
133
134void menu_set_type(int type)
135{
136 struct symbol *sym = current_entry->sym;
137
138 if (sym->type == type)
139 return;
140 if (sym->type == S_UNKNOWN) {
141 sym->type = type;
142 return;
143 }
57540f1d
MW
144 menu_warn(current_entry,
145 "ignoring type redefinition of '%s' from '%s' to '%s'",
146 sym->name ? sym->name : "<choice>",
147 sym_type_name(sym->type), sym_type_name(type));
1da177e4
LT
148}
149
2ffeef61
MY
150static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
151 struct expr *dep)
1da177e4 152{
adf7c5bd 153 struct property *prop;
1da177e4 154
adf7c5bd
MY
155 prop = xmalloc(sizeof(*prop));
156 memset(prop, 0, sizeof(*prop));
157 prop->type = type;
1a90b0cd 158 prop->filename = cur_filename;
1d7c4f10 159 prop->lineno = cur_lineno;
1da177e4 160 prop->menu = current_entry;
1da177e4 161 prop->expr = expr;
f77850d3 162 prop->visible.expr = dep;
1da177e4 163
adf7c5bd
MY
164 /* append property to the prop list of symbol */
165 if (current_entry->sym) {
166 struct property **propp;
167
168 for (propp = &current_entry->sym->prop;
169 *propp;
170 propp = &(*propp)->next)
171 ;
172 *propp = prop;
173 }
174
024352ff
MY
175 return prop;
176}
177
178struct property *menu_add_prompt(enum prop_type type, char *prompt,
179 struct expr *dep)
180{
2ffeef61 181 struct property *prop = menu_add_prop(type, NULL, dep);
7ad12278 182
024352ff
MY
183 if (isspace(*prompt)) {
184 prop_warn(prop, "leading whitespace ignored");
185 while (isspace(*prompt))
186 prompt++;
1da177e4 187 }
024352ff
MY
188 if (current_entry->prompt)
189 prop_warn(prop, "prompt redefined");
190
191 /* Apply all upper menus' visibilities to actual prompts. */
192 if (type == P_PROMPT) {
193 struct menu *menu = current_entry;
194
195 while ((menu = menu->parent) != NULL) {
196 struct expr *dup_expr;
197
198 if (!menu->visibility)
199 continue;
200 /*
201 * Do not add a reference to the menu's visibility
202 * expression but use a copy of it. Otherwise the
203 * expression reduction functions will modify
204 * expressions that have multiple references which
205 * can cause unwanted side effects.
206 */
207 dup_expr = expr_copy(menu->visibility);
208
209 prop->visible.expr = expr_alloc_and(prop->visible.expr,
210 dup_expr);
211 }
212 }
213
214 current_entry->prompt = prop;
f001f7f8 215 prop->text = prompt;
1da177e4
LT
216
217 return prop;
218}
219
86e187ff
AL
220void menu_add_visibility(struct expr *expr)
221{
222 current_entry->visibility = expr_alloc_and(current_entry->visibility,
223 expr);
224}
225
1da177e4
LT
226void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
227{
2ffeef61 228 menu_add_prop(type, expr, dep);
1da177e4
LT
229}
230
231void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
232{
2ffeef61 233 menu_add_prop(type, expr_alloc_symbol(sym), dep);
1da177e4
LT
234}
235
ab60bd0b 236static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
4cf3cbe2
RZ
237{
238 return sym2->type == S_INT || sym2->type == S_HEX ||
239 (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
240}
241
4356f489 242static void sym_check_prop(struct symbol *sym)
1da177e4
LT
243{
244 struct property *prop;
245 struct symbol *sym2;
237e3ad0
NP
246 char *use;
247
1da177e4
LT
248 for (prop = sym->prop; prop; prop = prop->next) {
249 switch (prop->type) {
250 case P_DEFAULT:
251 if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
252 prop->expr->type != E_SYMBOL)
253 prop_warn(prop,
4280eae0 254 "default for config symbol '%s'"
1da177e4 255 " must be a single symbol", sym->name);
ab60bd0b
AL
256 if (prop->expr->type != E_SYMBOL)
257 break;
258 sym2 = prop_get_symbol(prop);
259 if (sym->type == S_HEX || sym->type == S_INT) {
260 if (!menu_validate_number(sym, sym2))
261 prop_warn(prop,
262 "'%s': number is invalid",
263 sym->name);
264 }
2c37e084 265 if (sym_is_choice(sym)) {
6ffe4fdf 266 struct menu *choice = sym_get_choice_menu(sym2);
2c37e084 267
6ffe4fdf 268 if (!choice || choice->sym != sym)
2c37e084
UM
269 prop_warn(prop,
270 "choice default symbol '%s' is not contained in the choice",
271 sym2->name);
272 }
1da177e4
LT
273 break;
274 case P_SELECT:
237e3ad0
NP
275 case P_IMPLY:
276 use = prop->type == P_SELECT ? "select" : "imply";
1da177e4
LT
277 sym2 = prop_get_symbol(prop);
278 if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
279 prop_warn(prop,
237e3ad0 280 "config symbol '%s' uses %s, but is "
b92d804a 281 "not bool or tristate", sym->name, use);
603d4988 282 else if (sym2->type != S_UNKNOWN &&
bb66fc67
MY
283 sym2->type != S_BOOLEAN &&
284 sym2->type != S_TRISTATE)
1da177e4 285 prop_warn(prop,
237e3ad0 286 "'%s' has wrong type. '%s' only "
b92d804a 287 "accept arguments of bool and "
237e3ad0 288 "tristate type", sym2->name, use);
1da177e4
LT
289 break;
290 case P_RANGE:
291 if (sym->type != S_INT && sym->type != S_HEX)
292 prop_warn(prop, "range is only allowed "
bb66fc67 293 "for int or hex symbols");
ab60bd0b
AL
294 if (!menu_validate_number(sym, prop->expr->left.sym) ||
295 !menu_validate_number(sym, prop->expr->right.sym))
1da177e4
LT
296 prop_warn(prop, "range is invalid");
297 break;
298 default:
299 ;
300 }
301 }
302}
303
7e3465f6 304static void _menu_finalize(struct menu *parent, bool inside_choice)
1da177e4
LT
305{
306 struct menu *menu, *last_menu;
307 struct symbol *sym;
308 struct property *prop;
309 struct expr *parentdep, *basedep, *dep, *dep2, **ep;
310
311 sym = parent->sym;
312 if (parent->list) {
fa8cedae
UM
313 /*
314 * This menu node has children. We (recursively) process them
315 * and propagate parent dependencies before moving on.
316 */
317
7e3465f6
MY
318 bool is_choice = false;
319
320 if (sym && sym_is_choice(sym))
321 is_choice = true;
322
323 if (is_choice) {
5a1aa8a1
RZ
324 if (sym->type == S_UNKNOWN) {
325 /* find the first choice value to find out choice type */
326 current_entry = parent;
327 for (menu = parent->list; menu; menu = menu->next) {
328 if (menu->sym && menu->sym->type != S_UNKNOWN) {
f5eaa323 329 menu_set_type(menu->sym->type);
5a1aa8a1
RZ
330 break;
331 }
1da177e4
LT
332 }
333 }
d3465af6
UM
334
335 /*
336 * Use the choice itself as the parent dependency of
337 * the contained items. This turns the mode of the
338 * choice into an upper bound on the visibility of the
339 * choice value symbols.
340 */
1da177e4 341 parentdep = expr_alloc_symbol(sym);
de026ca9
MY
342 } else {
343 /* Menu node for 'menu', 'if' */
1da177e4 344 parentdep = parent->dep;
de026ca9 345 }
1da177e4 346
fa8cedae 347 /* For each child menu node... */
1da177e4 348 for (menu = parent->list; menu; menu = menu->next) {
fa8cedae
UM
349 /*
350 * Propagate parent dependencies to the child menu
351 * node, also rewriting and simplifying expressions
352 */
f77850d3
UM
353 basedep = rewrite_m(menu->dep);
354 basedep = expr_transform(basedep);
e8b8c977 355 basedep = expr_alloc_and(expr_copy(parentdep), basedep);
1da177e4
LT
356 basedep = expr_eliminate_dups(basedep);
357 menu->dep = basedep;
fa8cedae 358
1da177e4 359 if (menu->sym)
fa8cedae
UM
360 /*
361 * Note: For symbols, all prompts are included
362 * too in the symbol's own property list
363 */
1da177e4
LT
364 prop = menu->sym->prop;
365 else
fa8cedae
UM
366 /*
367 * For non-symbol menu nodes, we just need to
368 * handle the prompt
369 */
1da177e4 370 prop = menu->prompt;
fa8cedae
UM
371
372 /* For each property... */
1da177e4
LT
373 for (; prop; prop = prop->next) {
374 if (prop->menu != menu)
fa8cedae
UM
375 /*
376 * Two possibilities:
377 *
378 * 1. The property lacks dependencies
379 * and so isn't location-specific,
380 * e.g. an 'option'
381 *
382 * 2. The property belongs to a symbol
383 * defined in multiple locations and
384 * is from some other location. It
385 * will be handled there in that
386 * case.
387 *
388 * Skip the property.
389 */
1da177e4 390 continue;
fa8cedae
UM
391
392 /*
393 * Propagate parent dependencies to the
394 * property's condition, rewriting and
395 * simplifying expressions at the same time
396 */
f77850d3
UM
397 dep = rewrite_m(prop->visible.expr);
398 dep = expr_transform(dep);
1da177e4
LT
399 dep = expr_alloc_and(expr_copy(basedep), dep);
400 dep = expr_eliminate_dups(dep);
401 if (menu->sym && menu->sym->type != S_TRISTATE)
402 dep = expr_trans_bool(dep);
403 prop->visible.expr = dep;
fa8cedae
UM
404
405 /*
406 * Handle selects and implies, which modify the
407 * dependencies of the selected/implied symbol
408 */
1da177e4
LT
409 if (prop->type == P_SELECT) {
410 struct symbol *es = prop_get_symbol(prop);
411 es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
412 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
237e3ad0
NP
413 } else if (prop->type == P_IMPLY) {
414 struct symbol *es = prop_get_symbol(prop);
415 es->implied.expr = expr_alloc_or(es->implied.expr,
416 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
1da177e4
LT
417 }
418 }
419 }
fa8cedae 420
7e3465f6 421 if (is_choice)
7cf33f88
UM
422 expr_free(parentdep);
423
fa8cedae
UM
424 /*
425 * Recursively process children in the same fashion before
426 * moving on
427 */
1da177e4 428 for (menu = parent->list; menu; menu = menu->next)
7e3465f6
MY
429 _menu_finalize(menu, is_choice);
430 } else if (!inside_choice && sym) {
05cccce5
UM
431 /*
432 * Automatic submenu creation. If sym is a symbol and A, B, C,
433 * ... are consecutive items (symbols, menus, ifs, etc.) that
434 * all depend on sym, then the following menu structure is
435 * created:
436 *
437 * sym
438 * +-A
439 * +-B
440 * +-C
441 * ...
442 *
443 * This also works recursively, giving the following structure
444 * if A is a symbol and B depends on A:
445 *
446 * sym
447 * +-A
448 * | +-B
449 * +-C
450 * ...
451 */
452
1da177e4
LT
453 basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
454 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
455 basedep = expr_eliminate_dups(expr_transform(basedep));
05cccce5
UM
456
457 /* Examine consecutive elements after sym */
1da177e4
LT
458 last_menu = NULL;
459 for (menu = parent->next; menu; menu = menu->next) {
460 dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
461 if (!expr_contains_symbol(dep, sym))
05cccce5 462 /* No dependency, quit */
1da177e4
LT
463 break;
464 if (expr_depends_symbol(dep, sym))
05cccce5 465 /* Absolute dependency, put in submenu */
1da177e4 466 goto next;
05cccce5
UM
467
468 /*
469 * Also consider it a dependency on sym if our
470 * dependencies contain sym and are a "superset" of
471 * sym's dependencies, e.g. '(sym || Q) && R' when sym
472 * depends on R.
473 *
474 * Note that 'R' might be from an enclosing menu or if,
475 * making this a more common case than it might seem.
476 */
1da177e4
LT
477 dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
478 dep = expr_eliminate_dups(expr_transform(dep));
479 dep2 = expr_copy(basedep);
480 expr_eliminate_eq(&dep, &dep2);
481 expr_free(dep);
482 if (!expr_is_yes(dep2)) {
05cccce5 483 /* Not superset, quit */
1da177e4
LT
484 expr_free(dep2);
485 break;
486 }
05cccce5 487 /* Superset, put in submenu */
1da177e4
LT
488 expr_free(dep2);
489 next:
7e3465f6 490 _menu_finalize(menu, false);
1da177e4
LT
491 menu->parent = parent;
492 last_menu = menu;
493 }
ae7440ef 494 expr_free(basedep);
1da177e4
LT
495 if (last_menu) {
496 parent->list = parent->next;
497 parent->next = last_menu->next;
498 last_menu->next = NULL;
499 }
ff5ff606 500
ec6452a5 501 sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
1da177e4
LT
502 }
503 for (menu = parent->list; menu; menu = menu->next) {
5a1aa8a1
RZ
504 if (sym && sym_is_choice(sym) &&
505 menu->sym && !sym_is_choice_value(menu->sym)) {
506 current_entry = menu;
1da177e4 507 menu->sym->flags |= SYMBOL_CHOICEVAL;
f5eaa323
JB
508 /* Non-tristate choice values of tristate choices must
509 * depend on the choice being set to Y. The choice
510 * values' dependencies were propagated to their
511 * properties above, so the change here must be re-
5a1aa8a1
RZ
512 * propagated.
513 */
f5eaa323
JB
514 if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
515 basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
5a1aa8a1 516 menu->dep = expr_alloc_and(basedep, menu->dep);
f5eaa323
JB
517 for (prop = menu->sym->prop; prop; prop = prop->next) {
518 if (prop->menu != menu)
519 continue;
5a1aa8a1
RZ
520 prop->visible.expr = expr_alloc_and(expr_copy(basedep),
521 prop->visible.expr);
f5eaa323
JB
522 }
523 }
1da177e4
LT
524 menu_add_symbol(P_CHOICE, sym, NULL);
525 prop = sym_get_choice_prop(sym);
526 for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
527 ;
7a962923 528 *ep = expr_alloc_one(E_LIST, NULL);
1da177e4
LT
529 (*ep)->right.sym = menu->sym;
530 }
9d1a9e8b
UM
531
532 /*
533 * This code serves two purposes:
534 *
535 * (1) Flattening 'if' blocks, which do not specify a submenu
536 * and only add dependencies.
537 *
538 * (Automatic submenu creation might still create a submenu
539 * from an 'if' before this code runs.)
540 *
541 * (2) "Undoing" any automatic submenus created earlier below
542 * promptless symbols.
543 *
544 * Before:
545 *
546 * A
547 * if ... (or promptless symbol)
548 * +-B
549 * +-C
550 * D
551 *
552 * After:
553 *
554 * A
555 * if ... (or promptless symbol)
556 * B
557 * C
558 * D
559 */
1da177e4
LT
560 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
561 for (last_menu = menu->list; ; last_menu = last_menu->next) {
562 last_menu->parent = parent;
563 if (!last_menu->next)
564 break;
565 }
566 last_menu->next = menu->next;
567 menu->next = menu->list;
568 menu->list = NULL;
569 }
570 }
571
572 if (sym && !(sym->flags & SYMBOL_WARNED)) {
573 if (sym->type == S_UNKNOWN)
f001f7f8 574 menu_warn(parent, "config symbol defined without type");
1da177e4 575
1da177e4
LT
576 /* Check properties connected to this symbol */
577 sym_check_prop(sym);
578 sym->flags |= SYMBOL_WARNED;
579 }
580
3e41ba05 581 /*
6a121588
MY
582 * For choices, add a reverse dependency (corresponding to a select) of
583 * '<visibility> && m'. This prevents the user from setting the choice
584 * mode to 'n' when the choice is visible.
3e41ba05 585 */
6a121588 586 if (sym && sym_is_choice(sym) && parent->prompt) {
1da177e4
LT
587 sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
588 expr_alloc_and(parent->prompt->visible.expr,
589 expr_alloc_symbol(&symbol_mod)));
590 }
591}
592
7e3465f6
MY
593void menu_finalize(void)
594{
595 _menu_finalize(&rootmenu, false);
596}
597
22c7eca6
LZ
598bool menu_has_prompt(struct menu *menu)
599{
600 if (!menu->prompt)
601 return false;
602 return true;
603}
604
1278ebdb
DG
605/*
606 * Determine if a menu is empty.
607 * A menu is considered empty if it contains no or only
608 * invisible entries.
609 */
610bool menu_is_empty(struct menu *menu)
611{
612 struct menu *child;
613
614 for (child = menu->list; child; child = child->next) {
615 if (menu_is_visible(child))
616 return(false);
617 }
618 return(true);
619}
620
1da177e4
LT
621bool menu_is_visible(struct menu *menu)
622{
623 struct menu *child;
624 struct symbol *sym;
625 tristate visible;
626
627 if (!menu->prompt)
628 return false;
22c7eca6 629
86e187ff
AL
630 if (menu->visibility) {
631 if (expr_calc_value(menu->visibility) == no)
aab24a89 632 return false;
86e187ff
AL
633 }
634
1da177e4
LT
635 sym = menu->sym;
636 if (sym) {
637 sym_calc_value(sym);
638 visible = menu->prompt->visible.tri;
639 } else
640 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
641
642 if (visible != no)
643 return true;
22c7eca6 644
1da177e4
LT
645 if (!sym || sym_get_tristate_value(menu->sym) == no)
646 return false;
647
3fb9acb3
LZ
648 for (child = menu->list; child; child = child->next) {
649 if (menu_is_visible(child)) {
650 if (sym)
651 sym->flags |= SYMBOL_DEF_USER;
1da177e4 652 return true;
3fb9acb3
LZ
653 }
654 }
22c7eca6 655
1da177e4
LT
656 return false;
657}
658
659const char *menu_get_prompt(struct menu *menu)
660{
661 if (menu->prompt)
01771b0f 662 return menu->prompt->text;
1da177e4 663 else if (menu->sym)
01771b0f 664 return menu->sym->name;
1da177e4
LT
665 return NULL;
666}
667
1da177e4
LT
668struct menu *menu_get_parent_menu(struct menu *menu)
669{
670 enum prop_type type;
671
672 for (; menu != &rootmenu; menu = menu->parent) {
673 type = menu->prompt ? menu->prompt->type : 0;
674 if (type == P_MENU)
675 break;
676 }
677 return menu;
678}
679
edda15f2
TH
680static void get_def_str(struct gstr *r, struct menu *menu)
681{
682 str_printf(r, "Defined at %s:%d\n",
40bab83a 683 menu->filename, menu->lineno);
edda15f2
TH
684}
685
686static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
687{
688 if (!expr_is_yes(expr)) {
689 str_append(r, prefix);
690 expr_gstr_print(expr, r);
691 str_append(r, "\n");
692 }
693}
694
e14f1242
MY
695int __attribute__((weak)) get_jump_key_char(void)
696{
697 return -1;
698}
699
95ac9b3b 700static void get_prompt_str(struct gstr *r, struct property *prop,
bad9955d 701 struct list_head *head)
6bd5999d
CR
702{
703 int i, j;
5e609add 704 struct menu *submenu[8], *menu, *location = NULL;
2d560306 705 struct jump_key *jump = NULL;
6bd5999d 706
edda15f2
TH
707 str_printf(r, " Prompt: %s\n", prop->text);
708
709 get_dep_str(r, prop->menu->dep, " Depends on: ");
3460d0bc
TH
710 /*
711 * Most prompts in Linux have visibility that exactly matches their
712 * dependencies. For these, we print only the dependencies to improve
713 * readability. However, prompts with inline "if" expressions and
714 * prompts with a parent that has a "visible if" expression have
715 * differing dependencies and visibility. In these rare cases, we
716 * print both.
717 */
718 if (!expr_eq(prop->menu->dep, prop->visible.expr))
719 get_dep_str(r, prop->visible.expr, " Visible if: ");
720
7a263a04
MY
721 menu = prop->menu;
722 for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
6bd5999d 723 submenu[i++] = menu;
1791360c 724 if (location == NULL && menu_is_visible(menu))
5e609add
BP
725 location = menu;
726 }
95ac9b3b 727 if (head && location) {
177acf78 728 jump = xmalloc(sizeof(struct jump_key));
7a263a04 729 jump->target = location;
bad9955d 730 list_add_tail(&jump->entries, head);
95ac9b3b 731 }
5e609add 732
d05377e1 733 str_printf(r, " Location:\n");
e14f1242
MY
734 for (j = 0; --i >= 0; j++) {
735 int jk = -1;
736 int indent = 2 * j + 4;
737
d05377e1 738 menu = submenu[i];
e14f1242 739 if (jump && menu == location) {
d05377e1 740 jump->offset = strlen(r->s);
e14f1242
MY
741 jk = get_jump_key_char();
742 }
743
744 if (jk >= 0) {
745 str_printf(r, "(%c)", jk);
746 indent -= 3;
747 }
748
749 str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu));
d05377e1
AM
750 if (menu->sym) {
751 str_printf(r, " (%s [=%s])", menu->sym->name ?
752 menu->sym->name : "<choice>",
753 sym_get_string_value(menu->sym));
6bd5999d 754 }
d05377e1 755 str_append(r, "\n");
6bd5999d
CR
756 }
757}
758
237e3ad0
NP
759static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
760 enum prop_type tok, const char *prefix)
761{
762 bool hit = false;
763 struct property *prop;
764
765 for_all_properties(sym, prop, tok) {
766 if (!hit) {
767 str_append(r, prefix);
768 hit = true;
769 } else
770 str_printf(r, " && ");
771 expr_gstr_print(prop->expr, r);
772 }
773 if (hit)
774 str_append(r, "\n");
775}
776
5e609add 777/*
95ac9b3b 778 * head is optional and may be NULL
5e609add 779 */
ad8d40cd 780static void get_symbol_str(struct gstr *r, struct symbol *sym,
bad9955d 781 struct list_head *head)
6bd5999d 782{
6bd5999d 783 struct property *prop;
bedf9236 784 struct menu *menu;
6bd5999d 785
b040b44c 786 if (sym && sym->name) {
6bd5999d
CR
787 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
788 sym_get_string_value(sym));
b040b44c 789 str_printf(r, "Type : %s\n", sym_type_name(sym->type));
70ed0747
LZ
790 if (sym->type == S_INT || sym->type == S_HEX) {
791 prop = sym_get_range_prop(sym);
792 if (prop) {
793 str_printf(r, "Range : ");
794 expr_gstr_print(prop->expr, r);
795 str_append(r, "\n");
796 }
797 }
b040b44c 798 }
edda15f2
TH
799
800 /* Print the definitions with prompts before the ones without */
bedf9236
MY
801 list_for_each_entry(menu, &sym->menus, link) {
802 if (menu->prompt) {
803 get_def_str(r, menu);
804 get_prompt_str(r, menu->prompt, head);
edda15f2
TH
805 }
806 }
807
bedf9236
MY
808 list_for_each_entry(menu, &sym->menus, link) {
809 if (!menu->prompt) {
810 get_def_str(r, menu);
811 get_dep_str(r, menu->dep, " Depends on: ");
383da76f 812 }
bcdedcc1 813 }
383da76f 814
a9609686 815 get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
6bd5999d 816 if (sym->rev_dep.expr) {
a9609686
TH
817 expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n");
818 expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n");
819 expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n");
6bd5999d 820 }
237e3ad0 821
a9609686 822 get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
237e3ad0 823 if (sym->implied.expr) {
a9609686
TH
824 expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n");
825 expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n");
826 expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n");
237e3ad0
NP
827 }
828
6bd5999d
CR
829 str_append(r, "\n\n");
830}
831
bad9955d 832struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
692d97c3 833{
834 struct symbol *sym;
835 struct gstr res = str_new();
95ac9b3b 836 int i;
692d97c3 837
838 for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
95ac9b3b 839 get_symbol_str(&res, sym, head);
692d97c3 840 if (!i)
694c49a7 841 str_append(&res, "No matches found.\n");
692d97c3 842 return res;
843}
844
845
6bd5999d
CR
846void menu_get_ext_help(struct menu *menu, struct gstr *help)
847{
848 struct symbol *sym = menu->sym;
57e6292d 849 const char *help_text = nohelp_text;
6bd5999d 850
092e39d1 851 if (menu->help) {
3f198dfe 852 if (sym->name)
ffb5957b 853 str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
092e39d1 854 help_text = menu->help;
6bd5999d 855 }
694c49a7 856 str_printf(help, "%s\n", help_text);
4779105e 857 if (sym)
95ac9b3b 858 get_symbol_str(help, sym, NULL);
6bd5999d 859}