10c874100SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) 2002 Roman Zippel <[email protected]>
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
11fbaf242cSMasahiro Yamada #include <list.h>
12a9d83d74SMasahiro Yamada #include <xalloc.h>
131da177e4SLinus Torvalds #include "lkc.h"
14a77a05dcSMasahiro Yamada #include "internal.h"
151da177e4SLinus Torvalds
1657e6292dSArnaud Lacombe static const char nohelp_text[] = "There is no help available for this option.";
176bd5999dSCheng Renquan
181da177e4SLinus Torvalds struct menu rootmenu;
191da177e4SLinus Torvalds static struct menu **last_entry_ptr;
201da177e4SLinus Torvalds
217284b4fbSMasahiro Yamada /**
227284b4fbSMasahiro Yamada * menu_next - return the next menu entry with depth-first traversal
237284b4fbSMasahiro Yamada * @menu: pointer to the current menu
247284b4fbSMasahiro Yamada * @root: root of the sub-tree to traverse. If NULL is given, the traveral
257284b4fbSMasahiro Yamada * continues until it reaches the end of the entire menu tree.
267284b4fbSMasahiro Yamada * return: the menu to visit next, or NULL when it reaches the end.
277284b4fbSMasahiro Yamada */
menu_next(struct menu * menu,struct menu * root)287284b4fbSMasahiro Yamada struct menu *menu_next(struct menu *menu, struct menu *root)
297284b4fbSMasahiro Yamada {
307284b4fbSMasahiro Yamada if (menu->list)
317284b4fbSMasahiro Yamada return menu->list;
327284b4fbSMasahiro Yamada
337284b4fbSMasahiro Yamada while (menu != root && !menu->next)
347284b4fbSMasahiro Yamada menu = menu->parent;
357284b4fbSMasahiro Yamada
367284b4fbSMasahiro Yamada if (menu == root)
377284b4fbSMasahiro Yamada return NULL;
387284b4fbSMasahiro Yamada
397284b4fbSMasahiro Yamada return menu->next;
407284b4fbSMasahiro Yamada }
417284b4fbSMasahiro Yamada
menu_warn(const struct menu * menu,const char * fmt,...)426425e3b2SMasahiro Yamada void menu_warn(const struct menu *menu, const char *fmt, ...)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds va_list ap;
451da177e4SLinus Torvalds va_start(ap, fmt);
4640bab83aSMasahiro Yamada fprintf(stderr, "%s:%d:warning: ", menu->filename, menu->lineno);
471da177e4SLinus Torvalds vfprintf(stderr, fmt, ap);
481da177e4SLinus Torvalds fprintf(stderr, "\n");
491da177e4SLinus Torvalds va_end(ap);
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds
prop_warn(const struct property * prop,const char * fmt,...)526425e3b2SMasahiro Yamada static void prop_warn(const struct property *prop, const char *fmt, ...)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds va_list ap;
551da177e4SLinus Torvalds va_start(ap, fmt);
561a90b0cdSMasahiro Yamada fprintf(stderr, "%s:%d:warning: ", prop->filename, prop->lineno);
571da177e4SLinus Torvalds vfprintf(stderr, fmt, ap);
581da177e4SLinus Torvalds fprintf(stderr, "\n");
591da177e4SLinus Torvalds va_end(ap);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds
_menu_init(void)62692d97c3S[email protected] void _menu_init(void)
631da177e4SLinus Torvalds {
641da177e4SLinus Torvalds current_entry = current_menu = &rootmenu;
651da177e4SLinus Torvalds last_entry_ptr = &rootmenu.list;
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds
menu_add_entry(struct symbol * sym)681da177e4SLinus Torvalds void menu_add_entry(struct symbol *sym)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds struct menu *menu;
711da177e4SLinus Torvalds
72177acf78SAlan Cox menu = xmalloc(sizeof(*menu));
731da177e4SLinus Torvalds memset(menu, 0, sizeof(*menu));
741da177e4SLinus Torvalds menu->sym = sym;
751da177e4SLinus Torvalds menu->parent = current_menu;
7640bab83aSMasahiro Yamada menu->filename = cur_filename;
771d7c4f10SMasahiro Yamada menu->lineno = cur_lineno;
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds *last_entry_ptr = menu;
801da177e4SLinus Torvalds last_entry_ptr = &menu->next;
811da177e4SLinus Torvalds current_entry = menu;
825e6cc7e3SMasahiro Yamada if (sym)
83e0492219SMasahiro Yamada list_add_tail(&menu->link, &sym->menus);
84e0492219SMasahiro Yamada }
851da177e4SLinus Torvalds
menu_add_menu(void)86a02f0570SRoman Zippel struct menu *menu_add_menu(void)
871da177e4SLinus Torvalds {
881da177e4SLinus Torvalds last_entry_ptr = ¤t_entry->list;
89644a4b6cSMasahiro Yamada current_menu = current_entry;
90644a4b6cSMasahiro Yamada return current_menu;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds
menu_end_menu(void)931da177e4SLinus Torvalds void menu_end_menu(void)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds last_entry_ptr = ¤t_menu->next;
961da177e4SLinus Torvalds current_menu = current_menu->parent;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds
999a826842SUlf Magnusson /*
1009a826842SUlf Magnusson * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
1019a826842SUlf Magnusson * without modules
1029a826842SUlf Magnusson */
rewrite_m(struct expr * e)1039a826842SUlf Magnusson static struct expr *rewrite_m(struct expr *e)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds if (!e)
1061da177e4SLinus Torvalds return e;
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds switch (e->type) {
1091da177e4SLinus Torvalds case E_NOT:
110f93d6bfbSMasahiro Yamada e = expr_alloc_one(E_NOT, rewrite_m(e->left.expr));
1111da177e4SLinus Torvalds break;
1121da177e4SLinus Torvalds case E_OR:
1131da177e4SLinus Torvalds case E_AND:
114f93d6bfbSMasahiro Yamada e = expr_alloc_two(e->type,
115f93d6bfbSMasahiro Yamada rewrite_m(e->left.expr),
116f93d6bfbSMasahiro Yamada rewrite_m(e->right.expr));
1171da177e4SLinus Torvalds break;
1181da177e4SLinus Torvalds case E_SYMBOL:
1191da177e4SLinus Torvalds /* change 'm' into 'm' && MODULES */
1201da177e4SLinus Torvalds if (e->left.sym == &symbol_mod)
1211da177e4SLinus Torvalds return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
1221da177e4SLinus Torvalds break;
1231da177e4SLinus Torvalds default:
1241da177e4SLinus Torvalds break;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds return e;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds
menu_add_dep(struct expr * dep)1291da177e4SLinus Torvalds void menu_add_dep(struct expr *dep)
1301da177e4SLinus Torvalds {
131f77850d3SUlf Magnusson current_entry->dep = expr_alloc_and(current_entry->dep, dep);
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds
menu_set_type(int type)1341da177e4SLinus Torvalds void menu_set_type(int type)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds struct symbol *sym = current_entry->sym;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds if (sym->type == type)
1391da177e4SLinus Torvalds return;
1401da177e4SLinus Torvalds if (sym->type == S_UNKNOWN) {
1411da177e4SLinus Torvalds sym->type = type;
1421da177e4SLinus Torvalds return;
1431da177e4SLinus Torvalds }
14457540f1dSMartin Walch menu_warn(current_entry,
14557540f1dSMartin Walch "ignoring type redefinition of '%s' from '%s' to '%s'",
1461da177e4SLinus Torvalds sym->name ? sym->name : "<choice>",
1471da177e4SLinus Torvalds sym_type_name(sym->type), sym_type_name(type));
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds
menu_add_prop(enum prop_type type,struct expr * expr,struct expr * dep)1502ffeef61SMasahiro Yamada static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
1512ffeef61SMasahiro Yamada struct expr *dep)
1521da177e4SLinus Torvalds {
153adf7c5bdSMasahiro Yamada struct property *prop;
1541da177e4SLinus Torvalds
155adf7c5bdSMasahiro Yamada prop = xmalloc(sizeof(*prop));
156adf7c5bdSMasahiro Yamada memset(prop, 0, sizeof(*prop));
157adf7c5bdSMasahiro Yamada prop->type = type;
1581a90b0cdSMasahiro Yamada prop->filename = cur_filename;
1591d7c4f10SMasahiro Yamada prop->lineno = cur_lineno;
1601da177e4SLinus Torvalds prop->menu = current_entry;
1611da177e4SLinus Torvalds prop->expr = expr;
162f77850d3SUlf Magnusson prop->visible.expr = dep;
1631da177e4SLinus Torvalds
164adf7c5bdSMasahiro Yamada /* append property to the prop list of symbol */
165adf7c5bdSMasahiro Yamada if (current_entry->sym) {
166adf7c5bdSMasahiro Yamada struct property **propp;
167adf7c5bdSMasahiro Yamada
168adf7c5bdSMasahiro Yamada for (propp = ¤t_entry->sym->prop;
169adf7c5bdSMasahiro Yamada *propp;
170adf7c5bdSMasahiro Yamada propp = &(*propp)->next)
171adf7c5bdSMasahiro Yamada ;
172adf7c5bdSMasahiro Yamada *propp = prop;
173adf7c5bdSMasahiro Yamada }
174adf7c5bdSMasahiro Yamada
175024352ffSMasahiro Yamada return prop;
176024352ffSMasahiro Yamada }
177024352ffSMasahiro Yamada
menu_add_prompt(enum prop_type type,const char * prompt,struct expr * dep)1786425e3b2SMasahiro Yamada struct property *menu_add_prompt(enum prop_type type, const char *prompt,
179024352ffSMasahiro Yamada struct expr *dep)
180024352ffSMasahiro Yamada {
1812ffeef61SMasahiro Yamada struct property *prop = menu_add_prop(type, NULL, dep);
182024352ffSMasahiro Yamada
183f001f7f8SRoman Zippel if (isspace(*prompt)) {
184f001f7f8SRoman Zippel prop_warn(prop, "leading whitespace ignored");
185f001f7f8SRoman Zippel while (isspace(*prompt))
186f001f7f8SRoman Zippel prompt++;
187f001f7f8SRoman Zippel }
188f64048a2SMasahiro Yamada if (current_entry->prompt)
189f001f7f8SRoman Zippel prop_warn(prop, "prompt redefined");
1907ad12278SJan Beulich
1917ad12278SJan Beulich /* Apply all upper menus' visibilities to actual prompts. */
1927ad12278SJan Beulich if (type == P_PROMPT) {
1937ad12278SJan Beulich struct menu *menu = current_entry;
1947ad12278SJan Beulich
1957ad12278SJan Beulich while ((menu = menu->parent) != NULL) {
196e983b7b1SDirk Gouders
1977ad12278SJan Beulich if (!menu->visibility)
1987ad12278SJan Beulich continue;
199024352ffSMasahiro Yamada prop->visible.expr = expr_alloc_and(prop->visible.expr,
200f93d6bfbSMasahiro Yamada menu->visibility);
2017ad12278SJan Beulich }
2027ad12278SJan Beulich }
2037ad12278SJan Beulich
2041da177e4SLinus Torvalds current_entry->prompt = prop;
205f001f7f8SRoman Zippel prop->text = prompt;
2061da177e4SLinus Torvalds
2071da177e4SLinus Torvalds return prop;
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds
menu_add_visibility(struct expr * expr)21086e187ffSArnaud Lacombe void menu_add_visibility(struct expr *expr)
21186e187ffSArnaud Lacombe {
21286e187ffSArnaud Lacombe current_entry->visibility = expr_alloc_and(current_entry->visibility,
21386e187ffSArnaud Lacombe expr);
21486e187ffSArnaud Lacombe }
21586e187ffSArnaud Lacombe
menu_add_expr(enum prop_type type,struct expr * expr,struct expr * dep)2161da177e4SLinus Torvalds void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
2171da177e4SLinus Torvalds {
2182ffeef61SMasahiro Yamada menu_add_prop(type, expr, dep);
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds
menu_add_symbol(enum prop_type type,struct symbol * sym,struct expr * dep)2211da177e4SLinus Torvalds void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
2221da177e4SLinus Torvalds {
2232ffeef61SMasahiro Yamada menu_add_prop(type, expr_alloc_symbol(sym), dep);
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds
menu_validate_number(struct symbol * sym,struct symbol * sym2)226ab60bd0bSArnaud Lacombe static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
2274cf3cbe2SRoman Zippel {
2284cf3cbe2SRoman Zippel return sym2->type == S_INT || sym2->type == S_HEX ||
2294cf3cbe2SRoman Zippel (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
2304cf3cbe2SRoman Zippel }
2314cf3cbe2SRoman Zippel
sym_check_prop(struct symbol * sym)2324356f489STrevor Keith static void sym_check_prop(struct symbol *sym)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds struct property *prop;
2351da177e4SLinus Torvalds struct symbol *sym2;
236237e3ad0SNicolas Pitre char *use;
237237e3ad0SNicolas Pitre
2381da177e4SLinus Torvalds for (prop = sym->prop; prop; prop = prop->next) {
2391da177e4SLinus Torvalds switch (prop->type) {
2401da177e4SLinus Torvalds case P_DEFAULT:
2411da177e4SLinus Torvalds if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
2421da177e4SLinus Torvalds prop->expr->type != E_SYMBOL)
2431da177e4SLinus Torvalds prop_warn(prop,
2444280eae0SLi Zefan "default for config symbol '%s'"
2451da177e4SLinus Torvalds " must be a single symbol", sym->name);
246ab60bd0bSArnaud Lacombe if (prop->expr->type != E_SYMBOL)
247ab60bd0bSArnaud Lacombe break;
248ab60bd0bSArnaud Lacombe sym2 = prop_get_symbol(prop);
249ab60bd0bSArnaud Lacombe if (sym->type == S_HEX || sym->type == S_INT) {
250ab60bd0bSArnaud Lacombe if (!menu_validate_number(sym, sym2))
251ab60bd0bSArnaud Lacombe prop_warn(prop,
252ab60bd0bSArnaud Lacombe "'%s': number is invalid",
253ab60bd0bSArnaud Lacombe sym->name);
254ab60bd0bSArnaud Lacombe }
2552c37e084SUlf Magnusson if (sym_is_choice(sym)) {
2566ffe4fdfSMasahiro Yamada struct menu *choice = sym_get_choice_menu(sym2);
2572c37e084SUlf Magnusson
2586ffe4fdfSMasahiro Yamada if (!choice || choice->sym != sym)
2592c37e084SUlf Magnusson prop_warn(prop,
2602c37e084SUlf Magnusson "choice default symbol '%s' is not contained in the choice",
2612c37e084SUlf Magnusson sym2->name);
2622c37e084SUlf Magnusson }
2631da177e4SLinus Torvalds break;
2641da177e4SLinus Torvalds case P_SELECT:
265237e3ad0SNicolas Pitre case P_IMPLY:
266237e3ad0SNicolas Pitre use = prop->type == P_SELECT ? "select" : "imply";
2671da177e4SLinus Torvalds sym2 = prop_get_symbol(prop);
2681da177e4SLinus Torvalds if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
2691da177e4SLinus Torvalds prop_warn(prop,
270237e3ad0SNicolas Pitre "config symbol '%s' uses %s, but is "
271b92d804aSMasahiro Yamada "not bool or tristate", sym->name, use);
272603d4988SSam Ravnborg else if (sym2->type != S_UNKNOWN &&
273603d4988SSam Ravnborg sym2->type != S_BOOLEAN &&
274603d4988SSam Ravnborg sym2->type != S_TRISTATE)
2751da177e4SLinus Torvalds prop_warn(prop,
276237e3ad0SNicolas Pitre "'%s' has wrong type. '%s' only "
277b92d804aSMasahiro Yamada "accept arguments of bool and "
278237e3ad0SNicolas Pitre "tristate type", sym2->name, use);
2791da177e4SLinus Torvalds break;
2801da177e4SLinus Torvalds case P_RANGE:
2811da177e4SLinus Torvalds if (sym->type != S_INT && sym->type != S_HEX)
2821da177e4SLinus Torvalds prop_warn(prop, "range is only allowed "
2831da177e4SLinus Torvalds "for int or hex symbols");
284ab60bd0bSArnaud Lacombe if (!menu_validate_number(sym, prop->expr->left.sym) ||
285ab60bd0bSArnaud Lacombe !menu_validate_number(sym, prop->expr->right.sym))
2861da177e4SLinus Torvalds prop_warn(prop, "range is invalid");
2871da177e4SLinus Torvalds break;
2881da177e4SLinus Torvalds default:
2891da177e4SLinus Torvalds ;
2901da177e4SLinus Torvalds }
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds
_menu_finalize(struct menu * parent,bool inside_choice)2947e3465f6SMasahiro Yamada static void _menu_finalize(struct menu *parent, bool inside_choice)
2951da177e4SLinus Torvalds {
2961da177e4SLinus Torvalds struct menu *menu, *last_menu;
2971da177e4SLinus Torvalds struct symbol *sym;
2981da177e4SLinus Torvalds struct property *prop;
299d533828eSMasahiro Yamada struct expr *basedep, *dep, *dep2;
3001da177e4SLinus Torvalds
3011da177e4SLinus Torvalds sym = parent->sym;
3021da177e4SLinus Torvalds if (parent->list) {
303fa8cedaeSUlf Magnusson /*
304fa8cedaeSUlf Magnusson * This menu node has children. We (recursively) process them
305fa8cedaeSUlf Magnusson * and propagate parent dependencies before moving on.
306fa8cedaeSUlf Magnusson */
307fa8cedaeSUlf Magnusson
308fa8cedaeSUlf Magnusson /* For each child menu node... */
3091da177e4SLinus Torvalds for (menu = parent->list; menu; menu = menu->next) {
310fa8cedaeSUlf Magnusson /*
311fa8cedaeSUlf Magnusson * Propagate parent dependencies to the child menu
312fa8cedaeSUlf Magnusson * node, also rewriting and simplifying expressions
313fa8cedaeSUlf Magnusson */
314f77850d3SUlf Magnusson basedep = rewrite_m(menu->dep);
315f77850d3SUlf Magnusson basedep = expr_transform(basedep);
316f93d6bfbSMasahiro Yamada basedep = expr_alloc_and(parent->dep, basedep);
3171da177e4SLinus Torvalds basedep = expr_eliminate_dups(basedep);
3181da177e4SLinus Torvalds menu->dep = basedep;
319fa8cedaeSUlf Magnusson
3201da177e4SLinus Torvalds if (menu->sym)
321fa8cedaeSUlf Magnusson /*
322fa8cedaeSUlf Magnusson * Note: For symbols, all prompts are included
323fa8cedaeSUlf Magnusson * too in the symbol's own property list
324fa8cedaeSUlf Magnusson */
3251da177e4SLinus Torvalds prop = menu->sym->prop;
3261da177e4SLinus Torvalds else
327fa8cedaeSUlf Magnusson /*
328fa8cedaeSUlf Magnusson * For non-symbol menu nodes, we just need to
329fa8cedaeSUlf Magnusson * handle the prompt
330fa8cedaeSUlf Magnusson */
3311da177e4SLinus Torvalds prop = menu->prompt;
332fa8cedaeSUlf Magnusson
333fa8cedaeSUlf Magnusson /* For each property... */
3341da177e4SLinus Torvalds for (; prop; prop = prop->next) {
3351da177e4SLinus Torvalds if (prop->menu != menu)
336fa8cedaeSUlf Magnusson /*
337fa8cedaeSUlf Magnusson * Two possibilities:
338fa8cedaeSUlf Magnusson *
339fa8cedaeSUlf Magnusson * 1. The property lacks dependencies
340fa8cedaeSUlf Magnusson * and so isn't location-specific,
341fa8cedaeSUlf Magnusson * e.g. an 'option'
342fa8cedaeSUlf Magnusson *
343fa8cedaeSUlf Magnusson * 2. The property belongs to a symbol
344fa8cedaeSUlf Magnusson * defined in multiple locations and
345fa8cedaeSUlf Magnusson * is from some other location. It
346fa8cedaeSUlf Magnusson * will be handled there in that
347fa8cedaeSUlf Magnusson * case.
348fa8cedaeSUlf Magnusson *
349fa8cedaeSUlf Magnusson * Skip the property.
350fa8cedaeSUlf Magnusson */
3511da177e4SLinus Torvalds continue;
352fa8cedaeSUlf Magnusson
353fa8cedaeSUlf Magnusson /*
354fa8cedaeSUlf Magnusson * Propagate parent dependencies to the
355fa8cedaeSUlf Magnusson * property's condition, rewriting and
356fa8cedaeSUlf Magnusson * simplifying expressions at the same time
357fa8cedaeSUlf Magnusson */
358f77850d3SUlf Magnusson dep = rewrite_m(prop->visible.expr);
359f77850d3SUlf Magnusson dep = expr_transform(dep);
360f93d6bfbSMasahiro Yamada dep = expr_alloc_and(basedep, dep);
3611da177e4SLinus Torvalds dep = expr_eliminate_dups(dep);
3621da177e4SLinus Torvalds prop->visible.expr = dep;
363fa8cedaeSUlf Magnusson
364fa8cedaeSUlf Magnusson /*
365fa8cedaeSUlf Magnusson * Handle selects and implies, which modify the
366fa8cedaeSUlf Magnusson * dependencies of the selected/implied symbol
367fa8cedaeSUlf Magnusson */
3681da177e4SLinus Torvalds if (prop->type == P_SELECT) {
3691da177e4SLinus Torvalds struct symbol *es = prop_get_symbol(prop);
3701da177e4SLinus Torvalds es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
371f93d6bfbSMasahiro Yamada expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
372237e3ad0SNicolas Pitre } else if (prop->type == P_IMPLY) {
373237e3ad0SNicolas Pitre struct symbol *es = prop_get_symbol(prop);
374237e3ad0SNicolas Pitre es->implied.expr = expr_alloc_or(es->implied.expr,
375f93d6bfbSMasahiro Yamada expr_alloc_and(expr_alloc_symbol(menu->sym), dep));
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds }
379fa8cedaeSUlf Magnusson
380fa8cedaeSUlf Magnusson /*
381fa8cedaeSUlf Magnusson * Recursively process children in the same fashion before
382fa8cedaeSUlf Magnusson * moving on
383fa8cedaeSUlf Magnusson */
3841da177e4SLinus Torvalds for (menu = parent->list; menu; menu = menu->next)
385d533828eSMasahiro Yamada _menu_finalize(menu, sym && sym_is_choice(sym));
3867e3465f6SMasahiro Yamada } else if (!inside_choice && sym) {
38705cccce5SUlf Magnusson /*
38805cccce5SUlf Magnusson * Automatic submenu creation. If sym is a symbol and A, B, C,
38905cccce5SUlf Magnusson * ... are consecutive items (symbols, menus, ifs, etc.) that
39005cccce5SUlf Magnusson * all depend on sym, then the following menu structure is
39105cccce5SUlf Magnusson * created:
39205cccce5SUlf Magnusson *
39305cccce5SUlf Magnusson * sym
39405cccce5SUlf Magnusson * +-A
39505cccce5SUlf Magnusson * +-B
39605cccce5SUlf Magnusson * +-C
39705cccce5SUlf Magnusson * ...
39805cccce5SUlf Magnusson *
39905cccce5SUlf Magnusson * This also works recursively, giving the following structure
40005cccce5SUlf Magnusson * if A is a symbol and B depends on A:
40105cccce5SUlf Magnusson *
40205cccce5SUlf Magnusson * sym
40305cccce5SUlf Magnusson * +-A
40405cccce5SUlf Magnusson * | +-B
40505cccce5SUlf Magnusson * +-C
40605cccce5SUlf Magnusson * ...
40705cccce5SUlf Magnusson */
40805cccce5SUlf Magnusson
4091da177e4SLinus Torvalds basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
4101da177e4SLinus Torvalds basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
4111da177e4SLinus Torvalds basedep = expr_eliminate_dups(expr_transform(basedep));
41205cccce5SUlf Magnusson
41305cccce5SUlf Magnusson /* Examine consecutive elements after sym */
4141da177e4SLinus Torvalds last_menu = NULL;
4151da177e4SLinus Torvalds for (menu = parent->next; menu; menu = menu->next) {
4161da177e4SLinus Torvalds dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
4171da177e4SLinus Torvalds if (!expr_contains_symbol(dep, sym))
41805cccce5SUlf Magnusson /* No dependency, quit */
4191da177e4SLinus Torvalds break;
4201da177e4SLinus Torvalds if (expr_depends_symbol(dep, sym))
42105cccce5SUlf Magnusson /* Absolute dependency, put in submenu */
4221da177e4SLinus Torvalds goto next;
42305cccce5SUlf Magnusson
42405cccce5SUlf Magnusson /*
42505cccce5SUlf Magnusson * Also consider it a dependency on sym if our
42605cccce5SUlf Magnusson * dependencies contain sym and are a "superset" of
42705cccce5SUlf Magnusson * sym's dependencies, e.g. '(sym || Q) && R' when sym
42805cccce5SUlf Magnusson * depends on R.
42905cccce5SUlf Magnusson *
43005cccce5SUlf Magnusson * Note that 'R' might be from an enclosing menu or if,
43105cccce5SUlf Magnusson * making this a more common case than it might seem.
43205cccce5SUlf Magnusson */
4331da177e4SLinus Torvalds dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
4341da177e4SLinus Torvalds dep = expr_eliminate_dups(expr_transform(dep));
435f93d6bfbSMasahiro Yamada dep2 = basedep;
4361da177e4SLinus Torvalds expr_eliminate_eq(&dep, &dep2);
4371da177e4SLinus Torvalds if (!expr_is_yes(dep2)) {
43805cccce5SUlf Magnusson /* Not superset, quit */
4391da177e4SLinus Torvalds break;
4401da177e4SLinus Torvalds }
44105cccce5SUlf Magnusson /* Superset, put in submenu */
4421da177e4SLinus Torvalds next:
4437e3465f6SMasahiro Yamada _menu_finalize(menu, false);
4441da177e4SLinus Torvalds menu->parent = parent;
4451da177e4SLinus Torvalds last_menu = menu;
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds if (last_menu) {
4481da177e4SLinus Torvalds parent->list = parent->next;
4491da177e4SLinus Torvalds parent->next = last_menu->next;
4501da177e4SLinus Torvalds last_menu->next = NULL;
4511da177e4SLinus Torvalds }
452ff5ff606SArnaud Lacombe
453ec6452a5SArnaud Lacombe sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
4541da177e4SLinus Torvalds }
4551da177e4SLinus Torvalds for (menu = parent->list; menu; menu = menu->next) {
4569d1a9e8bSUlf Magnusson /*
4579d1a9e8bSUlf Magnusson * This code serves two purposes:
4589d1a9e8bSUlf Magnusson *
4599d1a9e8bSUlf Magnusson * (1) Flattening 'if' blocks, which do not specify a submenu
4609d1a9e8bSUlf Magnusson * and only add dependencies.
4619d1a9e8bSUlf Magnusson *
4629d1a9e8bSUlf Magnusson * (Automatic submenu creation might still create a submenu
4639d1a9e8bSUlf Magnusson * from an 'if' before this code runs.)
4649d1a9e8bSUlf Magnusson *
4659d1a9e8bSUlf Magnusson * (2) "Undoing" any automatic submenus created earlier below
4669d1a9e8bSUlf Magnusson * promptless symbols.
4679d1a9e8bSUlf Magnusson *
4689d1a9e8bSUlf Magnusson * Before:
4699d1a9e8bSUlf Magnusson *
4709d1a9e8bSUlf Magnusson * A
4719d1a9e8bSUlf Magnusson * if ... (or promptless symbol)
4729d1a9e8bSUlf Magnusson * +-B
4739d1a9e8bSUlf Magnusson * +-C
4749d1a9e8bSUlf Magnusson * D
4759d1a9e8bSUlf Magnusson *
4769d1a9e8bSUlf Magnusson * After:
4779d1a9e8bSUlf Magnusson *
4789d1a9e8bSUlf Magnusson * A
4799d1a9e8bSUlf Magnusson * if ... (or promptless symbol)
4809d1a9e8bSUlf Magnusson * B
4819d1a9e8bSUlf Magnusson * C
4829d1a9e8bSUlf Magnusson * D
4839d1a9e8bSUlf Magnusson */
4841da177e4SLinus Torvalds if (menu->list && (!menu->prompt || !menu->prompt->text)) {
4851da177e4SLinus Torvalds for (last_menu = menu->list; ; last_menu = last_menu->next) {
4861da177e4SLinus Torvalds last_menu->parent = parent;
4871da177e4SLinus Torvalds if (!last_menu->next)
4881da177e4SLinus Torvalds break;
4891da177e4SLinus Torvalds }
4901da177e4SLinus Torvalds last_menu->next = menu->next;
4911da177e4SLinus Torvalds menu->next = menu->list;
4921da177e4SLinus Torvalds menu->list = NULL;
4931da177e4SLinus Torvalds }
4941da177e4SLinus Torvalds }
4951da177e4SLinus Torvalds
4961da177e4SLinus Torvalds if (sym && !(sym->flags & SYMBOL_WARNED)) {
4971da177e4SLinus Torvalds if (sym->type == S_UNKNOWN)
498f001f7f8SRoman Zippel menu_warn(parent, "config symbol defined without type");
4991da177e4SLinus Torvalds
5001da177e4SLinus Torvalds /* Check properties connected to this symbol */
5011da177e4SLinus Torvalds sym_check_prop(sym);
5021da177e4SLinus Torvalds sym->flags |= SYMBOL_WARNED;
5031da177e4SLinus Torvalds }
5041da177e4SLinus Torvalds }
5051da177e4SLinus Torvalds
menu_finalize(void)5067e3465f6SMasahiro Yamada void menu_finalize(void)
5077e3465f6SMasahiro Yamada {
5087e3465f6SMasahiro Yamada _menu_finalize(&rootmenu, false);
5097e3465f6SMasahiro Yamada }
5107e3465f6SMasahiro Yamada
menu_has_prompt(const struct menu * menu)5116425e3b2SMasahiro Yamada bool menu_has_prompt(const struct menu *menu)
51222c7eca6SLi Zefan {
51322c7eca6SLi Zefan if (!menu->prompt)
51422c7eca6SLi Zefan return false;
51522c7eca6SLi Zefan return true;
51622c7eca6SLi Zefan }
51722c7eca6SLi Zefan
5181278ebdbSDirk Gouders /*
5191278ebdbSDirk Gouders * Determine if a menu is empty.
5201278ebdbSDirk Gouders * A menu is considered empty if it contains no or only
5211278ebdbSDirk Gouders * invisible entries.
5221278ebdbSDirk Gouders */
menu_is_empty(struct menu * menu)5231278ebdbSDirk Gouders bool menu_is_empty(struct menu *menu)
5241278ebdbSDirk Gouders {
5251278ebdbSDirk Gouders struct menu *child;
5261278ebdbSDirk Gouders
5271278ebdbSDirk Gouders for (child = menu->list; child; child = child->next) {
5281278ebdbSDirk Gouders if (menu_is_visible(child))
5291278ebdbSDirk Gouders return(false);
5301278ebdbSDirk Gouders }
5311278ebdbSDirk Gouders return(true);
5321278ebdbSDirk Gouders }
5331278ebdbSDirk Gouders
menu_is_visible(struct menu * menu)5341da177e4SLinus Torvalds bool menu_is_visible(struct menu *menu)
5351da177e4SLinus Torvalds {
536*d01661e1SMasahiro Yamada struct menu *child;
5371da177e4SLinus Torvalds struct symbol *sym;
5381da177e4SLinus Torvalds tristate visible;
5391da177e4SLinus Torvalds
5401da177e4SLinus Torvalds if (!menu->prompt)
5411da177e4SLinus Torvalds return false;
54222c7eca6SLi Zefan
54386e187ffSArnaud Lacombe if (menu->visibility) {
54486e187ffSArnaud Lacombe if (expr_calc_value(menu->visibility) == no)
545aab24a89SVegard Nossum return false;
54686e187ffSArnaud Lacombe }
54786e187ffSArnaud Lacombe
5481da177e4SLinus Torvalds sym = menu->sym;
5491da177e4SLinus Torvalds if (sym) {
5501da177e4SLinus Torvalds sym_calc_value(sym);
5511da177e4SLinus Torvalds visible = menu->prompt->visible.tri;
5521da177e4SLinus Torvalds } else
5531da177e4SLinus Torvalds visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
5541da177e4SLinus Torvalds
555*d01661e1SMasahiro Yamada if (visible != no)
556*d01661e1SMasahiro Yamada return true;
557*d01661e1SMasahiro Yamada
558*d01661e1SMasahiro Yamada if (!sym || sym_get_tristate_value(menu->sym) == no)
559*d01661e1SMasahiro Yamada return false;
560*d01661e1SMasahiro Yamada
561*d01661e1SMasahiro Yamada for (child = menu->list; child; child = child->next)
562*d01661e1SMasahiro Yamada if (menu_is_visible(child))
563*d01661e1SMasahiro Yamada return true;
564*d01661e1SMasahiro Yamada
565*d01661e1SMasahiro Yamada return false;
5661da177e4SLinus Torvalds }
5671da177e4SLinus Torvalds
menu_get_prompt(const struct menu * menu)5686425e3b2SMasahiro Yamada const char *menu_get_prompt(const struct menu *menu)
5691da177e4SLinus Torvalds {
5701da177e4SLinus Torvalds if (menu->prompt)
57101771b0fSEGRY Gabor return menu->prompt->text;
5721da177e4SLinus Torvalds else if (menu->sym)
57301771b0fSEGRY Gabor return menu->sym->name;
5741da177e4SLinus Torvalds return NULL;
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds
menu_get_parent_menu(struct menu * menu)5771da177e4SLinus Torvalds struct menu *menu_get_parent_menu(struct menu *menu)
5781da177e4SLinus Torvalds {
5791da177e4SLinus Torvalds enum prop_type type;
5801da177e4SLinus Torvalds
5811da177e4SLinus Torvalds for (; menu != &rootmenu; menu = menu->parent) {
5821da177e4SLinus Torvalds type = menu->prompt ? menu->prompt->type : 0;
5831da177e4SLinus Torvalds if (type == P_MENU)
5841da177e4SLinus Torvalds break;
5851da177e4SLinus Torvalds }
5861da177e4SLinus Torvalds return menu;
5871da177e4SLinus Torvalds }
5881da177e4SLinus Torvalds
get_def_str(struct gstr * r,const struct menu * menu)5896425e3b2SMasahiro Yamada static void get_def_str(struct gstr *r, const struct menu *menu)
590edda15f2SThomas Hebb {
591edda15f2SThomas Hebb str_printf(r, "Defined at %s:%d\n",
59240bab83aSMasahiro Yamada menu->filename, menu->lineno);
593edda15f2SThomas Hebb }
594edda15f2SThomas Hebb
get_dep_str(struct gstr * r,const struct expr * expr,const char * prefix)5956425e3b2SMasahiro Yamada static void get_dep_str(struct gstr *r, const struct expr *expr,
5966425e3b2SMasahiro Yamada const char *prefix)
597edda15f2SThomas Hebb {
598edda15f2SThomas Hebb if (!expr_is_yes(expr)) {
599edda15f2SThomas Hebb str_append(r, prefix);
600edda15f2SThomas Hebb expr_gstr_print(expr, r);
601edda15f2SThomas Hebb str_append(r, "\n");
602edda15f2SThomas Hebb }
603edda15f2SThomas Hebb }
604edda15f2SThomas Hebb
get_jump_key_char(void)605e14f1242SMasahiro Yamada int __attribute__((weak)) get_jump_key_char(void)
606e14f1242SMasahiro Yamada {
607e14f1242SMasahiro Yamada return -1;
608e14f1242SMasahiro Yamada }
609e14f1242SMasahiro Yamada
get_prompt_str(struct gstr * r,struct property * prop,struct list_head * head)61095ac9b3bSBenjamin Poirier static void get_prompt_str(struct gstr *r, struct property *prop,
611bad9955dSBenjamin Poirier struct list_head *head)
6126bd5999dSCheng Renquan {
6136bd5999dSCheng Renquan int i, j;
6145e609addSBenjamin Poirier struct menu *submenu[8], *menu, *location = NULL;
6152d560306SPeter Kümmel struct jump_key *jump = NULL;
6166bd5999dSCheng Renquan
617694c49a7SSam Ravnborg str_printf(r, " Prompt: %s\n", prop->text);
618edda15f2SThomas Hebb
619edda15f2SThomas Hebb get_dep_str(r, prop->menu->dep, " Depends on: ");
6203460d0bcSThomas Hebb /*
6213460d0bcSThomas Hebb * Most prompts in Linux have visibility that exactly matches their
6223460d0bcSThomas Hebb * dependencies. For these, we print only the dependencies to improve
6233460d0bcSThomas Hebb * readability. However, prompts with inline "if" expressions and
6243460d0bcSThomas Hebb * prompts with a parent that has a "visible if" expression have
6253460d0bcSThomas Hebb * differing dependencies and visibility. In these rare cases, we
6263460d0bcSThomas Hebb * print both.
6273460d0bcSThomas Hebb */
6283460d0bcSThomas Hebb if (!expr_eq(prop->menu->dep, prop->visible.expr))
6293460d0bcSThomas Hebb get_dep_str(r, prop->visible.expr, " Visible if: ");
6303460d0bcSThomas Hebb
6317a263a04SMasahiro Yamada menu = prop->menu;
6327a263a04SMasahiro Yamada for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
6336bd5999dSCheng Renquan submenu[i++] = menu;
6341791360cSMasahiro Yamada if (location == NULL && menu_is_visible(menu))
6355e609addSBenjamin Poirier location = menu;
6365e609addSBenjamin Poirier }
63795ac9b3bSBenjamin Poirier if (head && location) {
638177acf78SAlan Cox jump = xmalloc(sizeof(struct jump_key));
63995ac9b3bSBenjamin Poirier jump->target = location;
640bad9955dSBenjamin Poirier list_add_tail(&jump->entries, head);
64195ac9b3bSBenjamin Poirier }
6425e609addSBenjamin Poirier
643694c49a7SSam Ravnborg str_printf(r, " Location:\n");
644e14f1242SMasahiro Yamada for (j = 0; --i >= 0; j++) {
645e14f1242SMasahiro Yamada int jk = -1;
646e14f1242SMasahiro Yamada int indent = 2 * j + 4;
647e14f1242SMasahiro Yamada
6486bd5999dSCheng Renquan menu = submenu[i];
649e14f1242SMasahiro Yamada if (jump && menu == location) {
650503c8230SMartin Walch jump->offset = strlen(r->s);
651e14f1242SMasahiro Yamada jk = get_jump_key_char();
652e14f1242SMasahiro Yamada }
653e14f1242SMasahiro Yamada
654e14f1242SMasahiro Yamada if (jk >= 0) {
655e14f1242SMasahiro Yamada str_printf(r, "(%c)", jk);
656e14f1242SMasahiro Yamada indent -= 3;
657e14f1242SMasahiro Yamada }
658e14f1242SMasahiro Yamada
659e14f1242SMasahiro Yamada str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu));
6606bd5999dSCheng Renquan if (menu->sym) {
6616bd5999dSCheng Renquan str_printf(r, " (%s [=%s])", menu->sym->name ?
662694c49a7SSam Ravnborg menu->sym->name : "<choice>",
6636bd5999dSCheng Renquan sym_get_string_value(menu->sym));
6646bd5999dSCheng Renquan }
6656bd5999dSCheng Renquan str_append(r, "\n");
6666bd5999dSCheng Renquan }
6676bd5999dSCheng Renquan }
6686bd5999dSCheng Renquan
get_symbol_props_str(struct gstr * r,struct symbol * sym,enum prop_type tok,const char * prefix)669237e3ad0SNicolas Pitre static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
670237e3ad0SNicolas Pitre enum prop_type tok, const char *prefix)
671237e3ad0SNicolas Pitre {
672237e3ad0SNicolas Pitre bool hit = false;
673237e3ad0SNicolas Pitre struct property *prop;
674237e3ad0SNicolas Pitre
675237e3ad0SNicolas Pitre for_all_properties(sym, prop, tok) {
676237e3ad0SNicolas Pitre if (!hit) {
677237e3ad0SNicolas Pitre str_append(r, prefix);
678237e3ad0SNicolas Pitre hit = true;
679237e3ad0SNicolas Pitre } else
680237e3ad0SNicolas Pitre str_printf(r, " && ");
681237e3ad0SNicolas Pitre expr_gstr_print(prop->expr, r);
682237e3ad0SNicolas Pitre }
683237e3ad0SNicolas Pitre if (hit)
684237e3ad0SNicolas Pitre str_append(r, "\n");
685237e3ad0SNicolas Pitre }
686237e3ad0SNicolas Pitre
687bcdedcc1SWengmeiling /*
68895ac9b3bSBenjamin Poirier * head is optional and may be NULL
6895e609addSBenjamin Poirier */
get_symbol_str(struct gstr * r,struct symbol * sym,struct list_head * head)690ad8d40cdSMichal Marek static void get_symbol_str(struct gstr *r, struct symbol *sym,
691bad9955dSBenjamin Poirier struct list_head *head)
6926bd5999dSCheng Renquan {
6936bd5999dSCheng Renquan struct property *prop;
694bedf9236SMasahiro Yamada struct menu *menu;
6956bd5999dSCheng Renquan
696b040b44cSLi Zefan if (sym && sym->name) {
6976bd5999dSCheng Renquan str_printf(r, "Symbol: %s [=%s]\n", sym->name,
6986bd5999dSCheng Renquan sym_get_string_value(sym));
699b040b44cSLi Zefan str_printf(r, "Type : %s\n", sym_type_name(sym->type));
70070ed0747SLi Zefan if (sym->type == S_INT || sym->type == S_HEX) {
70170ed0747SLi Zefan prop = sym_get_range_prop(sym);
70270ed0747SLi Zefan if (prop) {
70370ed0747SLi Zefan str_printf(r, "Range : ");
70470ed0747SLi Zefan expr_gstr_print(prop->expr, r);
70570ed0747SLi Zefan str_append(r, "\n");
70670ed0747SLi Zefan }
70770ed0747SLi Zefan }
708b040b44cSLi Zefan }
709383da76fSLi Zefan
710edda15f2SThomas Hebb /* Print the definitions with prompts before the ones without */
711bedf9236SMasahiro Yamada list_for_each_entry(menu, &sym->menus, link) {
712bedf9236SMasahiro Yamada if (menu->prompt) {
713bedf9236SMasahiro Yamada get_def_str(r, menu);
714bedf9236SMasahiro Yamada get_prompt_str(r, menu->prompt, head);
715edda15f2SThomas Hebb }
716edda15f2SThomas Hebb }
717edda15f2SThomas Hebb
718bedf9236SMasahiro Yamada list_for_each_entry(menu, &sym->menus, link) {
719bedf9236SMasahiro Yamada if (!menu->prompt) {
720bedf9236SMasahiro Yamada get_def_str(r, menu);
721bedf9236SMasahiro Yamada get_dep_str(r, menu->dep, " Depends on: ");
722bcdedcc1SWengmeiling }
723383da76fSLi Zefan }
724383da76fSLi Zefan
725694c49a7SSam Ravnborg get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
7266bd5999dSCheng Renquan if (sym->rev_dep.expr) {
727d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n");
728d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n");
729d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n");
7306bd5999dSCheng Renquan }
731237e3ad0SNicolas Pitre
732694c49a7SSam Ravnborg get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
733237e3ad0SNicolas Pitre if (sym->implied.expr) {
734d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n");
735d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n");
736d9119b59SEugeniu Rosca expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n");
737237e3ad0SNicolas Pitre }
738237e3ad0SNicolas Pitre
7396bd5999dSCheng Renquan str_append(r, "\n\n");
7406bd5999dSCheng Renquan }
7416bd5999dSCheng Renquan
get_relations_str(struct symbol ** sym_arr,struct list_head * head)742bad9955dSBenjamin Poirier struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
743692d97c3S[email protected] {
744692d97c3S[email protected] struct symbol *sym;
745692d97c3S[email protected] struct gstr res = str_new();
74695ac9b3bSBenjamin Poirier int i;
747692d97c3S[email protected]
748692d97c3S[email protected] for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
74995ac9b3bSBenjamin Poirier get_symbol_str(&res, sym, head);
750692d97c3S[email protected] if (!i)
751694c49a7SSam Ravnborg str_append(&res, "No matches found.\n");
752692d97c3S[email protected] return res;
753692d97c3S[email protected] }
754692d97c3S[email protected]
755692d97c3S[email protected]
menu_get_ext_help(struct menu * menu,struct gstr * help)7566bd5999dSCheng Renquan void menu_get_ext_help(struct menu *menu, struct gstr *help)
7576bd5999dSCheng Renquan {
7586bd5999dSCheng Renquan struct symbol *sym = menu->sym;
75957e6292dSArnaud Lacombe const char *help_text = nohelp_text;
7606bd5999dSCheng Renquan
761092e39d1SMasahiro Yamada if (menu->help) {
7623f198dfeSSrinivas Kandagatla if (sym->name)
763ffb5957bSArnaud Lacombe str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
764092e39d1SMasahiro Yamada help_text = menu->help;
7656bd5999dSCheng Renquan }
766694c49a7SSam Ravnborg str_printf(help, "%s\n", help_text);
7674779105eSCheng Renquan if (sym)
76895ac9b3bSBenjamin Poirier get_symbol_str(help, sym, NULL);
7696bd5999dSCheng Renquan }
770