xref: /linux-6.15/scripts/kconfig/menu.c (revision d01661e1)
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 = &current_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 = &current_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 = &current_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