10c874100SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
6dd003306SArnaud Lacombe #include <ctype.h>
710a4b277SArnaud Lacombe #include <stdarg.h>
81da177e4SLinus Torvalds #include <stdlib.h>
91da177e4SLinus Torvalds #include <string.h>
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include "lkc.h"
12a77a05dcSMasahiro Yamada #include "internal.h"
131da177e4SLinus Torvalds
1457e6292dSArnaud Lacombe static const char nohelp_text[] = "There is no help available for this option.";
156bd5999dSCheng Renquan
161da177e4SLinus Torvalds struct menu rootmenu;
171da177e4SLinus Torvalds static struct menu **last_entry_ptr;
181da177e4SLinus Torvalds
191da177e4SLinus Torvalds struct file *file_list;
201da177e4SLinus Torvalds struct file *current_file;
211da177e4SLinus Torvalds
menu_warn(struct menu * menu,const char * fmt,...)2293449082SRoman Zippel void menu_warn(struct menu *menu, const char *fmt, ...)
231da177e4SLinus Torvalds {
241da177e4SLinus Torvalds va_list ap;
251da177e4SLinus Torvalds va_start(ap, fmt);
261da177e4SLinus Torvalds fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
271da177e4SLinus Torvalds vfprintf(stderr, fmt, ap);
281da177e4SLinus Torvalds fprintf(stderr, "\n");
291da177e4SLinus Torvalds va_end(ap);
301da177e4SLinus Torvalds }
311da177e4SLinus Torvalds
prop_warn(struct property * prop,const char * fmt,...)321da177e4SLinus Torvalds static void prop_warn(struct property *prop, const char *fmt, ...)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds va_list ap;
351da177e4SLinus Torvalds va_start(ap, fmt);
361da177e4SLinus Torvalds fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
371da177e4SLinus Torvalds vfprintf(stderr, fmt, ap);
381da177e4SLinus Torvalds fprintf(stderr, "\n");
391da177e4SLinus Torvalds va_end(ap);
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds
_menu_init(void)42692d97c3Snir.tzachar@gmail.com void _menu_init(void)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds current_entry = current_menu = &rootmenu;
451da177e4SLinus Torvalds last_entry_ptr = &rootmenu.list;
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds
menu_add_entry(struct symbol * sym)481da177e4SLinus Torvalds void menu_add_entry(struct symbol *sym)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds struct menu *menu;
511da177e4SLinus Torvalds
52177acf78SAlan Cox menu = xmalloc(sizeof(*menu));
531da177e4SLinus Torvalds memset(menu, 0, sizeof(*menu));
541da177e4SLinus Torvalds menu->sym = sym;
551da177e4SLinus Torvalds menu->parent = current_menu;
561da177e4SLinus Torvalds menu->file = current_file;
571da177e4SLinus Torvalds menu->lineno = zconf_lineno();
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds *last_entry_ptr = menu;
601da177e4SLinus Torvalds last_entry_ptr = &menu->next;
611da177e4SLinus Torvalds current_entry = menu;
6259e89e3dSSam Ravnborg if (sym)
6359e89e3dSSam Ravnborg menu_add_symbol(P_SYMBOL, sym, NULL);
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds
menu_add_menu(void)66a02f0570SRoman Zippel struct menu *menu_add_menu(void)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds last_entry_ptr = ¤t_entry->list;
69644a4b6cSMasahiro Yamada current_menu = current_entry;
70644a4b6cSMasahiro Yamada return current_menu;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds
menu_end_menu(void)731da177e4SLinus Torvalds void menu_end_menu(void)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds last_entry_ptr = ¤t_menu->next;
761da177e4SLinus Torvalds current_menu = current_menu->parent;
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds
799a826842SUlf Magnusson /*
809a826842SUlf Magnusson * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
819a826842SUlf Magnusson * without modules
829a826842SUlf Magnusson */
rewrite_m(struct expr * e)839a826842SUlf Magnusson static struct expr *rewrite_m(struct expr *e)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds if (!e)
861da177e4SLinus Torvalds return e;
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds switch (e->type) {
891da177e4SLinus Torvalds case E_NOT:
909a826842SUlf Magnusson e->left.expr = rewrite_m(e->left.expr);
911da177e4SLinus Torvalds break;
921da177e4SLinus Torvalds case E_OR:
931da177e4SLinus Torvalds case E_AND:
949a826842SUlf Magnusson e->left.expr = rewrite_m(e->left.expr);
959a826842SUlf Magnusson e->right.expr = rewrite_m(e->right.expr);
961da177e4SLinus Torvalds break;
971da177e4SLinus Torvalds case E_SYMBOL:
981da177e4SLinus Torvalds /* change 'm' into 'm' && MODULES */
991da177e4SLinus Torvalds if (e->left.sym == &symbol_mod)
1001da177e4SLinus Torvalds return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
1011da177e4SLinus Torvalds break;
1021da177e4SLinus Torvalds default:
1031da177e4SLinus Torvalds break;
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds return e;
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds
menu_add_dep(struct expr * dep)1081da177e4SLinus Torvalds void menu_add_dep(struct expr *dep)
1091da177e4SLinus Torvalds {
110f77850d3SUlf Magnusson current_entry->dep = expr_alloc_and(current_entry->dep, dep);
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds
menu_set_type(int type)1131da177e4SLinus Torvalds void menu_set_type(int type)
1141da177e4SLinus Torvalds {
1151da177e4SLinus Torvalds struct symbol *sym = current_entry->sym;
1161da177e4SLinus Torvalds
1171da177e4SLinus Torvalds if (sym->type == type)
1181da177e4SLinus Torvalds return;
1191da177e4SLinus Torvalds if (sym->type == S_UNKNOWN) {
1201da177e4SLinus Torvalds sym->type = type;
1211da177e4SLinus Torvalds return;
1221da177e4SLinus Torvalds }
12357540f1dSMartin Walch menu_warn(current_entry,
12457540f1dSMartin Walch "ignoring type redefinition of '%s' from '%s' to '%s'",
1251da177e4SLinus Torvalds sym->name ? sym->name : "<choice>",
1261da177e4SLinus Torvalds sym_type_name(sym->type), sym_type_name(type));
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds
menu_add_prop(enum prop_type type,struct expr * expr,struct expr * dep)1292ffeef61SMasahiro Yamada static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
1302ffeef61SMasahiro Yamada struct expr *dep)
1311da177e4SLinus Torvalds {
132adf7c5bdSMasahiro Yamada struct property *prop;
1331da177e4SLinus Torvalds
134adf7c5bdSMasahiro Yamada prop = xmalloc(sizeof(*prop));
135adf7c5bdSMasahiro Yamada memset(prop, 0, sizeof(*prop));
136adf7c5bdSMasahiro Yamada prop->type = type;
137adf7c5bdSMasahiro Yamada prop->file = current_file;
138adf7c5bdSMasahiro Yamada prop->lineno = zconf_lineno();
1391da177e4SLinus Torvalds prop->menu = current_entry;
1401da177e4SLinus Torvalds prop->expr = expr;
141f77850d3SUlf Magnusson prop->visible.expr = dep;
1421da177e4SLinus Torvalds
143adf7c5bdSMasahiro Yamada /* append property to the prop list of symbol */
144adf7c5bdSMasahiro Yamada if (current_entry->sym) {
145adf7c5bdSMasahiro Yamada struct property **propp;
146adf7c5bdSMasahiro Yamada
147adf7c5bdSMasahiro Yamada for (propp = ¤t_entry->sym->prop;
148adf7c5bdSMasahiro Yamada *propp;
149adf7c5bdSMasahiro Yamada propp = &(*propp)->next)
150adf7c5bdSMasahiro Yamada ;
151adf7c5bdSMasahiro Yamada *propp = prop;
152adf7c5bdSMasahiro Yamada }
153adf7c5bdSMasahiro Yamada
154024352ffSMasahiro Yamada return prop;
155024352ffSMasahiro Yamada }
156024352ffSMasahiro Yamada
menu_add_prompt(enum prop_type type,char * prompt,struct expr * dep)157024352ffSMasahiro Yamada struct property *menu_add_prompt(enum prop_type type, char *prompt,
158024352ffSMasahiro Yamada struct expr *dep)
159024352ffSMasahiro Yamada {
1602ffeef61SMasahiro Yamada struct property *prop = menu_add_prop(type, NULL, dep);
161024352ffSMasahiro Yamada
162f001f7f8SRoman Zippel if (isspace(*prompt)) {
163f001f7f8SRoman Zippel prop_warn(prop, "leading whitespace ignored");
164f001f7f8SRoman Zippel while (isspace(*prompt))
165f001f7f8SRoman Zippel prompt++;
166f001f7f8SRoman Zippel }
167f64048a2SMasahiro Yamada if (current_entry->prompt)
168f001f7f8SRoman Zippel prop_warn(prop, "prompt redefined");
1697ad12278SJan Beulich
1707ad12278SJan Beulich /* Apply all upper menus' visibilities to actual prompts. */
1717ad12278SJan Beulich if (type == P_PROMPT) {
1727ad12278SJan Beulich struct menu *menu = current_entry;
1737ad12278SJan Beulich
1747ad12278SJan Beulich while ((menu = menu->parent) != NULL) {
175e983b7b1SDirk Gouders struct expr *dup_expr;
176e983b7b1SDirk Gouders
1777ad12278SJan Beulich if (!menu->visibility)
1787ad12278SJan Beulich continue;
179e983b7b1SDirk Gouders /*
180024352ffSMasahiro Yamada * Do not add a reference to the menu's visibility
181024352ffSMasahiro Yamada * expression but use a copy of it. Otherwise the
182024352ffSMasahiro Yamada * expression reduction functions will modify
183024352ffSMasahiro Yamada * expressions that have multiple references which
184024352ffSMasahiro Yamada * can cause unwanted side effects.
185e983b7b1SDirk Gouders */
186e983b7b1SDirk Gouders dup_expr = expr_copy(menu->visibility);
187e983b7b1SDirk Gouders
188024352ffSMasahiro Yamada prop->visible.expr = expr_alloc_and(prop->visible.expr,
189e983b7b1SDirk Gouders dup_expr);
1907ad12278SJan Beulich }
1917ad12278SJan Beulich }
1927ad12278SJan Beulich
1931da177e4SLinus Torvalds current_entry->prompt = prop;
194f001f7f8SRoman Zippel prop->text = prompt;
1951da177e4SLinus Torvalds
1961da177e4SLinus Torvalds return prop;
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds
menu_add_visibility(struct expr * expr)19986e187ffSArnaud Lacombe void menu_add_visibility(struct expr *expr)
20086e187ffSArnaud Lacombe {
20186e187ffSArnaud Lacombe current_entry->visibility = expr_alloc_and(current_entry->visibility,
20286e187ffSArnaud Lacombe expr);
20386e187ffSArnaud Lacombe }
20486e187ffSArnaud Lacombe
menu_add_expr(enum prop_type type,struct expr * expr,struct expr * dep)2051da177e4SLinus Torvalds void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
2061da177e4SLinus Torvalds {
2072ffeef61SMasahiro Yamada menu_add_prop(type, expr, dep);
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds
menu_add_symbol(enum prop_type type,struct symbol * sym,struct expr * dep)2101da177e4SLinus Torvalds void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
2111da177e4SLinus Torvalds {
2122ffeef61SMasahiro Yamada menu_add_prop(type, expr_alloc_symbol(sym), dep);
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds
menu_validate_number(struct symbol * sym,struct symbol * sym2)215ab60bd0bSArnaud Lacombe static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
2164cf3cbe2SRoman Zippel {
2174cf3cbe2SRoman Zippel return sym2->type == S_INT || sym2->type == S_HEX ||
2184cf3cbe2SRoman Zippel (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
2194cf3cbe2SRoman Zippel }
2204cf3cbe2SRoman Zippel
sym_check_prop(struct symbol * sym)2214356f489STrevor Keith static void sym_check_prop(struct symbol *sym)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds struct property *prop;
2241da177e4SLinus Torvalds struct symbol *sym2;
225237e3ad0SNicolas Pitre char *use;
226237e3ad0SNicolas Pitre
2271da177e4SLinus Torvalds for (prop = sym->prop; prop; prop = prop->next) {
2281da177e4SLinus Torvalds switch (prop->type) {
2291da177e4SLinus Torvalds case P_DEFAULT:
2301da177e4SLinus Torvalds if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
2311da177e4SLinus Torvalds prop->expr->type != E_SYMBOL)
2321da177e4SLinus Torvalds prop_warn(prop,
2334280eae0SLi Zefan "default for config symbol '%s'"
2341da177e4SLinus Torvalds " must be a single symbol", sym->name);
235ab60bd0bSArnaud Lacombe if (prop->expr->type != E_SYMBOL)
236ab60bd0bSArnaud Lacombe break;
237ab60bd0bSArnaud Lacombe sym2 = prop_get_symbol(prop);
238ab60bd0bSArnaud Lacombe if (sym->type == S_HEX || sym->type == S_INT) {
239ab60bd0bSArnaud Lacombe if (!menu_validate_number(sym, sym2))
240ab60bd0bSArnaud Lacombe prop_warn(prop,
241ab60bd0bSArnaud Lacombe "'%s': number is invalid",
242ab60bd0bSArnaud Lacombe sym->name);
243ab60bd0bSArnaud Lacombe }
2442c37e084SUlf Magnusson if (sym_is_choice(sym)) {
2452c37e084SUlf Magnusson struct property *choice_prop =
2462c37e084SUlf Magnusson sym_get_choice_prop(sym2);
2472c37e084SUlf Magnusson
2482c37e084SUlf Magnusson if (!choice_prop ||
2492c37e084SUlf Magnusson prop_get_symbol(choice_prop) != sym)
2502c37e084SUlf Magnusson prop_warn(prop,
2512c37e084SUlf Magnusson "choice default symbol '%s' is not contained in the choice",
2522c37e084SUlf Magnusson sym2->name);
2532c37e084SUlf Magnusson }
2541da177e4SLinus Torvalds break;
2551da177e4SLinus Torvalds case P_SELECT:
256237e3ad0SNicolas Pitre case P_IMPLY:
257237e3ad0SNicolas Pitre use = prop->type == P_SELECT ? "select" : "imply";
2581da177e4SLinus Torvalds sym2 = prop_get_symbol(prop);
2591da177e4SLinus Torvalds if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
2601da177e4SLinus Torvalds prop_warn(prop,
261237e3ad0SNicolas Pitre "config symbol '%s' uses %s, but is "
262b92d804aSMasahiro Yamada "not bool or tristate", sym->name, use);
263603d4988SSam Ravnborg else if (sym2->type != S_UNKNOWN &&
264603d4988SSam Ravnborg sym2->type != S_BOOLEAN &&
265603d4988SSam Ravnborg sym2->type != S_TRISTATE)
2661da177e4SLinus Torvalds prop_warn(prop,
267237e3ad0SNicolas Pitre "'%s' has wrong type. '%s' only "
268b92d804aSMasahiro Yamada "accept arguments of bool and "
269237e3ad0SNicolas Pitre "tristate type", sym2->name, use);
2701da177e4SLinus Torvalds break;
2711da177e4SLinus Torvalds case P_RANGE:
2721da177e4SLinus Torvalds if (sym->type != S_INT && sym->type != S_HEX)
2731da177e4SLinus Torvalds prop_warn(prop, "range is only allowed "
2741da177e4SLinus Torvalds "for int or hex symbols");
275ab60bd0bSArnaud Lacombe if (!menu_validate_number(sym, prop->expr->left.sym) ||
276ab60bd0bSArnaud Lacombe !menu_validate_number(sym, prop->expr->right.sym))
2771da177e4SLinus Torvalds prop_warn(prop, "range is invalid");
2781da177e4SLinus Torvalds break;
2791da177e4SLinus Torvalds default:
2801da177e4SLinus Torvalds ;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds }
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds
menu_finalize(struct menu * parent)2851da177e4SLinus Torvalds void menu_finalize(struct menu *parent)
2861da177e4SLinus Torvalds {
2871da177e4SLinus Torvalds struct menu *menu, *last_menu;
2881da177e4SLinus Torvalds struct symbol *sym;
2891da177e4SLinus Torvalds struct property *prop;
2901da177e4SLinus Torvalds struct expr *parentdep, *basedep, *dep, *dep2, **ep;
2911da177e4SLinus Torvalds
2921da177e4SLinus Torvalds sym = parent->sym;
2931da177e4SLinus Torvalds if (parent->list) {
294fa8cedaeSUlf Magnusson /*
295fa8cedaeSUlf Magnusson * This menu node has children. We (recursively) process them
296fa8cedaeSUlf Magnusson * and propagate parent dependencies before moving on.
297fa8cedaeSUlf Magnusson */
298fa8cedaeSUlf Magnusson
2991da177e4SLinus Torvalds if (sym && sym_is_choice(sym)) {
3005a1aa8a1SRoman Zippel if (sym->type == S_UNKNOWN) {
3015a1aa8a1SRoman Zippel /* find the first choice value to find out choice type */
302a5bf3d89SJan Beulich current_entry = parent;
3035a1aa8a1SRoman Zippel for (menu = parent->list; menu; menu = menu->next) {
3045a1aa8a1SRoman Zippel if (menu->sym && menu->sym->type != S_UNKNOWN) {
305e8b8c977SLinus Torvalds menu_set_type(menu->sym->type);
306e8b8c977SLinus Torvalds break;
307e8b8c977SLinus Torvalds }
308e8b8c977SLinus Torvalds }
3095a1aa8a1SRoman Zippel }
3105a1aa8a1SRoman Zippel /* set the type of the remaining choice values */
3115a1aa8a1SRoman Zippel for (menu = parent->list; menu; menu = menu->next) {
3125a1aa8a1SRoman Zippel current_entry = menu;
3135a1aa8a1SRoman Zippel if (menu->sym && menu->sym->type == S_UNKNOWN)
3145a1aa8a1SRoman Zippel menu_set_type(sym->type);
3155a1aa8a1SRoman Zippel }
316d3465af6SUlf Magnusson
317d3465af6SUlf Magnusson /*
318d3465af6SUlf Magnusson * Use the choice itself as the parent dependency of
319d3465af6SUlf Magnusson * the contained items. This turns the mode of the
320d3465af6SUlf Magnusson * choice into an upper bound on the visibility of the
321d3465af6SUlf Magnusson * choice value symbols.
322d3465af6SUlf Magnusson */
3231da177e4SLinus Torvalds parentdep = expr_alloc_symbol(sym);
324de026ca9SMasahiro Yamada } else {
325de026ca9SMasahiro Yamada /* Menu node for 'menu', 'if' */
3261da177e4SLinus Torvalds parentdep = parent->dep;
327de026ca9SMasahiro Yamada }
3281da177e4SLinus Torvalds
329fa8cedaeSUlf Magnusson /* For each child menu node... */
3301da177e4SLinus Torvalds for (menu = parent->list; menu; menu = menu->next) {
331fa8cedaeSUlf Magnusson /*
332fa8cedaeSUlf Magnusson * Propagate parent dependencies to the child menu
333fa8cedaeSUlf Magnusson * node, also rewriting and simplifying expressions
334fa8cedaeSUlf Magnusson */
335f77850d3SUlf Magnusson basedep = rewrite_m(menu->dep);
336f77850d3SUlf Magnusson basedep = expr_transform(basedep);
337e8b8c977SLinus Torvalds basedep = expr_alloc_and(expr_copy(parentdep), basedep);
3381da177e4SLinus Torvalds basedep = expr_eliminate_dups(basedep);
3391da177e4SLinus Torvalds menu->dep = basedep;
340fa8cedaeSUlf Magnusson
3411da177e4SLinus Torvalds if (menu->sym)
342fa8cedaeSUlf Magnusson /*
343fa8cedaeSUlf Magnusson * Note: For symbols, all prompts are included
344fa8cedaeSUlf Magnusson * too in the symbol's own property list
345fa8cedaeSUlf Magnusson */
3461da177e4SLinus Torvalds prop = menu->sym->prop;
3471da177e4SLinus Torvalds else
348fa8cedaeSUlf Magnusson /*
349fa8cedaeSUlf Magnusson * For non-symbol menu nodes, we just need to
350fa8cedaeSUlf Magnusson * handle the prompt
351fa8cedaeSUlf Magnusson */
3521da177e4SLinus Torvalds prop = menu->prompt;
353fa8cedaeSUlf Magnusson
354fa8cedaeSUlf Magnusson /* For each property... */
3551da177e4SLinus Torvalds for (; prop; prop = prop->next) {
3561da177e4SLinus Torvalds if (prop->menu != menu)
357fa8cedaeSUlf Magnusson /*
358fa8cedaeSUlf Magnusson * Two possibilities:
359fa8cedaeSUlf Magnusson *
360fa8cedaeSUlf Magnusson * 1. The property lacks dependencies
361fa8cedaeSUlf Magnusson * and so isn't location-specific,
362fa8cedaeSUlf Magnusson * e.g. an 'option'
363fa8cedaeSUlf Magnusson *
364fa8cedaeSUlf Magnusson * 2. The property belongs to a symbol
365fa8cedaeSUlf Magnusson * defined in multiple locations and
366fa8cedaeSUlf Magnusson * is from some other location. It
367fa8cedaeSUlf Magnusson * will be handled there in that
368fa8cedaeSUlf Magnusson * case.
369fa8cedaeSUlf Magnusson *
370fa8cedaeSUlf Magnusson * Skip the property.
371fa8cedaeSUlf Magnusson */
3721da177e4SLinus Torvalds continue;
373fa8cedaeSUlf Magnusson
374fa8cedaeSUlf Magnusson /*
375fa8cedaeSUlf Magnusson * Propagate parent dependencies to the
376fa8cedaeSUlf Magnusson * property's condition, rewriting and
377fa8cedaeSUlf Magnusson * simplifying expressions at the same time
378fa8cedaeSUlf Magnusson */
379f77850d3SUlf Magnusson dep = rewrite_m(prop->visible.expr);
380f77850d3SUlf Magnusson dep = expr_transform(dep);
3811da177e4SLinus Torvalds dep = expr_alloc_and(expr_copy(basedep), dep);
3821da177e4SLinus Torvalds dep = expr_eliminate_dups(dep);
3831da177e4SLinus Torvalds prop->visible.expr = dep;
384fa8cedaeSUlf Magnusson
385fa8cedaeSUlf Magnusson /*
386fa8cedaeSUlf Magnusson * Handle selects and implies, which modify the
387fa8cedaeSUlf Magnusson * dependencies of the selected/implied symbol
388fa8cedaeSUlf Magnusson */
3891da177e4SLinus Torvalds if (prop->type == P_SELECT) {
3901da177e4SLinus Torvalds struct symbol *es = prop_get_symbol(prop);
3911da177e4SLinus Torvalds es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
3921da177e4SLinus Torvalds expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
393237e3ad0SNicolas Pitre } else if (prop->type == P_IMPLY) {
394237e3ad0SNicolas Pitre struct symbol *es = prop_get_symbol(prop);
395237e3ad0SNicolas Pitre es->implied.expr = expr_alloc_or(es->implied.expr,
396237e3ad0SNicolas Pitre expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds }
400fa8cedaeSUlf Magnusson
4017cf33f88SUlf Magnusson if (sym && sym_is_choice(sym))
4027cf33f88SUlf Magnusson expr_free(parentdep);
4037cf33f88SUlf Magnusson
404fa8cedaeSUlf Magnusson /*
405fa8cedaeSUlf Magnusson * Recursively process children in the same fashion before
406fa8cedaeSUlf Magnusson * moving on
407fa8cedaeSUlf Magnusson */
4081da177e4SLinus Torvalds for (menu = parent->list; menu; menu = menu->next)
4091da177e4SLinus Torvalds menu_finalize(menu);
4101da177e4SLinus Torvalds } else if (sym) {
41105cccce5SUlf Magnusson /*
41205cccce5SUlf Magnusson * Automatic submenu creation. If sym is a symbol and A, B, C,
41305cccce5SUlf Magnusson * ... are consecutive items (symbols, menus, ifs, etc.) that
41405cccce5SUlf Magnusson * all depend on sym, then the following menu structure is
41505cccce5SUlf Magnusson * created:
41605cccce5SUlf Magnusson *
41705cccce5SUlf Magnusson * sym
41805cccce5SUlf Magnusson * +-A
41905cccce5SUlf Magnusson * +-B
42005cccce5SUlf Magnusson * +-C
42105cccce5SUlf Magnusson * ...
42205cccce5SUlf Magnusson *
42305cccce5SUlf Magnusson * This also works recursively, giving the following structure
42405cccce5SUlf Magnusson * if A is a symbol and B depends on A:
42505cccce5SUlf Magnusson *
42605cccce5SUlf Magnusson * sym
42705cccce5SUlf Magnusson * +-A
42805cccce5SUlf Magnusson * | +-B
42905cccce5SUlf Magnusson * +-C
43005cccce5SUlf Magnusson * ...
43105cccce5SUlf Magnusson */
43205cccce5SUlf Magnusson
4331da177e4SLinus Torvalds basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
4341da177e4SLinus Torvalds basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
4351da177e4SLinus Torvalds basedep = expr_eliminate_dups(expr_transform(basedep));
43605cccce5SUlf Magnusson
43705cccce5SUlf Magnusson /* Examine consecutive elements after sym */
4381da177e4SLinus Torvalds last_menu = NULL;
4391da177e4SLinus Torvalds for (menu = parent->next; menu; menu = menu->next) {
4401da177e4SLinus Torvalds dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
4411da177e4SLinus Torvalds if (!expr_contains_symbol(dep, sym))
44205cccce5SUlf Magnusson /* No dependency, quit */
4431da177e4SLinus Torvalds break;
4441da177e4SLinus Torvalds if (expr_depends_symbol(dep, sym))
44505cccce5SUlf Magnusson /* Absolute dependency, put in submenu */
4461da177e4SLinus Torvalds goto next;
44705cccce5SUlf Magnusson
44805cccce5SUlf Magnusson /*
44905cccce5SUlf Magnusson * Also consider it a dependency on sym if our
45005cccce5SUlf Magnusson * dependencies contain sym and are a "superset" of
45105cccce5SUlf Magnusson * sym's dependencies, e.g. '(sym || Q) && R' when sym
45205cccce5SUlf Magnusson * depends on R.
45305cccce5SUlf Magnusson *
45405cccce5SUlf Magnusson * Note that 'R' might be from an enclosing menu or if,
45505cccce5SUlf Magnusson * making this a more common case than it might seem.
45605cccce5SUlf Magnusson */
4571da177e4SLinus Torvalds dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
4581da177e4SLinus Torvalds dep = expr_eliminate_dups(expr_transform(dep));
4591da177e4SLinus Torvalds dep2 = expr_copy(basedep);
4601da177e4SLinus Torvalds expr_eliminate_eq(&dep, &dep2);
4611da177e4SLinus Torvalds expr_free(dep);
4621da177e4SLinus Torvalds if (!expr_is_yes(dep2)) {
46305cccce5SUlf Magnusson /* Not superset, quit */
4641da177e4SLinus Torvalds expr_free(dep2);
4651da177e4SLinus Torvalds break;
4661da177e4SLinus Torvalds }
46705cccce5SUlf Magnusson /* Superset, put in submenu */
4681da177e4SLinus Torvalds expr_free(dep2);
4691da177e4SLinus Torvalds next:
4701da177e4SLinus Torvalds menu_finalize(menu);
4711da177e4SLinus Torvalds menu->parent = parent;
4721da177e4SLinus Torvalds last_menu = menu;
4731da177e4SLinus Torvalds }
474ae7440efSUlf Magnusson expr_free(basedep);
4751da177e4SLinus Torvalds if (last_menu) {
4761da177e4SLinus Torvalds parent->list = parent->next;
4771da177e4SLinus Torvalds parent->next = last_menu->next;
4781da177e4SLinus Torvalds last_menu->next = NULL;
4791da177e4SLinus Torvalds }
480ff5ff606SArnaud Lacombe
481ec6452a5SArnaud Lacombe sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
4821da177e4SLinus Torvalds }
4831da177e4SLinus Torvalds for (menu = parent->list; menu; menu = menu->next) {
4845a1aa8a1SRoman Zippel if (sym && sym_is_choice(sym) &&
4855a1aa8a1SRoman Zippel menu->sym && !sym_is_choice_value(menu->sym)) {
4865a1aa8a1SRoman Zippel current_entry = menu;
4871da177e4SLinus Torvalds menu->sym->flags |= SYMBOL_CHOICEVAL;
4881da177e4SLinus Torvalds if (!menu->prompt)
4891da177e4SLinus Torvalds menu_warn(menu, "choice value must have a prompt");
4901da177e4SLinus Torvalds for (prop = menu->sym->prop; prop; prop = prop->next) {
4911da177e4SLinus Torvalds if (prop->type == P_DEFAULT)
4921da177e4SLinus Torvalds prop_warn(prop, "defaults for choice "
4931da177e4SLinus Torvalds "values not supported");
4945a1aa8a1SRoman Zippel if (prop->menu == menu)
4955a1aa8a1SRoman Zippel continue;
4965a1aa8a1SRoman Zippel if (prop->type == P_PROMPT &&
4975a1aa8a1SRoman Zippel prop->menu->parent->sym != sym)
4985a1aa8a1SRoman Zippel prop_warn(prop, "choice value used outside its choice group");
4991da177e4SLinus Torvalds }
500f5eaa323SJan Beulich /* Non-tristate choice values of tristate choices must
501f5eaa323SJan Beulich * depend on the choice being set to Y. The choice
502f5eaa323SJan Beulich * values' dependencies were propagated to their
503f5eaa323SJan Beulich * properties above, so the change here must be re-
5045a1aa8a1SRoman Zippel * propagated.
5055a1aa8a1SRoman Zippel */
506f5eaa323SJan Beulich if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
507f5eaa323SJan Beulich basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
5085a1aa8a1SRoman Zippel menu->dep = expr_alloc_and(basedep, menu->dep);
509f5eaa323SJan Beulich for (prop = menu->sym->prop; prop; prop = prop->next) {
510f5eaa323SJan Beulich if (prop->menu != menu)
511f5eaa323SJan Beulich continue;
5125a1aa8a1SRoman Zippel prop->visible.expr = expr_alloc_and(expr_copy(basedep),
513f5eaa323SJan Beulich prop->visible.expr);
514f5eaa323SJan Beulich }
515f5eaa323SJan Beulich }
5161da177e4SLinus Torvalds menu_add_symbol(P_CHOICE, sym, NULL);
5171da177e4SLinus Torvalds prop = sym_get_choice_prop(sym);
5181da177e4SLinus Torvalds for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
5191da177e4SLinus Torvalds ;
5207a962923SRoman Zippel *ep = expr_alloc_one(E_LIST, NULL);
5211da177e4SLinus Torvalds (*ep)->right.sym = menu->sym;
5221da177e4SLinus Torvalds }
5239d1a9e8bSUlf Magnusson
5249d1a9e8bSUlf Magnusson /*
5259d1a9e8bSUlf Magnusson * This code serves two purposes:
5269d1a9e8bSUlf Magnusson *
5279d1a9e8bSUlf Magnusson * (1) Flattening 'if' blocks, which do not specify a submenu
5289d1a9e8bSUlf Magnusson * and only add dependencies.
5299d1a9e8bSUlf Magnusson *
5309d1a9e8bSUlf Magnusson * (Automatic submenu creation might still create a submenu
5319d1a9e8bSUlf Magnusson * from an 'if' before this code runs.)
5329d1a9e8bSUlf Magnusson *
5339d1a9e8bSUlf Magnusson * (2) "Undoing" any automatic submenus created earlier below
5349d1a9e8bSUlf Magnusson * promptless symbols.
5359d1a9e8bSUlf Magnusson *
5369d1a9e8bSUlf Magnusson * Before:
5379d1a9e8bSUlf Magnusson *
5389d1a9e8bSUlf Magnusson * A
5399d1a9e8bSUlf Magnusson * if ... (or promptless symbol)
5409d1a9e8bSUlf Magnusson * +-B
5419d1a9e8bSUlf Magnusson * +-C
5429d1a9e8bSUlf Magnusson * D
5439d1a9e8bSUlf Magnusson *
5449d1a9e8bSUlf Magnusson * After:
5459d1a9e8bSUlf Magnusson *
5469d1a9e8bSUlf Magnusson * A
5479d1a9e8bSUlf Magnusson * if ... (or promptless symbol)
5489d1a9e8bSUlf Magnusson * B
5499d1a9e8bSUlf Magnusson * C
5509d1a9e8bSUlf Magnusson * D
5519d1a9e8bSUlf Magnusson */
5521da177e4SLinus Torvalds if (menu->list && (!menu->prompt || !menu->prompt->text)) {
5531da177e4SLinus Torvalds for (last_menu = menu->list; ; last_menu = last_menu->next) {
5541da177e4SLinus Torvalds last_menu->parent = parent;
5551da177e4SLinus Torvalds if (!last_menu->next)
5561da177e4SLinus Torvalds break;
5571da177e4SLinus Torvalds }
5581da177e4SLinus Torvalds last_menu->next = menu->next;
5591da177e4SLinus Torvalds menu->next = menu->list;
5601da177e4SLinus Torvalds menu->list = NULL;
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds }
5631da177e4SLinus Torvalds
5641da177e4SLinus Torvalds if (sym && !(sym->flags & SYMBOL_WARNED)) {
5651da177e4SLinus Torvalds if (sym->type == S_UNKNOWN)
566f001f7f8SRoman Zippel menu_warn(parent, "config symbol defined without type");
5671da177e4SLinus Torvalds
5681da177e4SLinus Torvalds if (sym_is_choice(sym) && !parent->prompt)
569f001f7f8SRoman Zippel menu_warn(parent, "choice must have a prompt");
5701da177e4SLinus Torvalds
5711da177e4SLinus Torvalds /* Check properties connected to this symbol */
5721da177e4SLinus Torvalds sym_check_prop(sym);
5731da177e4SLinus Torvalds sym->flags |= SYMBOL_WARNED;
5741da177e4SLinus Torvalds }
5751da177e4SLinus Torvalds
5763e41ba05SUlf Magnusson /*
5773e41ba05SUlf Magnusson * For non-optional choices, add a reverse dependency (corresponding to
5783e41ba05SUlf Magnusson * a select) of '<visibility> && m'. This prevents the user from
5793e41ba05SUlf Magnusson * setting the choice mode to 'n' when the choice is visible.
5803e41ba05SUlf Magnusson *
5813e41ba05SUlf Magnusson * This would also work for non-choice symbols, but only non-optional
5823e41ba05SUlf Magnusson * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented
5833e41ba05SUlf Magnusson * as a type of symbol.
5843e41ba05SUlf Magnusson */
5851da177e4SLinus Torvalds if (sym && !sym_is_optional(sym) && parent->prompt) {
5861da177e4SLinus Torvalds sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
5871da177e4SLinus Torvalds expr_alloc_and(parent->prompt->visible.expr,
5881da177e4SLinus Torvalds expr_alloc_symbol(&symbol_mod)));
5891da177e4SLinus Torvalds }
5901da177e4SLinus Torvalds }
5911da177e4SLinus Torvalds
menu_has_prompt(struct menu * menu)59222c7eca6SLi Zefan bool menu_has_prompt(struct menu *menu)
59322c7eca6SLi Zefan {
59422c7eca6SLi Zefan if (!menu->prompt)
59522c7eca6SLi Zefan return false;
59622c7eca6SLi Zefan return true;
59722c7eca6SLi Zefan }
59822c7eca6SLi Zefan
5991278ebdbSDirk Gouders /*
6001278ebdbSDirk Gouders * Determine if a menu is empty.
6011278ebdbSDirk Gouders * A menu is considered empty if it contains no or only
6021278ebdbSDirk Gouders * invisible entries.
6031278ebdbSDirk Gouders */
menu_is_empty(struct menu * menu)6041278ebdbSDirk Gouders bool menu_is_empty(struct menu *menu)
6051278ebdbSDirk Gouders {
6061278ebdbSDirk Gouders struct menu *child;
6071278ebdbSDirk Gouders
6081278ebdbSDirk Gouders for (child = menu->list; child; child = child->next) {
6091278ebdbSDirk Gouders if (menu_is_visible(child))
6101278ebdbSDirk Gouders return(false);
6111278ebdbSDirk Gouders }
6121278ebdbSDirk Gouders return(true);
6131278ebdbSDirk Gouders }
6141278ebdbSDirk Gouders
menu_is_visible(struct menu * menu)6151da177e4SLinus Torvalds bool menu_is_visible(struct menu *menu)
6161da177e4SLinus Torvalds {
6171da177e4SLinus Torvalds struct menu *child;
6181da177e4SLinus Torvalds struct symbol *sym;
6191da177e4SLinus Torvalds tristate visible;
6201da177e4SLinus Torvalds
6211da177e4SLinus Torvalds if (!menu->prompt)
6221da177e4SLinus Torvalds return false;
62322c7eca6SLi Zefan
62486e187ffSArnaud Lacombe if (menu->visibility) {
62586e187ffSArnaud Lacombe if (expr_calc_value(menu->visibility) == no)
626aab24a89SVegard Nossum return false;
62786e187ffSArnaud Lacombe }
62886e187ffSArnaud Lacombe
6291da177e4SLinus Torvalds sym = menu->sym;
6301da177e4SLinus Torvalds if (sym) {
6311da177e4SLinus Torvalds sym_calc_value(sym);
6321da177e4SLinus Torvalds visible = menu->prompt->visible.tri;
6331da177e4SLinus Torvalds } else
6341da177e4SLinus Torvalds visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
6351da177e4SLinus Torvalds
6361da177e4SLinus Torvalds if (visible != no)
6371da177e4SLinus Torvalds return true;
63822c7eca6SLi Zefan
6391da177e4SLinus Torvalds if (!sym || sym_get_tristate_value(menu->sym) == no)
6401da177e4SLinus Torvalds return false;
6411da177e4SLinus Torvalds
6423fb9acb3SLi Zefan for (child = menu->list; child; child = child->next) {
6433fb9acb3SLi Zefan if (menu_is_visible(child)) {
6443fb9acb3SLi Zefan if (sym)
6453fb9acb3SLi Zefan sym->flags |= SYMBOL_DEF_USER;
6461da177e4SLinus Torvalds return true;
6473fb9acb3SLi Zefan }
6483fb9acb3SLi Zefan }
64922c7eca6SLi Zefan
6501da177e4SLinus Torvalds return false;
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds
menu_get_prompt(struct menu * menu)6531da177e4SLinus Torvalds const char *menu_get_prompt(struct menu *menu)
6541da177e4SLinus Torvalds {
6551da177e4SLinus Torvalds if (menu->prompt)
65601771b0fSEGRY Gabor return menu->prompt->text;
6571da177e4SLinus Torvalds else if (menu->sym)
65801771b0fSEGRY Gabor return menu->sym->name;
6591da177e4SLinus Torvalds return NULL;
6601da177e4SLinus Torvalds }
6611da177e4SLinus Torvalds
menu_get_parent_menu(struct menu * menu)6621da177e4SLinus Torvalds struct menu *menu_get_parent_menu(struct menu *menu)
6631da177e4SLinus Torvalds {
6641da177e4SLinus Torvalds enum prop_type type;
6651da177e4SLinus Torvalds
6661da177e4SLinus Torvalds for (; menu != &rootmenu; menu = menu->parent) {
6671da177e4SLinus Torvalds type = menu->prompt ? menu->prompt->type : 0;
6681da177e4SLinus Torvalds if (type == P_MENU)
6691da177e4SLinus Torvalds break;
6701da177e4SLinus Torvalds }
6711da177e4SLinus Torvalds return menu;
6721da177e4SLinus Torvalds }
6731da177e4SLinus Torvalds
menu_has_help(struct menu * menu)67403d29122SSam Ravnborg bool menu_has_help(struct menu *menu)
67503d29122SSam Ravnborg {
67603d29122SSam Ravnborg return menu->help != NULL;
67703d29122SSam Ravnborg }
67803d29122SSam Ravnborg
menu_get_help(struct menu * menu)67903d29122SSam Ravnborg const char *menu_get_help(struct menu *menu)
68003d29122SSam Ravnborg {
68103d29122SSam Ravnborg if (menu->help)
68203d29122SSam Ravnborg return menu->help;
68303d29122SSam Ravnborg else
68403d29122SSam Ravnborg return "";
68503d29122SSam Ravnborg }
6866bd5999dSCheng Renquan
get_def_str(struct gstr * r,struct menu * menu)687edda15f2SThomas Hebb static void get_def_str(struct gstr *r, struct menu *menu)
688edda15f2SThomas Hebb {
689edda15f2SThomas Hebb str_printf(r, "Defined at %s:%d\n",
690edda15f2SThomas Hebb menu->file->name, menu->lineno);
691edda15f2SThomas Hebb }
692edda15f2SThomas Hebb
get_dep_str(struct gstr * r,struct expr * expr,const char * prefix)693edda15f2SThomas Hebb static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
694edda15f2SThomas Hebb {
695edda15f2SThomas Hebb if (!expr_is_yes(expr)) {
696edda15f2SThomas Hebb str_append(r, prefix);
697edda15f2SThomas Hebb expr_gstr_print(expr, r);
698edda15f2SThomas Hebb str_append(r, "\n");
699edda15f2SThomas Hebb }
700edda15f2SThomas Hebb }
701edda15f2SThomas Hebb
get_jump_key_char(void)702*e14f1242SMasahiro Yamada int __attribute__((weak)) get_jump_key_char(void)
703*e14f1242SMasahiro Yamada {
704*e14f1242SMasahiro Yamada return -1;
705*e14f1242SMasahiro Yamada }
706*e14f1242SMasahiro Yamada
get_prompt_str(struct gstr * r,struct property * prop,struct list_head * head)70795ac9b3bSBenjamin Poirier static void get_prompt_str(struct gstr *r, struct property *prop,
708bad9955dSBenjamin Poirier struct list_head *head)
7096bd5999dSCheng Renquan {
7106bd5999dSCheng Renquan int i, j;
7115e609addSBenjamin Poirier struct menu *submenu[8], *menu, *location = NULL;
7122d560306SPeter Kümmel struct jump_key *jump = NULL;
7136bd5999dSCheng Renquan
714694c49a7SSam Ravnborg str_printf(r, " Prompt: %s\n", prop->text);
715edda15f2SThomas Hebb
716edda15f2SThomas Hebb get_dep_str(r, prop->menu->dep, " Depends on: ");
7173460d0bcSThomas Hebb /*
7183460d0bcSThomas Hebb * Most prompts in Linux have visibility that exactly matches their
7193460d0bcSThomas Hebb * dependencies. For these, we print only the dependencies to improve
7203460d0bcSThomas Hebb * readability. However, prompts with inline "if" expressions and
7213460d0bcSThomas Hebb * prompts with a parent that has a "visible if" expression have
7223460d0bcSThomas Hebb * differing dependencies and visibility. In these rare cases, we
7233460d0bcSThomas Hebb * print both.
7243460d0bcSThomas Hebb */
7253460d0bcSThomas Hebb if (!expr_eq(prop->menu->dep, prop->visible.expr))
7263460d0bcSThomas Hebb get_dep_str(r, prop->visible.expr, " Visible if: ");
7273460d0bcSThomas Hebb
7287a263a04SMasahiro Yamada menu = prop->menu;
7297a263a04SMasahiro Yamada for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
7306bd5999dSCheng Renquan submenu[i++] = menu;
7311791360cSMasahiro Yamada if (location == NULL && menu_is_visible(menu))
7325e609addSBenjamin Poirier location = menu;
7335e609addSBenjamin Poirier }
73495ac9b3bSBenjamin Poirier if (head && location) {
735177acf78SAlan Cox jump = xmalloc(sizeof(struct jump_key));
73695ac9b3bSBenjamin Poirier jump->target = location;
737bad9955dSBenjamin Poirier list_add_tail(&jump->entries, head);
73895ac9b3bSBenjamin Poirier }
7395e609addSBenjamin Poirier
740694c49a7SSam Ravnborg str_printf(r, " Location:\n");
741*e14f1242SMasahiro Yamada for (j = 0; --i >= 0; j++) {
742*e14f1242SMasahiro Yamada int jk = -1;
743*e14f1242SMasahiro Yamada int indent = 2 * j + 4;
744*e14f1242SMasahiro Yamada
7456bd5999dSCheng Renquan menu = submenu[i];
746*e14f1242SMasahiro Yamada if (jump && menu == location) {
747503c8230SMartin Walch jump->offset = strlen(r->s);
748*e14f1242SMasahiro Yamada jk = get_jump_key_char();
749*e14f1242SMasahiro Yamada }
750*e14f1242SMasahiro Yamada
751*e14f1242SMasahiro Yamada if (jk >= 0) {
752*e14f1242SMasahiro Yamada str_printf(r, "(%c)", jk);
753*e14f1242SMasahiro Yamada indent -= 3;
754*e14f1242SMasahiro Yamada }
755*e14f1242SMasahiro Yamada
756*e14f1242SMasahiro Yamada str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu));
7576bd5999dSCheng Renquan if (menu->sym) {
7586bd5999dSCheng Renquan str_printf(r, " (%s [=%s])", menu->sym->name ?
759694c49a7SSam Ravnborg menu->sym->name : "<choice>",
7606bd5999dSCheng Renquan sym_get_string_value(menu->sym));
7616bd5999dSCheng Renquan }
7626bd5999dSCheng Renquan str_append(r, "\n");
7636bd5999dSCheng Renquan }
7646bd5999dSCheng Renquan }
7656bd5999dSCheng Renquan
get_symbol_props_str(struct gstr * r,struct symbol * sym,enum prop_type tok,const char * prefix)766237e3ad0SNicolas Pitre static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
767237e3ad0SNicolas Pitre enum prop_type tok, const char *prefix)
768237e3ad0SNicolas Pitre {
769237e3ad0SNicolas Pitre bool hit = false;
770237e3ad0SNicolas Pitre struct property *prop;
771237e3ad0SNicolas Pitre
772237e3ad0SNicolas Pitre for_all_properties(sym, prop, tok) {
773237e3ad0SNicolas Pitre if (!hit) {
774237e3ad0SNicolas Pitre str_append(r, prefix);
775237e3ad0SNicolas Pitre hit = true;
776237e3ad0SNicolas Pitre } else
777237e3ad0SNicolas Pitre str_printf(r, " && ");
778237e3ad0SNicolas Pitre expr_gstr_print(prop->expr, r);
779237e3ad0SNicolas Pitre }
780237e3ad0SNicolas Pitre if (hit)
781237e3ad0SNicolas Pitre str_append(r, "\n");
782237e3ad0SNicolas Pitre }
783237e3ad0SNicolas Pitre
784bcdedcc1SWengmeiling /*
78595ac9b3bSBenjamin Poirier * head is optional and may be NULL
7865e609addSBenjamin Poirier */
get_symbol_str(struct gstr * r,struct symbol * sym,struct list_head * head)787ad8d40cdSMichal Marek static void get_symbol_str(struct gstr *r, struct symbol *sym,
788bad9955dSBenjamin Poirier struct list_head *head)
7896bd5999dSCheng Renquan {
7906bd5999dSCheng Renquan struct property *prop;
7916bd5999dSCheng Renquan
792b040b44cSLi Zefan if (sym && sym->name) {
7936bd5999dSCheng Renquan str_printf(r, "Symbol: %s [=%s]\n", sym->name,
7946bd5999dSCheng Renquan sym_get_string_value(sym));
795b040b44cSLi Zefan str_printf(r, "Type : %s\n", sym_type_name(sym->type));
79670ed0747SLi Zefan if (sym->type == S_INT || sym->type == S_HEX) {
79770ed0747SLi Zefan prop = sym_get_range_prop(sym);
79870ed0747SLi Zefan if (prop) {
79970ed0747SLi Zefan str_printf(r, "Range : ");
80070ed0747SLi Zefan expr_gstr_print(prop->expr, r);
80170ed0747SLi Zefan str_append(r, "\n");
80270ed0747SLi Zefan }
80370ed0747SLi Zefan }
804b040b44cSLi Zefan }
805383da76fSLi Zefan
806edda15f2SThomas Hebb /* Print the definitions with prompts before the ones without */
807edda15f2SThomas Hebb for_all_properties(sym, prop, P_SYMBOL) {
808edda15f2SThomas Hebb if (prop->menu->prompt) {
809edda15f2SThomas Hebb get_def_str(r, prop->menu);
810edda15f2SThomas Hebb get_prompt_str(r, prop->menu->prompt, head);
811edda15f2SThomas Hebb }
812edda15f2SThomas Hebb }
813edda15f2SThomas Hebb
814edda15f2SThomas Hebb for_all_properties(sym, prop, P_SYMBOL) {
815edda15f2SThomas Hebb if (!prop->menu->prompt) {
816edda15f2SThomas Hebb get_def_str(r, prop->menu);
817edda15f2SThomas Hebb get_dep_str(r, prop->menu->dep, " Depends on: ");
818bcdedcc1SWengmeiling }
819383da76fSLi Zefan }
820383da76fSLi Zefan
821694c49a7SSam Ravnborg get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
8226bd5999dSCheng Renquan if (sym->rev_dep.expr) {
823d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n");
824d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n");
825d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n");
8266bd5999dSCheng Renquan }
827237e3ad0SNicolas Pitre
828694c49a7SSam Ravnborg get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
829237e3ad0SNicolas Pitre if (sym->implied.expr) {
830d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n");
831d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n");
832d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n");
833237e3ad0SNicolas Pitre }
834237e3ad0SNicolas Pitre
8356bd5999dSCheng Renquan str_append(r, "\n\n");
8366bd5999dSCheng Renquan }
8376bd5999dSCheng Renquan
get_relations_str(struct symbol ** sym_arr,struct list_head * head)838bad9955dSBenjamin Poirier struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
839692d97c3Snir.tzachar@gmail.com {
840692d97c3Snir.tzachar@gmail.com struct symbol *sym;
841692d97c3Snir.tzachar@gmail.com struct gstr res = str_new();
84295ac9b3bSBenjamin Poirier int i;
843692d97c3Snir.tzachar@gmail.com
844692d97c3Snir.tzachar@gmail.com for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
84595ac9b3bSBenjamin Poirier get_symbol_str(&res, sym, head);
846692d97c3Snir.tzachar@gmail.com if (!i)
847694c49a7SSam Ravnborg str_append(&res, "No matches found.\n");
848692d97c3Snir.tzachar@gmail.com return res;
849692d97c3Snir.tzachar@gmail.com }
850692d97c3Snir.tzachar@gmail.com
851692d97c3Snir.tzachar@gmail.com
menu_get_ext_help(struct menu * menu,struct gstr * help)8526bd5999dSCheng Renquan void menu_get_ext_help(struct menu *menu, struct gstr *help)
8536bd5999dSCheng Renquan {
8546bd5999dSCheng Renquan struct symbol *sym = menu->sym;
85557e6292dSArnaud Lacombe const char *help_text = nohelp_text;
8566bd5999dSCheng Renquan
8576bd5999dSCheng Renquan if (menu_has_help(menu)) {
8583f198dfeSSrinivas Kandagatla if (sym->name)
859ffb5957bSArnaud Lacombe str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
86057e6292dSArnaud Lacombe help_text = menu_get_help(menu);
8616bd5999dSCheng Renquan }
862694c49a7SSam Ravnborg str_printf(help, "%s\n", help_text);
8634779105eSCheng Renquan if (sym)
86495ac9b3bSBenjamin Poirier get_symbol_str(help, sym, NULL);
8656bd5999dSCheng Renquan }
866