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