• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4  */
5 
6 #include <ctype.h>
7 #include <stdarg.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "lkc.h"
12 
13 static const char nohelp_text[] = "There is no help available for this option.";
14 
15 struct menu rootmenu;
16 static struct menu **last_entry_ptr;
17 
18 struct file *file_list;
19 struct file *current_file;
20 
menu_warn(struct menu * menu,const char * fmt,...)21 void menu_warn(struct menu *menu, const char *fmt, ...)
22 {
23 	va_list ap;
24 	va_start(ap, fmt);
25 	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
26 	vfprintf(stderr, fmt, ap);
27 	fprintf(stderr, "\n");
28 	va_end(ap);
29 }
30 
prop_warn(struct property * prop,const char * fmt,...)31 static void prop_warn(struct property *prop, const char *fmt, ...)
32 {
33 	va_list ap;
34 	va_start(ap, fmt);
35 	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
36 	vfprintf(stderr, fmt, ap);
37 	fprintf(stderr, "\n");
38 	va_end(ap);
39 }
40 
_menu_init(void)41 void _menu_init(void)
42 {
43 	current_entry = current_menu = &rootmenu;
44 	last_entry_ptr = &rootmenu.list;
45 }
46 
menu_add_entry(struct symbol * sym)47 void menu_add_entry(struct symbol *sym)
48 {
49 	struct menu *menu;
50 
51 	menu = xmalloc(sizeof(*menu));
52 	memset(menu, 0, sizeof(*menu));
53 	menu->sym = sym;
54 	menu->parent = current_menu;
55 	menu->file = current_file;
56 	menu->lineno = zconf_lineno();
57 
58 	*last_entry_ptr = menu;
59 	last_entry_ptr = &menu->next;
60 	current_entry = menu;
61 	if (sym)
62 		menu_add_symbol(P_SYMBOL, sym, NULL);
63 }
64 
menu_add_menu(void)65 struct menu *menu_add_menu(void)
66 {
67 	last_entry_ptr = &current_entry->list;
68 	current_menu = current_entry;
69 	return current_menu;
70 }
71 
menu_end_menu(void)72 void menu_end_menu(void)
73 {
74 	last_entry_ptr = &current_menu->next;
75 	current_menu = current_menu->parent;
76 }
77 
78 /*
79  * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
80  * without modules
81  */
rewrite_m(struct expr * e)82 static struct expr *rewrite_m(struct expr *e)
83 {
84 	if (!e)
85 		return e;
86 
87 	switch (e->type) {
88 	case E_NOT:
89 		e->left.expr = rewrite_m(e->left.expr);
90 		break;
91 	case E_OR:
92 	case E_AND:
93 		e->left.expr = rewrite_m(e->left.expr);
94 		e->right.expr = rewrite_m(e->right.expr);
95 		break;
96 	case E_SYMBOL:
97 		/* change 'm' into 'm' && MODULES */
98 		if (e->left.sym == &symbol_mod)
99 			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
100 		break;
101 	default:
102 		break;
103 	}
104 	return e;
105 }
106 
menu_add_dep(struct expr * dep)107 void menu_add_dep(struct expr *dep)
108 {
109 	current_entry->dep = expr_alloc_and(current_entry->dep, dep);
110 }
111 
menu_set_type(int type)112 void menu_set_type(int type)
113 {
114 	struct symbol *sym = current_entry->sym;
115 
116 	if (sym->type == type)
117 		return;
118 	if (sym->type == S_UNKNOWN) {
119 		sym->type = type;
120 		return;
121 	}
122 	menu_warn(current_entry,
123 		"ignoring type redefinition of '%s' from '%s' to '%s'",
124 		sym->name ? sym->name : "<choice>",
125 		sym_type_name(sym->type), sym_type_name(type));
126 }
127 
menu_add_prop(enum prop_type type,struct expr * expr,struct expr * dep)128 static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
129 				      struct expr *dep)
130 {
131 	struct property *prop;
132 
133 	prop = xmalloc(sizeof(*prop));
134 	memset(prop, 0, sizeof(*prop));
135 	prop->type = type;
136 	prop->file = current_file;
137 	prop->lineno = zconf_lineno();
138 	prop->menu = current_entry;
139 	prop->expr = expr;
140 	prop->visible.expr = dep;
141 
142 	/* append property to the prop list of symbol */
143 	if (current_entry->sym) {
144 		struct property **propp;
145 
146 		for (propp = &current_entry->sym->prop;
147 		     *propp;
148 		     propp = &(*propp)->next)
149 			;
150 		*propp = prop;
151 	}
152 
153 	return prop;
154 }
155 
menu_add_prompt(enum prop_type type,char * prompt,struct expr * dep)156 struct property *menu_add_prompt(enum prop_type type, char *prompt,
157 				 struct expr *dep)
158 {
159 	struct property *prop = menu_add_prop(type, NULL, dep);
160 
161 	if (isspace(*prompt)) {
162 		prop_warn(prop, "leading whitespace ignored");
163 		while (isspace(*prompt))
164 			prompt++;
165 	}
166 	if (current_entry->prompt)
167 		prop_warn(prop, "prompt redefined");
168 
169 	/* Apply all upper menus' visibilities to actual prompts. */
170 	if (type == P_PROMPT) {
171 		struct menu *menu = current_entry;
172 
173 		while ((menu = menu->parent) != NULL) {
174 			struct expr *dup_expr;
175 
176 			if (!menu->visibility)
177 				continue;
178 			/*
179 			 * Do not add a reference to the menu's visibility
180 			 * expression but use a copy of it. Otherwise the
181 			 * expression reduction functions will modify
182 			 * expressions that have multiple references which
183 			 * can cause unwanted side effects.
184 			 */
185 			dup_expr = expr_copy(menu->visibility);
186 
187 			prop->visible.expr = expr_alloc_and(prop->visible.expr,
188 							    dup_expr);
189 		}
190 	}
191 
192 	current_entry->prompt = prop;
193 	prop->text = prompt;
194 
195 	return prop;
196 }
197 
menu_add_visibility(struct expr * expr)198 void menu_add_visibility(struct expr *expr)
199 {
200 	current_entry->visibility = expr_alloc_and(current_entry->visibility,
201 	    expr);
202 }
203 
menu_add_expr(enum prop_type type,struct expr * expr,struct expr * dep)204 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
205 {
206 	menu_add_prop(type, expr, dep);
207 }
208 
menu_add_symbol(enum prop_type type,struct symbol * sym,struct expr * dep)209 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
210 {
211 	menu_add_prop(type, expr_alloc_symbol(sym), dep);
212 }
213 
menu_add_option_modules(void)214 void menu_add_option_modules(void)
215 {
216 	if (modules_sym)
217 		zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
218 			    current_entry->sym->name, modules_sym->name);
219 	modules_sym = current_entry->sym;
220 }
221 
menu_add_option_defconfig_list(void)222 void menu_add_option_defconfig_list(void)
223 {
224 	if (!sym_defconfig_list)
225 		sym_defconfig_list = current_entry->sym;
226 	else if (sym_defconfig_list != current_entry->sym)
227 		zconf_error("trying to redefine defconfig symbol");
228 	sym_defconfig_list->flags |= SYMBOL_NO_WRITE;
229 }
230 
menu_add_option_allnoconfig_y(void)231 void menu_add_option_allnoconfig_y(void)
232 {
233 	current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
234 }
235 
menu_validate_number(struct symbol * sym,struct symbol * sym2)236 static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
237 {
238 	return sym2->type == S_INT || sym2->type == S_HEX ||
239 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
240 }
241 
sym_check_prop(struct symbol * sym)242 static void sym_check_prop(struct symbol *sym)
243 {
244 	struct property *prop;
245 	struct symbol *sym2;
246 	char *use;
247 
248 	for (prop = sym->prop; prop; prop = prop->next) {
249 		switch (prop->type) {
250 		case P_DEFAULT:
251 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
252 			    prop->expr->type != E_SYMBOL)
253 				prop_warn(prop,
254 				    "default for config symbol '%s'"
255 				    " must be a single symbol", sym->name);
256 			if (prop->expr->type != E_SYMBOL)
257 				break;
258 			sym2 = prop_get_symbol(prop);
259 			if (sym->type == S_HEX || sym->type == S_INT) {
260 				if (!menu_validate_number(sym, sym2))
261 					prop_warn(prop,
262 					    "'%s': number is invalid",
263 					    sym->name);
264 			}
265 			if (sym_is_choice(sym)) {
266 				struct property *choice_prop =
267 					sym_get_choice_prop(sym2);
268 
269 				if (!choice_prop ||
270 				    prop_get_symbol(choice_prop) != sym)
271 					prop_warn(prop,
272 						  "choice default symbol '%s' is not contained in the choice",
273 						  sym2->name);
274 			}
275 			break;
276 		case P_SELECT:
277 		case P_IMPLY:
278 			use = prop->type == P_SELECT ? "select" : "imply";
279 			sym2 = prop_get_symbol(prop);
280 			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
281 				prop_warn(prop,
282 				    "config symbol '%s' uses %s, but is "
283 				    "not bool or tristate", sym->name, use);
284 			else if (sym2->type != S_UNKNOWN &&
285 				 sym2->type != S_BOOLEAN &&
286 				 sym2->type != S_TRISTATE)
287 				prop_warn(prop,
288 				    "'%s' has wrong type. '%s' only "
289 				    "accept arguments of bool and "
290 				    "tristate type", sym2->name, use);
291 			break;
292 		case P_RANGE:
293 			if (sym->type != S_INT && sym->type != S_HEX)
294 				prop_warn(prop, "range is only allowed "
295 						"for int or hex symbols");
296 			if (!menu_validate_number(sym, prop->expr->left.sym) ||
297 			    !menu_validate_number(sym, prop->expr->right.sym))
298 				prop_warn(prop, "range is invalid");
299 			break;
300 		default:
301 			;
302 		}
303 	}
304 }
305 
menu_finalize(struct menu * parent)306 void menu_finalize(struct menu *parent)
307 {
308 	struct menu *menu, *last_menu;
309 	struct symbol *sym;
310 	struct property *prop;
311 	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
312 
313 	sym = parent->sym;
314 	if (parent->list) {
315 		/*
316 		 * This menu node has children. We (recursively) process them
317 		 * and propagate parent dependencies before moving on.
318 		 */
319 
320 		if (sym && sym_is_choice(sym)) {
321 			if (sym->type == S_UNKNOWN) {
322 				/* find the first choice value to find out choice type */
323 				current_entry = parent;
324 				for (menu = parent->list; menu; menu = menu->next) {
325 					if (menu->sym && menu->sym->type != S_UNKNOWN) {
326 						menu_set_type(menu->sym->type);
327 						break;
328 					}
329 				}
330 			}
331 			/* set the type of the remaining choice values */
332 			for (menu = parent->list; menu; menu = menu->next) {
333 				current_entry = menu;
334 				if (menu->sym && menu->sym->type == S_UNKNOWN)
335 					menu_set_type(sym->type);
336 			}
337 
338 			/*
339 			 * Use the choice itself as the parent dependency of
340 			 * the contained items. This turns the mode of the
341 			 * choice into an upper bound on the visibility of the
342 			 * choice value symbols.
343 			 */
344 			parentdep = expr_alloc_symbol(sym);
345 		} else {
346 			/* Menu node for 'menu', 'if' */
347 			parentdep = parent->dep;
348 		}
349 
350 		/* For each child menu node... */
351 		for (menu = parent->list; menu; menu = menu->next) {
352 			/*
353 			 * Propagate parent dependencies to the child menu
354 			 * node, also rewriting and simplifying expressions
355 			 */
356 			basedep = rewrite_m(menu->dep);
357 			basedep = expr_transform(basedep);
358 			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
359 			basedep = expr_eliminate_dups(basedep);
360 			menu->dep = basedep;
361 
362 			if (menu->sym)
363 				/*
364 				 * Note: For symbols, all prompts are included
365 				 * too in the symbol's own property list
366 				 */
367 				prop = menu->sym->prop;
368 			else
369 				/*
370 				 * For non-symbol menu nodes, we just need to
371 				 * handle the prompt
372 				 */
373 				prop = menu->prompt;
374 
375 			/* For each property... */
376 			for (; prop; prop = prop->next) {
377 				if (prop->menu != menu)
378 					/*
379 					 * Two possibilities:
380 					 *
381 					 * 1. The property lacks dependencies
382 					 *    and so isn't location-specific,
383 					 *    e.g. an 'option'
384 					 *
385 					 * 2. The property belongs to a symbol
386 					 *    defined in multiple locations and
387 					 *    is from some other location. It
388 					 *    will be handled there in that
389 					 *    case.
390 					 *
391 					 * Skip the property.
392 					 */
393 					continue;
394 
395 				/*
396 				 * Propagate parent dependencies to the
397 				 * property's condition, rewriting and
398 				 * simplifying expressions at the same time
399 				 */
400 				dep = rewrite_m(prop->visible.expr);
401 				dep = expr_transform(dep);
402 				dep = expr_alloc_and(expr_copy(basedep), dep);
403 				dep = expr_eliminate_dups(dep);
404 				if (menu->sym && menu->sym->type != S_TRISTATE)
405 					dep = expr_trans_bool(dep);
406 				prop->visible.expr = dep;
407 
408 				/*
409 				 * Handle selects and implies, which modify the
410 				 * dependencies of the selected/implied symbol
411 				 */
412 				if (prop->type == P_SELECT) {
413 					struct symbol *es = prop_get_symbol(prop);
414 					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
415 							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
416 				} else if (prop->type == P_IMPLY) {
417 					struct symbol *es = prop_get_symbol(prop);
418 					es->implied.expr = expr_alloc_or(es->implied.expr,
419 							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
420 				}
421 			}
422 		}
423 
424 		if (sym && sym_is_choice(sym))
425 			expr_free(parentdep);
426 
427 		/*
428 		 * Recursively process children in the same fashion before
429 		 * moving on
430 		 */
431 		for (menu = parent->list; menu; menu = menu->next)
432 			menu_finalize(menu);
433 	} else if (sym) {
434 		/*
435 		 * Automatic submenu creation. If sym is a symbol and A, B, C,
436 		 * ... are consecutive items (symbols, menus, ifs, etc.) that
437 		 * all depend on sym, then the following menu structure is
438 		 * created:
439 		 *
440 		 *	sym
441 		 *	 +-A
442 		 *	 +-B
443 		 *	 +-C
444 		 *	 ...
445 		 *
446 		 * This also works recursively, giving the following structure
447 		 * if A is a symbol and B depends on A:
448 		 *
449 		 *	sym
450 		 *	 +-A
451 		 *	 | +-B
452 		 *	 +-C
453 		 *	 ...
454 		 */
455 
456 		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
457 		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
458 		basedep = expr_eliminate_dups(expr_transform(basedep));
459 
460 		/* Examine consecutive elements after sym */
461 		last_menu = NULL;
462 		for (menu = parent->next; menu; menu = menu->next) {
463 			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
464 			if (!expr_contains_symbol(dep, sym))
465 				/* No dependency, quit */
466 				break;
467 			if (expr_depends_symbol(dep, sym))
468 				/* Absolute dependency, put in submenu */
469 				goto next;
470 
471 			/*
472 			 * Also consider it a dependency on sym if our
473 			 * dependencies contain sym and are a "superset" of
474 			 * sym's dependencies, e.g. '(sym || Q) && R' when sym
475 			 * depends on R.
476 			 *
477 			 * Note that 'R' might be from an enclosing menu or if,
478 			 * making this a more common case than it might seem.
479 			 */
480 			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
481 			dep = expr_eliminate_dups(expr_transform(dep));
482 			dep2 = expr_copy(basedep);
483 			expr_eliminate_eq(&dep, &dep2);
484 			expr_free(dep);
485 			if (!expr_is_yes(dep2)) {
486 				/* Not superset, quit */
487 				expr_free(dep2);
488 				break;
489 			}
490 			/* Superset, put in submenu */
491 			expr_free(dep2);
492 		next:
493 			menu_finalize(menu);
494 			menu->parent = parent;
495 			last_menu = menu;
496 		}
497 		expr_free(basedep);
498 		if (last_menu) {
499 			parent->list = parent->next;
500 			parent->next = last_menu->next;
501 			last_menu->next = NULL;
502 		}
503 
504 		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
505 	}
506 	for (menu = parent->list; menu; menu = menu->next) {
507 		if (sym && sym_is_choice(sym) &&
508 		    menu->sym && !sym_is_choice_value(menu->sym)) {
509 			current_entry = menu;
510 			menu->sym->flags |= SYMBOL_CHOICEVAL;
511 			if (!menu->prompt)
512 				menu_warn(menu, "choice value must have a prompt");
513 			for (prop = menu->sym->prop; prop; prop = prop->next) {
514 				if (prop->type == P_DEFAULT)
515 					prop_warn(prop, "defaults for choice "
516 						  "values not supported");
517 				if (prop->menu == menu)
518 					continue;
519 				if (prop->type == P_PROMPT &&
520 				    prop->menu->parent->sym != sym)
521 					prop_warn(prop, "choice value used outside its choice group");
522 			}
523 			/* Non-tristate choice values of tristate choices must
524 			 * depend on the choice being set to Y. The choice
525 			 * values' dependencies were propagated to their
526 			 * properties above, so the change here must be re-
527 			 * propagated.
528 			 */
529 			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
530 				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
531 				menu->dep = expr_alloc_and(basedep, menu->dep);
532 				for (prop = menu->sym->prop; prop; prop = prop->next) {
533 					if (prop->menu != menu)
534 						continue;
535 					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
536 									    prop->visible.expr);
537 				}
538 			}
539 			menu_add_symbol(P_CHOICE, sym, NULL);
540 			prop = sym_get_choice_prop(sym);
541 			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
542 				;
543 			*ep = expr_alloc_one(E_LIST, NULL);
544 			(*ep)->right.sym = menu->sym;
545 		}
546 
547 		/*
548 		 * This code serves two purposes:
549 		 *
550 		 * (1) Flattening 'if' blocks, which do not specify a submenu
551 		 *     and only add dependencies.
552 		 *
553 		 *     (Automatic submenu creation might still create a submenu
554 		 *     from an 'if' before this code runs.)
555 		 *
556 		 * (2) "Undoing" any automatic submenus created earlier below
557 		 *     promptless symbols.
558 		 *
559 		 * Before:
560 		 *
561 		 *	A
562 		 *	if ... (or promptless symbol)
563 		 *	 +-B
564 		 *	 +-C
565 		 *	D
566 		 *
567 		 * After:
568 		 *
569 		 *	A
570 		 *	if ... (or promptless symbol)
571 		 *	B
572 		 *	C
573 		 *	D
574 		 */
575 		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
576 			for (last_menu = menu->list; ; last_menu = last_menu->next) {
577 				last_menu->parent = parent;
578 				if (!last_menu->next)
579 					break;
580 			}
581 			last_menu->next = menu->next;
582 			menu->next = menu->list;
583 			menu->list = NULL;
584 		}
585 	}
586 
587 	if (sym && !(sym->flags & SYMBOL_WARNED)) {
588 		if (sym->type == S_UNKNOWN)
589 			menu_warn(parent, "config symbol defined without type");
590 
591 		if (sym_is_choice(sym) && !parent->prompt)
592 			menu_warn(parent, "choice must have a prompt");
593 
594 		/* Check properties connected to this symbol */
595 		sym_check_prop(sym);
596 		sym->flags |= SYMBOL_WARNED;
597 	}
598 
599 	/*
600 	 * For non-optional choices, add a reverse dependency (corresponding to
601 	 * a select) of '<visibility> && m'. This prevents the user from
602 	 * setting the choice mode to 'n' when the choice is visible.
603 	 *
604 	 * This would also work for non-choice symbols, but only non-optional
605 	 * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented
606 	 * as a type of symbol.
607 	 */
608 	if (sym && !sym_is_optional(sym) && parent->prompt) {
609 		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
610 				expr_alloc_and(parent->prompt->visible.expr,
611 					expr_alloc_symbol(&symbol_mod)));
612 	}
613 }
614 
menu_has_prompt(struct menu * menu)615 bool menu_has_prompt(struct menu *menu)
616 {
617 	if (!menu->prompt)
618 		return false;
619 	return true;
620 }
621 
622 /*
623  * Determine if a menu is empty.
624  * A menu is considered empty if it contains no or only
625  * invisible entries.
626  */
menu_is_empty(struct menu * menu)627 bool menu_is_empty(struct menu *menu)
628 {
629 	struct menu *child;
630 
631 	for (child = menu->list; child; child = child->next) {
632 		if (menu_is_visible(child))
633 			return(false);
634 	}
635 	return(true);
636 }
637 
menu_is_visible(struct menu * menu)638 bool menu_is_visible(struct menu *menu)
639 {
640 	struct menu *child;
641 	struct symbol *sym;
642 	tristate visible;
643 
644 	if (!menu->prompt)
645 		return false;
646 
647 	if (menu->visibility) {
648 		if (expr_calc_value(menu->visibility) == no)
649 			return false;
650 	}
651 
652 	sym = menu->sym;
653 	if (sym) {
654 		sym_calc_value(sym);
655 		visible = menu->prompt->visible.tri;
656 	} else
657 		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
658 
659 	if (visible != no)
660 		return true;
661 
662 	if (!sym || sym_get_tristate_value(menu->sym) == no)
663 		return false;
664 
665 	for (child = menu->list; child; child = child->next) {
666 		if (menu_is_visible(child)) {
667 			if (sym)
668 				sym->flags |= SYMBOL_DEF_USER;
669 			return true;
670 		}
671 	}
672 
673 	return false;
674 }
675 
menu_get_prompt(struct menu * menu)676 const char *menu_get_prompt(struct menu *menu)
677 {
678 	if (menu->prompt)
679 		return menu->prompt->text;
680 	else if (menu->sym)
681 		return menu->sym->name;
682 	return NULL;
683 }
684 
menu_get_root_menu(struct menu * menu)685 struct menu *menu_get_root_menu(struct menu *menu)
686 {
687 	return &rootmenu;
688 }
689 
menu_get_parent_menu(struct menu * menu)690 struct menu *menu_get_parent_menu(struct menu *menu)
691 {
692 	enum prop_type type;
693 
694 	for (; menu != &rootmenu; menu = menu->parent) {
695 		type = menu->prompt ? menu->prompt->type : 0;
696 		if (type == P_MENU)
697 			break;
698 	}
699 	return menu;
700 }
701 
menu_has_help(struct menu * menu)702 bool menu_has_help(struct menu *menu)
703 {
704 	return menu->help != NULL;
705 }
706 
menu_get_help(struct menu * menu)707 const char *menu_get_help(struct menu *menu)
708 {
709 	if (menu->help)
710 		return menu->help;
711 	else
712 		return "";
713 }
714 
get_def_str(struct gstr * r,struct menu * menu)715 static void get_def_str(struct gstr *r, struct menu *menu)
716 {
717 	str_printf(r, "Defined at %s:%d\n",
718 		   menu->file->name, menu->lineno);
719 }
720 
get_dep_str(struct gstr * r,struct expr * expr,const char * prefix)721 static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
722 {
723 	if (!expr_is_yes(expr)) {
724 		str_append(r, prefix);
725 		expr_gstr_print(expr, r);
726 		str_append(r, "\n");
727 	}
728 }
729 
get_prompt_str(struct gstr * r,struct property * prop,struct list_head * head)730 static void get_prompt_str(struct gstr *r, struct property *prop,
731 			   struct list_head *head)
732 {
733 	int i, j;
734 	struct menu *submenu[8], *menu, *location = NULL;
735 	struct jump_key *jump = NULL;
736 
737 	str_printf(r, "  Prompt: %s\n", prop->text);
738 
739 	get_dep_str(r, prop->menu->dep, "  Depends on: ");
740 	/*
741 	 * Most prompts in Linux have visibility that exactly matches their
742 	 * dependencies. For these, we print only the dependencies to improve
743 	 * readability. However, prompts with inline "if" expressions and
744 	 * prompts with a parent that has a "visible if" expression have
745 	 * differing dependencies and visibility. In these rare cases, we
746 	 * print both.
747 	 */
748 	if (!expr_eq(prop->menu->dep, prop->visible.expr))
749 		get_dep_str(r, prop->visible.expr, "  Visible if: ");
750 
751 	menu = prop->menu->parent;
752 	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
753 		bool accessible = menu_is_visible(menu);
754 
755 		submenu[i++] = menu;
756 		if (location == NULL && accessible)
757 			location = menu;
758 	}
759 	if (head && location) {
760 		jump = xmalloc(sizeof(struct jump_key));
761 
762 		if (menu_is_visible(prop->menu)) {
763 			/*
764 			 * There is not enough room to put the hint at the
765 			 * beginning of the "Prompt" line. Put the hint on the
766 			 * last "Location" line even when it would belong on
767 			 * the former.
768 			 */
769 			jump->target = prop->menu;
770 		} else
771 			jump->target = location;
772 
773 		if (list_empty(head))
774 			jump->index = 0;
775 		else
776 			jump->index = list_entry(head->prev, struct jump_key,
777 						 entries)->index + 1;
778 
779 		list_add_tail(&jump->entries, head);
780 	}
781 
782 	if (i > 0) {
783 		str_printf(r, "  Location:\n");
784 		for (j = 4; --i >= 0; j += 2) {
785 			menu = submenu[i];
786 			if (jump && menu == location)
787 				jump->offset = strlen(r->s);
788 			str_printf(r, "%*c-> %s", j, ' ',
789 				   menu_get_prompt(menu));
790 			if (menu->sym) {
791 				str_printf(r, " (%s [=%s])", menu->sym->name ?
792 					menu->sym->name : "<choice>",
793 					sym_get_string_value(menu->sym));
794 			}
795 			str_append(r, "\n");
796 		}
797 	}
798 }
799 
get_symbol_props_str(struct gstr * r,struct symbol * sym,enum prop_type tok,const char * prefix)800 static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
801 				 enum prop_type tok, const char *prefix)
802 {
803 	bool hit = false;
804 	struct property *prop;
805 
806 	for_all_properties(sym, prop, tok) {
807 		if (!hit) {
808 			str_append(r, prefix);
809 			hit = true;
810 		} else
811 			str_printf(r, " && ");
812 		expr_gstr_print(prop->expr, r);
813 	}
814 	if (hit)
815 		str_append(r, "\n");
816 }
817 
818 /*
819  * head is optional and may be NULL
820  */
get_symbol_str(struct gstr * r,struct symbol * sym,struct list_head * head)821 static void get_symbol_str(struct gstr *r, struct symbol *sym,
822 		    struct list_head *head)
823 {
824 	struct property *prop;
825 
826 	if (sym && sym->name) {
827 		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
828 			   sym_get_string_value(sym));
829 		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
830 		if (sym->type == S_INT || sym->type == S_HEX) {
831 			prop = sym_get_range_prop(sym);
832 			if (prop) {
833 				str_printf(r, "Range : ");
834 				expr_gstr_print(prop->expr, r);
835 				str_append(r, "\n");
836 			}
837 		}
838 	}
839 
840 	/* Print the definitions with prompts before the ones without */
841 	for_all_properties(sym, prop, P_SYMBOL) {
842 		if (prop->menu->prompt) {
843 			get_def_str(r, prop->menu);
844 			get_prompt_str(r, prop->menu->prompt, head);
845 		}
846 	}
847 
848 	for_all_properties(sym, prop, P_SYMBOL) {
849 		if (!prop->menu->prompt) {
850 			get_def_str(r, prop->menu);
851 			get_dep_str(r, prop->menu->dep, "  Depends on: ");
852 		}
853 	}
854 
855 	get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
856 	if (sym->rev_dep.expr) {
857 		expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n");
858 		expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n");
859 		expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n");
860 	}
861 
862 	get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
863 	if (sym->implied.expr) {
864 		expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n");
865 		expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n");
866 		expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n");
867 	}
868 
869 	str_append(r, "\n\n");
870 }
871 
get_relations_str(struct symbol ** sym_arr,struct list_head * head)872 struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
873 {
874 	struct symbol *sym;
875 	struct gstr res = str_new();
876 	int i;
877 
878 	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
879 		get_symbol_str(&res, sym, head);
880 	if (!i)
881 		str_append(&res, "No matches found.\n");
882 	return res;
883 }
884 
885 
menu_get_ext_help(struct menu * menu,struct gstr * help)886 void menu_get_ext_help(struct menu *menu, struct gstr *help)
887 {
888 	struct symbol *sym = menu->sym;
889 	const char *help_text = nohelp_text;
890 
891 	if (menu_has_help(menu)) {
892 		if (sym->name)
893 			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
894 		help_text = menu_get_help(menu);
895 	}
896 	str_printf(help, "%s\n", help_text);
897 	if (sym)
898 		get_symbol_str(help, sym, NULL);
899 }
900