xref: /rk3399_rockchip-uboot/scripts/kconfig/menu.c (revision 0a9064fb47bb0a239c04b0b63edebfdd3a201fdc)
1*0a9064fbSMasahiro Yamada /*
2*0a9064fbSMasahiro Yamada  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3*0a9064fbSMasahiro Yamada  * Released under the terms of the GNU GPL v2.0.
4*0a9064fbSMasahiro Yamada  */
5*0a9064fbSMasahiro Yamada 
6*0a9064fbSMasahiro Yamada #include <ctype.h>
7*0a9064fbSMasahiro Yamada #include <stdarg.h>
8*0a9064fbSMasahiro Yamada #include <stdlib.h>
9*0a9064fbSMasahiro Yamada #include <string.h>
10*0a9064fbSMasahiro Yamada 
11*0a9064fbSMasahiro Yamada #include "lkc.h"
12*0a9064fbSMasahiro Yamada 
13*0a9064fbSMasahiro Yamada static const char nohelp_text[] = "There is no help available for this option.";
14*0a9064fbSMasahiro Yamada 
15*0a9064fbSMasahiro Yamada struct menu rootmenu;
16*0a9064fbSMasahiro Yamada static struct menu **last_entry_ptr;
17*0a9064fbSMasahiro Yamada 
18*0a9064fbSMasahiro Yamada struct file *file_list;
19*0a9064fbSMasahiro Yamada struct file *current_file;
20*0a9064fbSMasahiro Yamada 
21*0a9064fbSMasahiro Yamada void menu_warn(struct menu *menu, const char *fmt, ...)
22*0a9064fbSMasahiro Yamada {
23*0a9064fbSMasahiro Yamada 	va_list ap;
24*0a9064fbSMasahiro Yamada 	va_start(ap, fmt);
25*0a9064fbSMasahiro Yamada 	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
26*0a9064fbSMasahiro Yamada 	vfprintf(stderr, fmt, ap);
27*0a9064fbSMasahiro Yamada 	fprintf(stderr, "\n");
28*0a9064fbSMasahiro Yamada 	va_end(ap);
29*0a9064fbSMasahiro Yamada }
30*0a9064fbSMasahiro Yamada 
31*0a9064fbSMasahiro Yamada static void prop_warn(struct property *prop, const char *fmt, ...)
32*0a9064fbSMasahiro Yamada {
33*0a9064fbSMasahiro Yamada 	va_list ap;
34*0a9064fbSMasahiro Yamada 	va_start(ap, fmt);
35*0a9064fbSMasahiro Yamada 	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
36*0a9064fbSMasahiro Yamada 	vfprintf(stderr, fmt, ap);
37*0a9064fbSMasahiro Yamada 	fprintf(stderr, "\n");
38*0a9064fbSMasahiro Yamada 	va_end(ap);
39*0a9064fbSMasahiro Yamada }
40*0a9064fbSMasahiro Yamada 
41*0a9064fbSMasahiro Yamada void _menu_init(void)
42*0a9064fbSMasahiro Yamada {
43*0a9064fbSMasahiro Yamada 	current_entry = current_menu = &rootmenu;
44*0a9064fbSMasahiro Yamada 	last_entry_ptr = &rootmenu.list;
45*0a9064fbSMasahiro Yamada }
46*0a9064fbSMasahiro Yamada 
47*0a9064fbSMasahiro Yamada void menu_add_entry(struct symbol *sym)
48*0a9064fbSMasahiro Yamada {
49*0a9064fbSMasahiro Yamada 	struct menu *menu;
50*0a9064fbSMasahiro Yamada 
51*0a9064fbSMasahiro Yamada 	menu = xmalloc(sizeof(*menu));
52*0a9064fbSMasahiro Yamada 	memset(menu, 0, sizeof(*menu));
53*0a9064fbSMasahiro Yamada 	menu->sym = sym;
54*0a9064fbSMasahiro Yamada 	menu->parent = current_menu;
55*0a9064fbSMasahiro Yamada 	menu->file = current_file;
56*0a9064fbSMasahiro Yamada 	menu->lineno = zconf_lineno();
57*0a9064fbSMasahiro Yamada 
58*0a9064fbSMasahiro Yamada 	*last_entry_ptr = menu;
59*0a9064fbSMasahiro Yamada 	last_entry_ptr = &menu->next;
60*0a9064fbSMasahiro Yamada 	current_entry = menu;
61*0a9064fbSMasahiro Yamada 	if (sym)
62*0a9064fbSMasahiro Yamada 		menu_add_symbol(P_SYMBOL, sym, NULL);
63*0a9064fbSMasahiro Yamada }
64*0a9064fbSMasahiro Yamada 
65*0a9064fbSMasahiro Yamada void menu_end_entry(void)
66*0a9064fbSMasahiro Yamada {
67*0a9064fbSMasahiro Yamada }
68*0a9064fbSMasahiro Yamada 
69*0a9064fbSMasahiro Yamada struct menu *menu_add_menu(void)
70*0a9064fbSMasahiro Yamada {
71*0a9064fbSMasahiro Yamada 	menu_end_entry();
72*0a9064fbSMasahiro Yamada 	last_entry_ptr = &current_entry->list;
73*0a9064fbSMasahiro Yamada 	return current_menu = current_entry;
74*0a9064fbSMasahiro Yamada }
75*0a9064fbSMasahiro Yamada 
76*0a9064fbSMasahiro Yamada void menu_end_menu(void)
77*0a9064fbSMasahiro Yamada {
78*0a9064fbSMasahiro Yamada 	last_entry_ptr = &current_menu->next;
79*0a9064fbSMasahiro Yamada 	current_menu = current_menu->parent;
80*0a9064fbSMasahiro Yamada }
81*0a9064fbSMasahiro Yamada 
82*0a9064fbSMasahiro Yamada static struct expr *menu_check_dep(struct expr *e)
83*0a9064fbSMasahiro Yamada {
84*0a9064fbSMasahiro Yamada 	if (!e)
85*0a9064fbSMasahiro Yamada 		return e;
86*0a9064fbSMasahiro Yamada 
87*0a9064fbSMasahiro Yamada 	switch (e->type) {
88*0a9064fbSMasahiro Yamada 	case E_NOT:
89*0a9064fbSMasahiro Yamada 		e->left.expr = menu_check_dep(e->left.expr);
90*0a9064fbSMasahiro Yamada 		break;
91*0a9064fbSMasahiro Yamada 	case E_OR:
92*0a9064fbSMasahiro Yamada 	case E_AND:
93*0a9064fbSMasahiro Yamada 		e->left.expr = menu_check_dep(e->left.expr);
94*0a9064fbSMasahiro Yamada 		e->right.expr = menu_check_dep(e->right.expr);
95*0a9064fbSMasahiro Yamada 		break;
96*0a9064fbSMasahiro Yamada 	case E_SYMBOL:
97*0a9064fbSMasahiro Yamada 		/* change 'm' into 'm' && MODULES */
98*0a9064fbSMasahiro Yamada 		if (e->left.sym == &symbol_mod)
99*0a9064fbSMasahiro Yamada 			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
100*0a9064fbSMasahiro Yamada 		break;
101*0a9064fbSMasahiro Yamada 	default:
102*0a9064fbSMasahiro Yamada 		break;
103*0a9064fbSMasahiro Yamada 	}
104*0a9064fbSMasahiro Yamada 	return e;
105*0a9064fbSMasahiro Yamada }
106*0a9064fbSMasahiro Yamada 
107*0a9064fbSMasahiro Yamada void menu_add_dep(struct expr *dep)
108*0a9064fbSMasahiro Yamada {
109*0a9064fbSMasahiro Yamada 	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
110*0a9064fbSMasahiro Yamada }
111*0a9064fbSMasahiro Yamada 
112*0a9064fbSMasahiro Yamada void menu_set_type(int type)
113*0a9064fbSMasahiro Yamada {
114*0a9064fbSMasahiro Yamada 	struct symbol *sym = current_entry->sym;
115*0a9064fbSMasahiro Yamada 
116*0a9064fbSMasahiro Yamada 	if (sym->type == type)
117*0a9064fbSMasahiro Yamada 		return;
118*0a9064fbSMasahiro Yamada 	if (sym->type == S_UNKNOWN) {
119*0a9064fbSMasahiro Yamada 		sym->type = type;
120*0a9064fbSMasahiro Yamada 		return;
121*0a9064fbSMasahiro Yamada 	}
122*0a9064fbSMasahiro Yamada 	menu_warn(current_entry,
123*0a9064fbSMasahiro Yamada 		"ignoring type redefinition of '%s' from '%s' to '%s'",
124*0a9064fbSMasahiro Yamada 		sym->name ? sym->name : "<choice>",
125*0a9064fbSMasahiro Yamada 		sym_type_name(sym->type), sym_type_name(type));
126*0a9064fbSMasahiro Yamada }
127*0a9064fbSMasahiro Yamada 
128*0a9064fbSMasahiro Yamada struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
129*0a9064fbSMasahiro Yamada {
130*0a9064fbSMasahiro Yamada 	struct property *prop = prop_alloc(type, current_entry->sym);
131*0a9064fbSMasahiro Yamada 
132*0a9064fbSMasahiro Yamada 	prop->menu = current_entry;
133*0a9064fbSMasahiro Yamada 	prop->expr = expr;
134*0a9064fbSMasahiro Yamada 	prop->visible.expr = menu_check_dep(dep);
135*0a9064fbSMasahiro Yamada 
136*0a9064fbSMasahiro Yamada 	if (prompt) {
137*0a9064fbSMasahiro Yamada 		if (isspace(*prompt)) {
138*0a9064fbSMasahiro Yamada 			prop_warn(prop, "leading whitespace ignored");
139*0a9064fbSMasahiro Yamada 			while (isspace(*prompt))
140*0a9064fbSMasahiro Yamada 				prompt++;
141*0a9064fbSMasahiro Yamada 		}
142*0a9064fbSMasahiro Yamada 		if (current_entry->prompt && current_entry != &rootmenu)
143*0a9064fbSMasahiro Yamada 			prop_warn(prop, "prompt redefined");
144*0a9064fbSMasahiro Yamada 
145*0a9064fbSMasahiro Yamada 		/* Apply all upper menus' visibilities to actual prompts. */
146*0a9064fbSMasahiro Yamada 		if(type == P_PROMPT) {
147*0a9064fbSMasahiro Yamada 			struct menu *menu = current_entry;
148*0a9064fbSMasahiro Yamada 
149*0a9064fbSMasahiro Yamada 			while ((menu = menu->parent) != NULL) {
150*0a9064fbSMasahiro Yamada 				struct expr *dup_expr;
151*0a9064fbSMasahiro Yamada 
152*0a9064fbSMasahiro Yamada 				if (!menu->visibility)
153*0a9064fbSMasahiro Yamada 					continue;
154*0a9064fbSMasahiro Yamada 				/*
155*0a9064fbSMasahiro Yamada 				 * Do not add a reference to the
156*0a9064fbSMasahiro Yamada 				 * menu's visibility expression but
157*0a9064fbSMasahiro Yamada 				 * use a copy of it.  Otherwise the
158*0a9064fbSMasahiro Yamada 				 * expression reduction functions
159*0a9064fbSMasahiro Yamada 				 * will modify expressions that have
160*0a9064fbSMasahiro Yamada 				 * multiple references which can
161*0a9064fbSMasahiro Yamada 				 * cause unwanted side effects.
162*0a9064fbSMasahiro Yamada 				 */
163*0a9064fbSMasahiro Yamada 				dup_expr = expr_copy(menu->visibility);
164*0a9064fbSMasahiro Yamada 
165*0a9064fbSMasahiro Yamada 				prop->visible.expr
166*0a9064fbSMasahiro Yamada 					= expr_alloc_and(prop->visible.expr,
167*0a9064fbSMasahiro Yamada 							 dup_expr);
168*0a9064fbSMasahiro Yamada 			}
169*0a9064fbSMasahiro Yamada 		}
170*0a9064fbSMasahiro Yamada 
171*0a9064fbSMasahiro Yamada 		current_entry->prompt = prop;
172*0a9064fbSMasahiro Yamada 	}
173*0a9064fbSMasahiro Yamada 	prop->text = prompt;
174*0a9064fbSMasahiro Yamada 
175*0a9064fbSMasahiro Yamada 	return prop;
176*0a9064fbSMasahiro Yamada }
177*0a9064fbSMasahiro Yamada 
178*0a9064fbSMasahiro Yamada struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
179*0a9064fbSMasahiro Yamada {
180*0a9064fbSMasahiro Yamada 	return menu_add_prop(type, prompt, NULL, dep);
181*0a9064fbSMasahiro Yamada }
182*0a9064fbSMasahiro Yamada 
183*0a9064fbSMasahiro Yamada void menu_add_visibility(struct expr *expr)
184*0a9064fbSMasahiro Yamada {
185*0a9064fbSMasahiro Yamada 	current_entry->visibility = expr_alloc_and(current_entry->visibility,
186*0a9064fbSMasahiro Yamada 	    expr);
187*0a9064fbSMasahiro Yamada }
188*0a9064fbSMasahiro Yamada 
189*0a9064fbSMasahiro Yamada void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
190*0a9064fbSMasahiro Yamada {
191*0a9064fbSMasahiro Yamada 	menu_add_prop(type, NULL, expr, dep);
192*0a9064fbSMasahiro Yamada }
193*0a9064fbSMasahiro Yamada 
194*0a9064fbSMasahiro Yamada void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
195*0a9064fbSMasahiro Yamada {
196*0a9064fbSMasahiro Yamada 	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
197*0a9064fbSMasahiro Yamada }
198*0a9064fbSMasahiro Yamada 
199*0a9064fbSMasahiro Yamada void menu_add_option(int token, char *arg)
200*0a9064fbSMasahiro Yamada {
201*0a9064fbSMasahiro Yamada 	switch (token) {
202*0a9064fbSMasahiro Yamada 	case T_OPT_MODULES:
203*0a9064fbSMasahiro Yamada 		if (modules_sym)
204*0a9064fbSMasahiro Yamada 			zconf_error("symbol '%s' redefines option 'modules'"
205*0a9064fbSMasahiro Yamada 				    " already defined by symbol '%s'",
206*0a9064fbSMasahiro Yamada 				    current_entry->sym->name,
207*0a9064fbSMasahiro Yamada 				    modules_sym->name
208*0a9064fbSMasahiro Yamada 				    );
209*0a9064fbSMasahiro Yamada 		modules_sym = current_entry->sym;
210*0a9064fbSMasahiro Yamada 		break;
211*0a9064fbSMasahiro Yamada 	case T_OPT_DEFCONFIG_LIST:
212*0a9064fbSMasahiro Yamada 		if (!sym_defconfig_list)
213*0a9064fbSMasahiro Yamada 			sym_defconfig_list = current_entry->sym;
214*0a9064fbSMasahiro Yamada 		else if (sym_defconfig_list != current_entry->sym)
215*0a9064fbSMasahiro Yamada 			zconf_error("trying to redefine defconfig symbol");
216*0a9064fbSMasahiro Yamada 		break;
217*0a9064fbSMasahiro Yamada 	case T_OPT_ENV:
218*0a9064fbSMasahiro Yamada 		prop_add_env(arg);
219*0a9064fbSMasahiro Yamada 		break;
220*0a9064fbSMasahiro Yamada 	case T_OPT_ALLNOCONFIG_Y:
221*0a9064fbSMasahiro Yamada 		current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
222*0a9064fbSMasahiro Yamada 		break;
223*0a9064fbSMasahiro Yamada 	}
224*0a9064fbSMasahiro Yamada }
225*0a9064fbSMasahiro Yamada 
226*0a9064fbSMasahiro Yamada static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
227*0a9064fbSMasahiro Yamada {
228*0a9064fbSMasahiro Yamada 	return sym2->type == S_INT || sym2->type == S_HEX ||
229*0a9064fbSMasahiro Yamada 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
230*0a9064fbSMasahiro Yamada }
231*0a9064fbSMasahiro Yamada 
232*0a9064fbSMasahiro Yamada static void sym_check_prop(struct symbol *sym)
233*0a9064fbSMasahiro Yamada {
234*0a9064fbSMasahiro Yamada 	struct property *prop;
235*0a9064fbSMasahiro Yamada 	struct symbol *sym2;
236*0a9064fbSMasahiro Yamada 	for (prop = sym->prop; prop; prop = prop->next) {
237*0a9064fbSMasahiro Yamada 		switch (prop->type) {
238*0a9064fbSMasahiro Yamada 		case P_DEFAULT:
239*0a9064fbSMasahiro Yamada 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
240*0a9064fbSMasahiro Yamada 			    prop->expr->type != E_SYMBOL)
241*0a9064fbSMasahiro Yamada 				prop_warn(prop,
242*0a9064fbSMasahiro Yamada 				    "default for config symbol '%s'"
243*0a9064fbSMasahiro Yamada 				    " must be a single symbol", sym->name);
244*0a9064fbSMasahiro Yamada 			if (prop->expr->type != E_SYMBOL)
245*0a9064fbSMasahiro Yamada 				break;
246*0a9064fbSMasahiro Yamada 			sym2 = prop_get_symbol(prop);
247*0a9064fbSMasahiro Yamada 			if (sym->type == S_HEX || sym->type == S_INT) {
248*0a9064fbSMasahiro Yamada 				if (!menu_validate_number(sym, sym2))
249*0a9064fbSMasahiro Yamada 					prop_warn(prop,
250*0a9064fbSMasahiro Yamada 					    "'%s': number is invalid",
251*0a9064fbSMasahiro Yamada 					    sym->name);
252*0a9064fbSMasahiro Yamada 			}
253*0a9064fbSMasahiro Yamada 			break;
254*0a9064fbSMasahiro Yamada 		case P_SELECT:
255*0a9064fbSMasahiro Yamada 			sym2 = prop_get_symbol(prop);
256*0a9064fbSMasahiro Yamada 			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
257*0a9064fbSMasahiro Yamada 				prop_warn(prop,
258*0a9064fbSMasahiro Yamada 				    "config symbol '%s' uses select, but is "
259*0a9064fbSMasahiro Yamada 				    "not boolean or tristate", sym->name);
260*0a9064fbSMasahiro Yamada 			else if (sym2->type != S_UNKNOWN &&
261*0a9064fbSMasahiro Yamada 				 sym2->type != S_BOOLEAN &&
262*0a9064fbSMasahiro Yamada 				 sym2->type != S_TRISTATE)
263*0a9064fbSMasahiro Yamada 				prop_warn(prop,
264*0a9064fbSMasahiro Yamada 				    "'%s' has wrong type. 'select' only "
265*0a9064fbSMasahiro Yamada 				    "accept arguments of boolean and "
266*0a9064fbSMasahiro Yamada 				    "tristate type", sym2->name);
267*0a9064fbSMasahiro Yamada 			break;
268*0a9064fbSMasahiro Yamada 		case P_RANGE:
269*0a9064fbSMasahiro Yamada 			if (sym->type != S_INT && sym->type != S_HEX)
270*0a9064fbSMasahiro Yamada 				prop_warn(prop, "range is only allowed "
271*0a9064fbSMasahiro Yamada 						"for int or hex symbols");
272*0a9064fbSMasahiro Yamada 			if (!menu_validate_number(sym, prop->expr->left.sym) ||
273*0a9064fbSMasahiro Yamada 			    !menu_validate_number(sym, prop->expr->right.sym))
274*0a9064fbSMasahiro Yamada 				prop_warn(prop, "range is invalid");
275*0a9064fbSMasahiro Yamada 			break;
276*0a9064fbSMasahiro Yamada 		default:
277*0a9064fbSMasahiro Yamada 			;
278*0a9064fbSMasahiro Yamada 		}
279*0a9064fbSMasahiro Yamada 	}
280*0a9064fbSMasahiro Yamada }
281*0a9064fbSMasahiro Yamada 
282*0a9064fbSMasahiro Yamada void menu_finalize(struct menu *parent)
283*0a9064fbSMasahiro Yamada {
284*0a9064fbSMasahiro Yamada 	struct menu *menu, *last_menu;
285*0a9064fbSMasahiro Yamada 	struct symbol *sym;
286*0a9064fbSMasahiro Yamada 	struct property *prop;
287*0a9064fbSMasahiro Yamada 	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
288*0a9064fbSMasahiro Yamada 
289*0a9064fbSMasahiro Yamada 	sym = parent->sym;
290*0a9064fbSMasahiro Yamada 	if (parent->list) {
291*0a9064fbSMasahiro Yamada 		if (sym && sym_is_choice(sym)) {
292*0a9064fbSMasahiro Yamada 			if (sym->type == S_UNKNOWN) {
293*0a9064fbSMasahiro Yamada 				/* find the first choice value to find out choice type */
294*0a9064fbSMasahiro Yamada 				current_entry = parent;
295*0a9064fbSMasahiro Yamada 				for (menu = parent->list; menu; menu = menu->next) {
296*0a9064fbSMasahiro Yamada 					if (menu->sym && menu->sym->type != S_UNKNOWN) {
297*0a9064fbSMasahiro Yamada 						menu_set_type(menu->sym->type);
298*0a9064fbSMasahiro Yamada 						break;
299*0a9064fbSMasahiro Yamada 					}
300*0a9064fbSMasahiro Yamada 				}
301*0a9064fbSMasahiro Yamada 			}
302*0a9064fbSMasahiro Yamada 			/* set the type of the remaining choice values */
303*0a9064fbSMasahiro Yamada 			for (menu = parent->list; menu; menu = menu->next) {
304*0a9064fbSMasahiro Yamada 				current_entry = menu;
305*0a9064fbSMasahiro Yamada 				if (menu->sym && menu->sym->type == S_UNKNOWN)
306*0a9064fbSMasahiro Yamada 					menu_set_type(sym->type);
307*0a9064fbSMasahiro Yamada 			}
308*0a9064fbSMasahiro Yamada 			parentdep = expr_alloc_symbol(sym);
309*0a9064fbSMasahiro Yamada 		} else if (parent->prompt)
310*0a9064fbSMasahiro Yamada 			parentdep = parent->prompt->visible.expr;
311*0a9064fbSMasahiro Yamada 		else
312*0a9064fbSMasahiro Yamada 			parentdep = parent->dep;
313*0a9064fbSMasahiro Yamada 
314*0a9064fbSMasahiro Yamada 		for (menu = parent->list; menu; menu = menu->next) {
315*0a9064fbSMasahiro Yamada 			basedep = expr_transform(menu->dep);
316*0a9064fbSMasahiro Yamada 			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
317*0a9064fbSMasahiro Yamada 			basedep = expr_eliminate_dups(basedep);
318*0a9064fbSMasahiro Yamada 			menu->dep = basedep;
319*0a9064fbSMasahiro Yamada 			if (menu->sym)
320*0a9064fbSMasahiro Yamada 				prop = menu->sym->prop;
321*0a9064fbSMasahiro Yamada 			else
322*0a9064fbSMasahiro Yamada 				prop = menu->prompt;
323*0a9064fbSMasahiro Yamada 			for (; prop; prop = prop->next) {
324*0a9064fbSMasahiro Yamada 				if (prop->menu != menu)
325*0a9064fbSMasahiro Yamada 					continue;
326*0a9064fbSMasahiro Yamada 				dep = expr_transform(prop->visible.expr);
327*0a9064fbSMasahiro Yamada 				dep = expr_alloc_and(expr_copy(basedep), dep);
328*0a9064fbSMasahiro Yamada 				dep = expr_eliminate_dups(dep);
329*0a9064fbSMasahiro Yamada 				if (menu->sym && menu->sym->type != S_TRISTATE)
330*0a9064fbSMasahiro Yamada 					dep = expr_trans_bool(dep);
331*0a9064fbSMasahiro Yamada 				prop->visible.expr = dep;
332*0a9064fbSMasahiro Yamada 				if (prop->type == P_SELECT) {
333*0a9064fbSMasahiro Yamada 					struct symbol *es = prop_get_symbol(prop);
334*0a9064fbSMasahiro Yamada 					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
335*0a9064fbSMasahiro Yamada 							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
336*0a9064fbSMasahiro Yamada 				}
337*0a9064fbSMasahiro Yamada 			}
338*0a9064fbSMasahiro Yamada 		}
339*0a9064fbSMasahiro Yamada 		for (menu = parent->list; menu; menu = menu->next)
340*0a9064fbSMasahiro Yamada 			menu_finalize(menu);
341*0a9064fbSMasahiro Yamada 	} else if (sym) {
342*0a9064fbSMasahiro Yamada 		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
343*0a9064fbSMasahiro Yamada 		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
344*0a9064fbSMasahiro Yamada 		basedep = expr_eliminate_dups(expr_transform(basedep));
345*0a9064fbSMasahiro Yamada 		last_menu = NULL;
346*0a9064fbSMasahiro Yamada 		for (menu = parent->next; menu; menu = menu->next) {
347*0a9064fbSMasahiro Yamada 			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
348*0a9064fbSMasahiro Yamada 			if (!expr_contains_symbol(dep, sym))
349*0a9064fbSMasahiro Yamada 				break;
350*0a9064fbSMasahiro Yamada 			if (expr_depends_symbol(dep, sym))
351*0a9064fbSMasahiro Yamada 				goto next;
352*0a9064fbSMasahiro Yamada 			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
353*0a9064fbSMasahiro Yamada 			dep = expr_eliminate_dups(expr_transform(dep));
354*0a9064fbSMasahiro Yamada 			dep2 = expr_copy(basedep);
355*0a9064fbSMasahiro Yamada 			expr_eliminate_eq(&dep, &dep2);
356*0a9064fbSMasahiro Yamada 			expr_free(dep);
357*0a9064fbSMasahiro Yamada 			if (!expr_is_yes(dep2)) {
358*0a9064fbSMasahiro Yamada 				expr_free(dep2);
359*0a9064fbSMasahiro Yamada 				break;
360*0a9064fbSMasahiro Yamada 			}
361*0a9064fbSMasahiro Yamada 			expr_free(dep2);
362*0a9064fbSMasahiro Yamada 		next:
363*0a9064fbSMasahiro Yamada 			menu_finalize(menu);
364*0a9064fbSMasahiro Yamada 			menu->parent = parent;
365*0a9064fbSMasahiro Yamada 			last_menu = menu;
366*0a9064fbSMasahiro Yamada 		}
367*0a9064fbSMasahiro Yamada 		if (last_menu) {
368*0a9064fbSMasahiro Yamada 			parent->list = parent->next;
369*0a9064fbSMasahiro Yamada 			parent->next = last_menu->next;
370*0a9064fbSMasahiro Yamada 			last_menu->next = NULL;
371*0a9064fbSMasahiro Yamada 		}
372*0a9064fbSMasahiro Yamada 
373*0a9064fbSMasahiro Yamada 		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
374*0a9064fbSMasahiro Yamada 	}
375*0a9064fbSMasahiro Yamada 	for (menu = parent->list; menu; menu = menu->next) {
376*0a9064fbSMasahiro Yamada 		if (sym && sym_is_choice(sym) &&
377*0a9064fbSMasahiro Yamada 		    menu->sym && !sym_is_choice_value(menu->sym)) {
378*0a9064fbSMasahiro Yamada 			current_entry = menu;
379*0a9064fbSMasahiro Yamada 			menu->sym->flags |= SYMBOL_CHOICEVAL;
380*0a9064fbSMasahiro Yamada 			if (!menu->prompt)
381*0a9064fbSMasahiro Yamada 				menu_warn(menu, "choice value must have a prompt");
382*0a9064fbSMasahiro Yamada 			for (prop = menu->sym->prop; prop; prop = prop->next) {
383*0a9064fbSMasahiro Yamada 				if (prop->type == P_DEFAULT)
384*0a9064fbSMasahiro Yamada 					prop_warn(prop, "defaults for choice "
385*0a9064fbSMasahiro Yamada 						  "values not supported");
386*0a9064fbSMasahiro Yamada 				if (prop->menu == menu)
387*0a9064fbSMasahiro Yamada 					continue;
388*0a9064fbSMasahiro Yamada 				if (prop->type == P_PROMPT &&
389*0a9064fbSMasahiro Yamada 				    prop->menu->parent->sym != sym)
390*0a9064fbSMasahiro Yamada 					prop_warn(prop, "choice value used outside its choice group");
391*0a9064fbSMasahiro Yamada 			}
392*0a9064fbSMasahiro Yamada 			/* Non-tristate choice values of tristate choices must
393*0a9064fbSMasahiro Yamada 			 * depend on the choice being set to Y. The choice
394*0a9064fbSMasahiro Yamada 			 * values' dependencies were propagated to their
395*0a9064fbSMasahiro Yamada 			 * properties above, so the change here must be re-
396*0a9064fbSMasahiro Yamada 			 * propagated.
397*0a9064fbSMasahiro Yamada 			 */
398*0a9064fbSMasahiro Yamada 			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
399*0a9064fbSMasahiro Yamada 				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
400*0a9064fbSMasahiro Yamada 				menu->dep = expr_alloc_and(basedep, menu->dep);
401*0a9064fbSMasahiro Yamada 				for (prop = menu->sym->prop; prop; prop = prop->next) {
402*0a9064fbSMasahiro Yamada 					if (prop->menu != menu)
403*0a9064fbSMasahiro Yamada 						continue;
404*0a9064fbSMasahiro Yamada 					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
405*0a9064fbSMasahiro Yamada 									    prop->visible.expr);
406*0a9064fbSMasahiro Yamada 				}
407*0a9064fbSMasahiro Yamada 			}
408*0a9064fbSMasahiro Yamada 			menu_add_symbol(P_CHOICE, sym, NULL);
409*0a9064fbSMasahiro Yamada 			prop = sym_get_choice_prop(sym);
410*0a9064fbSMasahiro Yamada 			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
411*0a9064fbSMasahiro Yamada 				;
412*0a9064fbSMasahiro Yamada 			*ep = expr_alloc_one(E_LIST, NULL);
413*0a9064fbSMasahiro Yamada 			(*ep)->right.sym = menu->sym;
414*0a9064fbSMasahiro Yamada 		}
415*0a9064fbSMasahiro Yamada 		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
416*0a9064fbSMasahiro Yamada 			for (last_menu = menu->list; ; last_menu = last_menu->next) {
417*0a9064fbSMasahiro Yamada 				last_menu->parent = parent;
418*0a9064fbSMasahiro Yamada 				if (!last_menu->next)
419*0a9064fbSMasahiro Yamada 					break;
420*0a9064fbSMasahiro Yamada 			}
421*0a9064fbSMasahiro Yamada 			last_menu->next = menu->next;
422*0a9064fbSMasahiro Yamada 			menu->next = menu->list;
423*0a9064fbSMasahiro Yamada 			menu->list = NULL;
424*0a9064fbSMasahiro Yamada 		}
425*0a9064fbSMasahiro Yamada 	}
426*0a9064fbSMasahiro Yamada 
427*0a9064fbSMasahiro Yamada 	if (sym && !(sym->flags & SYMBOL_WARNED)) {
428*0a9064fbSMasahiro Yamada 		if (sym->type == S_UNKNOWN)
429*0a9064fbSMasahiro Yamada 			menu_warn(parent, "config symbol defined without type");
430*0a9064fbSMasahiro Yamada 
431*0a9064fbSMasahiro Yamada 		if (sym_is_choice(sym) && !parent->prompt)
432*0a9064fbSMasahiro Yamada 			menu_warn(parent, "choice must have a prompt");
433*0a9064fbSMasahiro Yamada 
434*0a9064fbSMasahiro Yamada 		/* Check properties connected to this symbol */
435*0a9064fbSMasahiro Yamada 		sym_check_prop(sym);
436*0a9064fbSMasahiro Yamada 		sym->flags |= SYMBOL_WARNED;
437*0a9064fbSMasahiro Yamada 	}
438*0a9064fbSMasahiro Yamada 
439*0a9064fbSMasahiro Yamada 	if (sym && !sym_is_optional(sym) && parent->prompt) {
440*0a9064fbSMasahiro Yamada 		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
441*0a9064fbSMasahiro Yamada 				expr_alloc_and(parent->prompt->visible.expr,
442*0a9064fbSMasahiro Yamada 					expr_alloc_symbol(&symbol_mod)));
443*0a9064fbSMasahiro Yamada 	}
444*0a9064fbSMasahiro Yamada }
445*0a9064fbSMasahiro Yamada 
446*0a9064fbSMasahiro Yamada bool menu_has_prompt(struct menu *menu)
447*0a9064fbSMasahiro Yamada {
448*0a9064fbSMasahiro Yamada 	if (!menu->prompt)
449*0a9064fbSMasahiro Yamada 		return false;
450*0a9064fbSMasahiro Yamada 	return true;
451*0a9064fbSMasahiro Yamada }
452*0a9064fbSMasahiro Yamada 
453*0a9064fbSMasahiro Yamada /*
454*0a9064fbSMasahiro Yamada  * Determine if a menu is empty.
455*0a9064fbSMasahiro Yamada  * A menu is considered empty if it contains no or only
456*0a9064fbSMasahiro Yamada  * invisible entries.
457*0a9064fbSMasahiro Yamada  */
458*0a9064fbSMasahiro Yamada bool menu_is_empty(struct menu *menu)
459*0a9064fbSMasahiro Yamada {
460*0a9064fbSMasahiro Yamada 	struct menu *child;
461*0a9064fbSMasahiro Yamada 
462*0a9064fbSMasahiro Yamada 	for (child = menu->list; child; child = child->next) {
463*0a9064fbSMasahiro Yamada 		if (menu_is_visible(child))
464*0a9064fbSMasahiro Yamada 			return(false);
465*0a9064fbSMasahiro Yamada 	}
466*0a9064fbSMasahiro Yamada 	return(true);
467*0a9064fbSMasahiro Yamada }
468*0a9064fbSMasahiro Yamada 
469*0a9064fbSMasahiro Yamada bool menu_is_visible(struct menu *menu)
470*0a9064fbSMasahiro Yamada {
471*0a9064fbSMasahiro Yamada 	struct menu *child;
472*0a9064fbSMasahiro Yamada 	struct symbol *sym;
473*0a9064fbSMasahiro Yamada 	tristate visible;
474*0a9064fbSMasahiro Yamada 
475*0a9064fbSMasahiro Yamada 	if (!menu->prompt)
476*0a9064fbSMasahiro Yamada 		return false;
477*0a9064fbSMasahiro Yamada 
478*0a9064fbSMasahiro Yamada 	if (menu->visibility) {
479*0a9064fbSMasahiro Yamada 		if (expr_calc_value(menu->visibility) == no)
480*0a9064fbSMasahiro Yamada 			return no;
481*0a9064fbSMasahiro Yamada 	}
482*0a9064fbSMasahiro Yamada 
483*0a9064fbSMasahiro Yamada 	sym = menu->sym;
484*0a9064fbSMasahiro Yamada 	if (sym) {
485*0a9064fbSMasahiro Yamada 		sym_calc_value(sym);
486*0a9064fbSMasahiro Yamada 		visible = menu->prompt->visible.tri;
487*0a9064fbSMasahiro Yamada 	} else
488*0a9064fbSMasahiro Yamada 		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
489*0a9064fbSMasahiro Yamada 
490*0a9064fbSMasahiro Yamada 	if (visible != no)
491*0a9064fbSMasahiro Yamada 		return true;
492*0a9064fbSMasahiro Yamada 
493*0a9064fbSMasahiro Yamada 	if (!sym || sym_get_tristate_value(menu->sym) == no)
494*0a9064fbSMasahiro Yamada 		return false;
495*0a9064fbSMasahiro Yamada 
496*0a9064fbSMasahiro Yamada 	for (child = menu->list; child; child = child->next) {
497*0a9064fbSMasahiro Yamada 		if (menu_is_visible(child)) {
498*0a9064fbSMasahiro Yamada 			if (sym)
499*0a9064fbSMasahiro Yamada 				sym->flags |= SYMBOL_DEF_USER;
500*0a9064fbSMasahiro Yamada 			return true;
501*0a9064fbSMasahiro Yamada 		}
502*0a9064fbSMasahiro Yamada 	}
503*0a9064fbSMasahiro Yamada 
504*0a9064fbSMasahiro Yamada 	return false;
505*0a9064fbSMasahiro Yamada }
506*0a9064fbSMasahiro Yamada 
507*0a9064fbSMasahiro Yamada const char *menu_get_prompt(struct menu *menu)
508*0a9064fbSMasahiro Yamada {
509*0a9064fbSMasahiro Yamada 	if (menu->prompt)
510*0a9064fbSMasahiro Yamada 		return menu->prompt->text;
511*0a9064fbSMasahiro Yamada 	else if (menu->sym)
512*0a9064fbSMasahiro Yamada 		return menu->sym->name;
513*0a9064fbSMasahiro Yamada 	return NULL;
514*0a9064fbSMasahiro Yamada }
515*0a9064fbSMasahiro Yamada 
516*0a9064fbSMasahiro Yamada struct menu *menu_get_root_menu(struct menu *menu)
517*0a9064fbSMasahiro Yamada {
518*0a9064fbSMasahiro Yamada 	return &rootmenu;
519*0a9064fbSMasahiro Yamada }
520*0a9064fbSMasahiro Yamada 
521*0a9064fbSMasahiro Yamada struct menu *menu_get_parent_menu(struct menu *menu)
522*0a9064fbSMasahiro Yamada {
523*0a9064fbSMasahiro Yamada 	enum prop_type type;
524*0a9064fbSMasahiro Yamada 
525*0a9064fbSMasahiro Yamada 	for (; menu != &rootmenu; menu = menu->parent) {
526*0a9064fbSMasahiro Yamada 		type = menu->prompt ? menu->prompt->type : 0;
527*0a9064fbSMasahiro Yamada 		if (type == P_MENU)
528*0a9064fbSMasahiro Yamada 			break;
529*0a9064fbSMasahiro Yamada 	}
530*0a9064fbSMasahiro Yamada 	return menu;
531*0a9064fbSMasahiro Yamada }
532*0a9064fbSMasahiro Yamada 
533*0a9064fbSMasahiro Yamada bool menu_has_help(struct menu *menu)
534*0a9064fbSMasahiro Yamada {
535*0a9064fbSMasahiro Yamada 	return menu->help != NULL;
536*0a9064fbSMasahiro Yamada }
537*0a9064fbSMasahiro Yamada 
538*0a9064fbSMasahiro Yamada const char *menu_get_help(struct menu *menu)
539*0a9064fbSMasahiro Yamada {
540*0a9064fbSMasahiro Yamada 	if (menu->help)
541*0a9064fbSMasahiro Yamada 		return menu->help;
542*0a9064fbSMasahiro Yamada 	else
543*0a9064fbSMasahiro Yamada 		return "";
544*0a9064fbSMasahiro Yamada }
545*0a9064fbSMasahiro Yamada 
546*0a9064fbSMasahiro Yamada static void get_prompt_str(struct gstr *r, struct property *prop,
547*0a9064fbSMasahiro Yamada 			   struct list_head *head)
548*0a9064fbSMasahiro Yamada {
549*0a9064fbSMasahiro Yamada 	int i, j;
550*0a9064fbSMasahiro Yamada 	struct menu *submenu[8], *menu, *location = NULL;
551*0a9064fbSMasahiro Yamada 	struct jump_key *jump;
552*0a9064fbSMasahiro Yamada 
553*0a9064fbSMasahiro Yamada 	str_printf(r, _("Prompt: %s\n"), _(prop->text));
554*0a9064fbSMasahiro Yamada 	menu = prop->menu->parent;
555*0a9064fbSMasahiro Yamada 	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
556*0a9064fbSMasahiro Yamada 		bool accessible = menu_is_visible(menu);
557*0a9064fbSMasahiro Yamada 
558*0a9064fbSMasahiro Yamada 		submenu[i++] = menu;
559*0a9064fbSMasahiro Yamada 		if (location == NULL && accessible)
560*0a9064fbSMasahiro Yamada 			location = menu;
561*0a9064fbSMasahiro Yamada 	}
562*0a9064fbSMasahiro Yamada 	if (head && location) {
563*0a9064fbSMasahiro Yamada 		jump = xmalloc(sizeof(struct jump_key));
564*0a9064fbSMasahiro Yamada 
565*0a9064fbSMasahiro Yamada 		if (menu_is_visible(prop->menu)) {
566*0a9064fbSMasahiro Yamada 			/*
567*0a9064fbSMasahiro Yamada 			 * There is not enough room to put the hint at the
568*0a9064fbSMasahiro Yamada 			 * beginning of the "Prompt" line. Put the hint on the
569*0a9064fbSMasahiro Yamada 			 * last "Location" line even when it would belong on
570*0a9064fbSMasahiro Yamada 			 * the former.
571*0a9064fbSMasahiro Yamada 			 */
572*0a9064fbSMasahiro Yamada 			jump->target = prop->menu;
573*0a9064fbSMasahiro Yamada 		} else
574*0a9064fbSMasahiro Yamada 			jump->target = location;
575*0a9064fbSMasahiro Yamada 
576*0a9064fbSMasahiro Yamada 		if (list_empty(head))
577*0a9064fbSMasahiro Yamada 			jump->index = 0;
578*0a9064fbSMasahiro Yamada 		else
579*0a9064fbSMasahiro Yamada 			jump->index = list_entry(head->prev, struct jump_key,
580*0a9064fbSMasahiro Yamada 						 entries)->index + 1;
581*0a9064fbSMasahiro Yamada 
582*0a9064fbSMasahiro Yamada 		list_add_tail(&jump->entries, head);
583*0a9064fbSMasahiro Yamada 	}
584*0a9064fbSMasahiro Yamada 
585*0a9064fbSMasahiro Yamada 	if (i > 0) {
586*0a9064fbSMasahiro Yamada 		str_printf(r, _("  Location:\n"));
587*0a9064fbSMasahiro Yamada 		for (j = 4; --i >= 0; j += 2) {
588*0a9064fbSMasahiro Yamada 			menu = submenu[i];
589*0a9064fbSMasahiro Yamada 			if (head && location && menu == location)
590*0a9064fbSMasahiro Yamada 				jump->offset = strlen(r->s);
591*0a9064fbSMasahiro Yamada 			str_printf(r, "%*c-> %s", j, ' ',
592*0a9064fbSMasahiro Yamada 				   _(menu_get_prompt(menu)));
593*0a9064fbSMasahiro Yamada 			if (menu->sym) {
594*0a9064fbSMasahiro Yamada 				str_printf(r, " (%s [=%s])", menu->sym->name ?
595*0a9064fbSMasahiro Yamada 					menu->sym->name : _("<choice>"),
596*0a9064fbSMasahiro Yamada 					sym_get_string_value(menu->sym));
597*0a9064fbSMasahiro Yamada 			}
598*0a9064fbSMasahiro Yamada 			str_append(r, "\n");
599*0a9064fbSMasahiro Yamada 		}
600*0a9064fbSMasahiro Yamada 	}
601*0a9064fbSMasahiro Yamada }
602*0a9064fbSMasahiro Yamada 
603*0a9064fbSMasahiro Yamada /*
604*0a9064fbSMasahiro Yamada  * get property of type P_SYMBOL
605*0a9064fbSMasahiro Yamada  */
606*0a9064fbSMasahiro Yamada static struct property *get_symbol_prop(struct symbol *sym)
607*0a9064fbSMasahiro Yamada {
608*0a9064fbSMasahiro Yamada 	struct property *prop = NULL;
609*0a9064fbSMasahiro Yamada 
610*0a9064fbSMasahiro Yamada 	for_all_properties(sym, prop, P_SYMBOL)
611*0a9064fbSMasahiro Yamada 		break;
612*0a9064fbSMasahiro Yamada 	return prop;
613*0a9064fbSMasahiro Yamada }
614*0a9064fbSMasahiro Yamada 
615*0a9064fbSMasahiro Yamada /*
616*0a9064fbSMasahiro Yamada  * head is optional and may be NULL
617*0a9064fbSMasahiro Yamada  */
618*0a9064fbSMasahiro Yamada void get_symbol_str(struct gstr *r, struct symbol *sym,
619*0a9064fbSMasahiro Yamada 		    struct list_head *head)
620*0a9064fbSMasahiro Yamada {
621*0a9064fbSMasahiro Yamada 	bool hit;
622*0a9064fbSMasahiro Yamada 	struct property *prop;
623*0a9064fbSMasahiro Yamada 
624*0a9064fbSMasahiro Yamada 	if (sym && sym->name) {
625*0a9064fbSMasahiro Yamada 		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
626*0a9064fbSMasahiro Yamada 			   sym_get_string_value(sym));
627*0a9064fbSMasahiro Yamada 		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
628*0a9064fbSMasahiro Yamada 		if (sym->type == S_INT || sym->type == S_HEX) {
629*0a9064fbSMasahiro Yamada 			prop = sym_get_range_prop(sym);
630*0a9064fbSMasahiro Yamada 			if (prop) {
631*0a9064fbSMasahiro Yamada 				str_printf(r, "Range : ");
632*0a9064fbSMasahiro Yamada 				expr_gstr_print(prop->expr, r);
633*0a9064fbSMasahiro Yamada 				str_append(r, "\n");
634*0a9064fbSMasahiro Yamada 			}
635*0a9064fbSMasahiro Yamada 		}
636*0a9064fbSMasahiro Yamada 	}
637*0a9064fbSMasahiro Yamada 	for_all_prompts(sym, prop)
638*0a9064fbSMasahiro Yamada 		get_prompt_str(r, prop, head);
639*0a9064fbSMasahiro Yamada 
640*0a9064fbSMasahiro Yamada 	prop = get_symbol_prop(sym);
641*0a9064fbSMasahiro Yamada 	if (prop) {
642*0a9064fbSMasahiro Yamada 		str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
643*0a9064fbSMasahiro Yamada 			prop->menu->lineno);
644*0a9064fbSMasahiro Yamada 		if (!expr_is_yes(prop->visible.expr)) {
645*0a9064fbSMasahiro Yamada 			str_append(r, _("  Depends on: "));
646*0a9064fbSMasahiro Yamada 			expr_gstr_print(prop->visible.expr, r);
647*0a9064fbSMasahiro Yamada 			str_append(r, "\n");
648*0a9064fbSMasahiro Yamada 		}
649*0a9064fbSMasahiro Yamada 	}
650*0a9064fbSMasahiro Yamada 
651*0a9064fbSMasahiro Yamada 	hit = false;
652*0a9064fbSMasahiro Yamada 	for_all_properties(sym, prop, P_SELECT) {
653*0a9064fbSMasahiro Yamada 		if (!hit) {
654*0a9064fbSMasahiro Yamada 			str_append(r, "  Selects: ");
655*0a9064fbSMasahiro Yamada 			hit = true;
656*0a9064fbSMasahiro Yamada 		} else
657*0a9064fbSMasahiro Yamada 			str_printf(r, " && ");
658*0a9064fbSMasahiro Yamada 		expr_gstr_print(prop->expr, r);
659*0a9064fbSMasahiro Yamada 	}
660*0a9064fbSMasahiro Yamada 	if (hit)
661*0a9064fbSMasahiro Yamada 		str_append(r, "\n");
662*0a9064fbSMasahiro Yamada 	if (sym->rev_dep.expr) {
663*0a9064fbSMasahiro Yamada 		str_append(r, _("  Selected by: "));
664*0a9064fbSMasahiro Yamada 		expr_gstr_print(sym->rev_dep.expr, r);
665*0a9064fbSMasahiro Yamada 		str_append(r, "\n");
666*0a9064fbSMasahiro Yamada 	}
667*0a9064fbSMasahiro Yamada 	str_append(r, "\n\n");
668*0a9064fbSMasahiro Yamada }
669*0a9064fbSMasahiro Yamada 
670*0a9064fbSMasahiro Yamada struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
671*0a9064fbSMasahiro Yamada {
672*0a9064fbSMasahiro Yamada 	struct symbol *sym;
673*0a9064fbSMasahiro Yamada 	struct gstr res = str_new();
674*0a9064fbSMasahiro Yamada 	int i;
675*0a9064fbSMasahiro Yamada 
676*0a9064fbSMasahiro Yamada 	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
677*0a9064fbSMasahiro Yamada 		get_symbol_str(&res, sym, head);
678*0a9064fbSMasahiro Yamada 	if (!i)
679*0a9064fbSMasahiro Yamada 		str_append(&res, _("No matches found.\n"));
680*0a9064fbSMasahiro Yamada 	return res;
681*0a9064fbSMasahiro Yamada }
682*0a9064fbSMasahiro Yamada 
683*0a9064fbSMasahiro Yamada 
684*0a9064fbSMasahiro Yamada void menu_get_ext_help(struct menu *menu, struct gstr *help)
685*0a9064fbSMasahiro Yamada {
686*0a9064fbSMasahiro Yamada 	struct symbol *sym = menu->sym;
687*0a9064fbSMasahiro Yamada 	const char *help_text = nohelp_text;
688*0a9064fbSMasahiro Yamada 
689*0a9064fbSMasahiro Yamada 	if (menu_has_help(menu)) {
690*0a9064fbSMasahiro Yamada 		if (sym->name)
691*0a9064fbSMasahiro Yamada 			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
692*0a9064fbSMasahiro Yamada 		help_text = menu_get_help(menu);
693*0a9064fbSMasahiro Yamada 	}
694*0a9064fbSMasahiro Yamada 	str_printf(help, "%s\n", _(help_text));
695*0a9064fbSMasahiro Yamada 	if (sym)
696*0a9064fbSMasahiro Yamada 		get_symbol_str(help, sym, NULL);
697*0a9064fbSMasahiro Yamada }
698