kconfig/menu.c
author "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
Mon Apr 16 15:25:36 2012 +0200 (2012-04-16)
changeset 2941 13e40098fffc
parent 2451 d83221161129
permissions -rw-r--r--
cc/gcc: update Linaro GCC revisions to 2012.04

Update Linaro GCC with the latest available revisions.

The 4.7 revision is also released, but the infrastructure is not yet ready for
it in CT-NG.

Signed-off-by: "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
     1 /*
     2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
     3  * Released under the terms of the GNU GPL v2.0.
     4  */
     5 
     6 #include <stdlib.h>
     7 #include <string.h>
     8 
     9 #define LKC_DIRECT_LINK
    10 #include "lkc.h"
    11 
    12 static const char nohelp_text[] = N_(
    13 	"There is no help available for this option.\n");
    14 
    15 struct menu rootmenu;
    16 static struct menu **last_entry_ptr;
    17 
    18 struct file *file_list;
    19 struct file *current_file;
    20 
    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 
    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 
    41 void _menu_init(void)
    42 {
    43 	current_entry = current_menu = &rootmenu;
    44 	last_entry_ptr = &rootmenu.list;
    45 }
    46 
    47 void menu_add_entry(struct symbol *sym)
    48 {
    49 	struct menu *menu;
    50 
    51 	menu = malloc(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 
    65 void menu_end_entry(void)
    66 {
    67 }
    68 
    69 struct menu *menu_add_menu(void)
    70 {
    71 	menu_end_entry();
    72 	last_entry_ptr = &current_entry->list;
    73 	return current_menu = current_entry;
    74 }
    75 
    76 void menu_end_menu(void)
    77 {
    78 	last_entry_ptr = &current_menu->next;
    79 	current_menu = current_menu->parent;
    80 }
    81 
    82 static struct expr *menu_check_dep(struct expr *e)
    83 {
    84 	if (!e)
    85 		return e;
    86 
    87 	switch (e->type) {
    88 	case E_NOT:
    89 		e->left.expr = menu_check_dep(e->left.expr);
    90 		break;
    91 	case E_OR:
    92 	case E_AND:
    93 		e->left.expr = menu_check_dep(e->left.expr);
    94 		e->right.expr = menu_check_dep(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 
   107 void menu_add_dep(struct expr *dep)
   108 {
   109 	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
   110 }
   111 
   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, "type of '%s' redefined from '%s' to '%s'",
   123 	    sym->name ? sym->name : "<choice>",
   124 	    sym_type_name(sym->type), sym_type_name(type));
   125 }
   126 
   127 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
   128 {
   129 	struct property *prop = prop_alloc(type, current_entry->sym);
   130 
   131 	prop->menu = current_entry;
   132 	prop->expr = expr;
   133 	prop->visible.expr = menu_check_dep(dep);
   134 
   135 	if (prompt) {
   136 		/* For crostool-NG, a leading pipe followed with spaces
   137 		 * means that pipe shall be removed, and the spaces should
   138 		 * not be trimmed.
   139 		 */
   140 		if (*prompt == '|')
   141 			prompt++;
   142 		else if (isspace(*prompt)) {
   143 			prop_warn(prop, "leading whitespace ignored");
   144 			while (isspace(*prompt))
   145 				prompt++;
   146 		}
   147 		if (current_entry->prompt && current_entry != &rootmenu)
   148 			prop_warn(prop, "prompt redefined");
   149 
   150 		/* Apply all upper menus' visibilities to actual prompts. */
   151 		if(type == P_PROMPT) {
   152 			struct menu *menu = current_entry;
   153 
   154 			while ((menu = menu->parent) != NULL) {
   155 				if (!menu->visibility)
   156 					continue;
   157 				prop->visible.expr
   158 					= expr_alloc_and(prop->visible.expr,
   159 							 menu->visibility);
   160 			}
   161 		}
   162 
   163 		current_entry->prompt = prop;
   164 	}
   165 	prop->text = prompt;
   166 
   167 	return prop;
   168 }
   169 
   170 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
   171 {
   172 	return menu_add_prop(type, prompt, NULL, dep);
   173 }
   174 
   175 void menu_add_visibility(struct expr *expr)
   176 {
   177 	current_entry->visibility = expr_alloc_and(current_entry->visibility,
   178 	    expr);
   179 }
   180 
   181 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
   182 {
   183 	menu_add_prop(type, NULL, expr, dep);
   184 }
   185 
   186 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
   187 {
   188 	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
   189 }
   190 
   191 void menu_add_option(int token, char *arg)
   192 {
   193 	struct property *prop;
   194 
   195 	switch (token) {
   196 	case T_OPT_MODULES:
   197 		prop = prop_alloc(P_DEFAULT, modules_sym);
   198 		prop->expr = expr_alloc_symbol(current_entry->sym);
   199 		break;
   200 	case T_OPT_DEFCONFIG_LIST:
   201 		if (!sym_defconfig_list)
   202 			sym_defconfig_list = current_entry->sym;
   203 		else if (sym_defconfig_list != current_entry->sym)
   204 			zconf_error("trying to redefine defconfig symbol");
   205 		break;
   206 	case T_OPT_ENV:
   207 		prop_add_env(arg);
   208 		break;
   209 	}
   210 }
   211 
   212 static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
   213 {
   214 	return sym2->type == S_INT || sym2->type == S_HEX ||
   215 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
   216 }
   217 
   218 static void sym_check_prop(struct symbol *sym)
   219 {
   220 	struct property *prop;
   221 	struct symbol *sym2;
   222 	for (prop = sym->prop; prop; prop = prop->next) {
   223 		switch (prop->type) {
   224 		case P_DEFAULT:
   225 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
   226 			    prop->expr->type != E_SYMBOL)
   227 				prop_warn(prop,
   228 				    "default for config symbol '%s'"
   229 				    " must be a single symbol", sym->name);
   230 			if (prop->expr->type != E_SYMBOL)
   231 				break;
   232 			sym2 = prop_get_symbol(prop);
   233 			if (sym->type == S_HEX || sym->type == S_INT) {
   234 				if (!menu_validate_number(sym, sym2))
   235 					prop_warn(prop,
   236 					    "'%s': number is invalid",
   237 					    sym->name);
   238 			}
   239 			break;
   240 		case P_SELECT:
   241 			sym2 = prop_get_symbol(prop);
   242 			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
   243 				prop_warn(prop,
   244 				    "config symbol '%s' uses select, but is "
   245 				    "not boolean or tristate", sym->name);
   246 			else if (sym2->type != S_UNKNOWN &&
   247 			         sym2->type != S_BOOLEAN &&
   248 			         sym2->type != S_TRISTATE)
   249 				prop_warn(prop,
   250 				    "'%s' has wrong type. 'select' only "
   251 				    "accept arguments of boolean and "
   252 				    "tristate type", sym2->name);
   253 			break;
   254 		case P_RANGE:
   255 			if (sym->type != S_INT && sym->type != S_HEX)
   256 				prop_warn(prop, "range is only allowed "
   257 				                "for int or hex symbols");
   258 			if (!menu_validate_number(sym, prop->expr->left.sym) ||
   259 			    !menu_validate_number(sym, prop->expr->right.sym))
   260 				prop_warn(prop, "range is invalid");
   261 			break;
   262 		default:
   263 			;
   264 		}
   265 	}
   266 }
   267 
   268 void menu_finalize(struct menu *parent)
   269 {
   270 	struct menu *menu, *last_menu;
   271 	struct symbol *sym;
   272 	struct property *prop;
   273 	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
   274 
   275 	sym = parent->sym;
   276 	if (parent->list) {
   277 		if (sym && sym_is_choice(sym)) {
   278 			if (sym->type == S_UNKNOWN) {
   279 				/* find the first choice value to find out choice type */
   280 				current_entry = parent;
   281 				for (menu = parent->list; menu; menu = menu->next) {
   282 					if (menu->sym && menu->sym->type != S_UNKNOWN) {
   283 						menu_set_type(menu->sym->type);
   284 						break;
   285 					}
   286 				}
   287 			}
   288 			if (parent->prompt &&
   289 			    !expr_is_yes(parent->prompt->visible.expr)) {
   290 				parent->visibility = expr_alloc_and (parent->visibility,
   291 								     parent->prompt->visible.expr);
   292 			}
   293 			/* set the type of the remaining choice values */
   294 			for (menu = parent->list; menu; menu = menu->next) {
   295 				current_entry = menu;
   296 				if (menu->sym && menu->sym->type == S_UNKNOWN)
   297 					menu_set_type(sym->type);
   298 			}
   299 			parentdep = expr_alloc_symbol(sym);
   300 		} else if (parent->prompt)
   301 			parentdep = parent->prompt->visible.expr;
   302 		else
   303 			parentdep = parent->dep;
   304 
   305 		for (menu = parent->list; menu; menu = menu->next) {
   306 			basedep = expr_transform(menu->dep);
   307 			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
   308 			basedep = expr_eliminate_dups(basedep);
   309 			menu->dep = basedep;
   310 			if (menu->sym)
   311 				prop = menu->sym->prop;
   312 			else
   313 				prop = menu->prompt;
   314 			for (; prop; prop = prop->next) {
   315 				if (prop->menu != menu)
   316 					continue;
   317 				dep = expr_transform(prop->visible.expr);
   318 				dep = expr_alloc_and(expr_copy(basedep), dep);
   319 				dep = expr_eliminate_dups(dep);
   320 				if (menu->sym && menu->sym->type != S_TRISTATE)
   321 					dep = expr_trans_bool(dep);
   322 				prop->visible.expr = dep;
   323 				if (prop->type == P_SELECT) {
   324 					struct symbol *es = prop_get_symbol(prop);
   325 					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
   326 							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
   327 				}
   328 			}
   329 		}
   330 		for (menu = parent->list; menu; menu = menu->next)
   331 			menu_finalize(menu);
   332 	} else if (sym) {
   333 		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
   334 		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
   335 		basedep = expr_eliminate_dups(expr_transform(basedep));
   336 		last_menu = NULL;
   337 		for (menu = parent->next; menu; menu = menu->next) {
   338 			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
   339 			if (!expr_contains_symbol(dep, sym))
   340 				break;
   341 			if (expr_depends_symbol(dep, sym))
   342 				goto next;
   343 			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
   344 			dep = expr_eliminate_dups(expr_transform(dep));
   345 			dep2 = expr_copy(basedep);
   346 			expr_eliminate_eq(&dep, &dep2);
   347 			expr_free(dep);
   348 			if (!expr_is_yes(dep2)) {
   349 				expr_free(dep2);
   350 				break;
   351 			}
   352 			expr_free(dep2);
   353 		next:
   354 			menu_finalize(menu);
   355 			menu->parent = parent;
   356 			last_menu = menu;
   357 		}
   358 		if (last_menu) {
   359 			parent->list = parent->next;
   360 			parent->next = last_menu->next;
   361 			last_menu->next = NULL;
   362 		}
   363 
   364 		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
   365 	}
   366 	for (menu = parent->list; menu; menu = menu->next) {
   367 		if (sym && sym_is_choice(sym) &&
   368 		    menu->sym && !sym_is_choice_value(menu->sym)) {
   369 			current_entry = menu;
   370 			menu->sym->flags |= SYMBOL_CHOICEVAL;
   371 			if (!menu->prompt)
   372 				menu_warn(menu, "choice value must have a prompt");
   373 			for (prop = menu->sym->prop; prop; prop = prop->next) {
   374 				if (prop->type == P_DEFAULT)
   375 					prop_warn(prop, "defaults for choice "
   376 						  "values not supported");
   377 				if (prop->menu == menu)
   378 					continue;
   379 				if (prop->type == P_PROMPT &&
   380 				    prop->menu->parent->sym != sym)
   381 					prop_warn(prop, "choice value used outside its choice group");
   382 			}
   383 			/* Non-tristate choice values of tristate choices must
   384 			 * depend on the choice being set to Y. The choice
   385 			 * values' dependencies were propagated to their
   386 			 * properties above, so the change here must be re-
   387 			 * propagated.
   388 			 */
   389 			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
   390 				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
   391 				menu->dep = expr_alloc_and(basedep, menu->dep);
   392 				for (prop = menu->sym->prop; prop; prop = prop->next) {
   393 					if (prop->menu != menu)
   394 						continue;
   395 					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
   396 									    prop->visible.expr);
   397 				}
   398 			}
   399 			menu_add_symbol(P_CHOICE, sym, NULL);
   400 			prop = sym_get_choice_prop(sym);
   401 			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
   402 				;
   403 			*ep = expr_alloc_one(E_LIST, NULL);
   404 			(*ep)->right.sym = menu->sym;
   405 		}
   406 		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
   407 			for (last_menu = menu->list; ; last_menu = last_menu->next) {
   408 				last_menu->parent = parent;
   409 				if (!last_menu->next)
   410 					break;
   411 			}
   412 			last_menu->next = menu->next;
   413 			menu->next = menu->list;
   414 			menu->list = NULL;
   415 		}
   416 	}
   417 
   418 	if (sym && !(sym->flags & SYMBOL_WARNED)) {
   419 		if (sym->type == S_UNKNOWN)
   420 			menu_warn(parent, "config symbol defined without type");
   421 
   422 		if (sym_is_choice(sym) && !parent->prompt)
   423 			menu_warn(parent, "choice must have a prompt");
   424 
   425 		/* Check properties connected to this symbol */
   426 		sym_check_prop(sym);
   427 		sym->flags |= SYMBOL_WARNED;
   428 	}
   429 
   430 	if (sym && !sym_is_optional(sym) && parent->prompt) {
   431 		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
   432 				expr_alloc_and(parent->prompt->visible.expr,
   433 					expr_alloc_symbol(&symbol_mod)));
   434 	}
   435 }
   436 
   437 bool menu_has_prompt(struct menu *menu)
   438 {
   439 	if (!menu->prompt)
   440 		return false;
   441 	return true;
   442 }
   443 
   444 bool menu_is_visible(struct menu *menu)
   445 {
   446 	struct menu *child;
   447 	struct symbol *sym;
   448 	tristate visible;
   449 
   450 	if (!menu->prompt)
   451 		return false;
   452 
   453 	if (menu->visibility) {
   454 		if (expr_calc_value(menu->visibility) == no)
   455 			return no;
   456 	}
   457 
   458 	sym = menu->sym;
   459 	if (sym) {
   460 		sym_calc_value(sym);
   461 		visible = menu->prompt->visible.tri;
   462 	} else
   463 		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
   464 
   465 	if (visible != no)
   466 		return true;
   467 
   468 	if (!sym || sym_get_tristate_value(menu->sym) == no)
   469 		return false;
   470 
   471 	for (child = menu->list; child; child = child->next) {
   472 		if (menu_is_visible(child)) {
   473 			if (sym)
   474 				sym->flags |= SYMBOL_DEF_USER;
   475 			return true;
   476 		}
   477 	}
   478 
   479 	return false;
   480 }
   481 
   482 const char *menu_get_prompt(struct menu *menu)
   483 {
   484 	if (menu->prompt)
   485 		return menu->prompt->text;
   486 	else if (menu->sym)
   487 		return menu->sym->name;
   488 	return NULL;
   489 }
   490 
   491 struct menu *menu_get_root_menu(struct menu *menu)
   492 {
   493 	return &rootmenu;
   494 }
   495 
   496 struct menu *menu_get_parent_menu(struct menu *menu)
   497 {
   498 	enum prop_type type;
   499 
   500 	for (; menu != &rootmenu; menu = menu->parent) {
   501 		type = menu->prompt ? menu->prompt->type : 0;
   502 		if (type == P_MENU)
   503 			break;
   504 	}
   505 	return menu;
   506 }
   507 
   508 bool menu_has_help(struct menu *menu)
   509 {
   510 	return menu->help != NULL;
   511 }
   512 
   513 const char *menu_get_help(struct menu *menu)
   514 {
   515 	if (menu->help)
   516 		return menu->help;
   517 	else
   518 		return "";
   519 }
   520 
   521 static void get_prompt_str(struct gstr *r, struct property *prop)
   522 {
   523 	int i, j;
   524 	struct menu *submenu[8], *menu;
   525 
   526 	str_printf(r, _("Prompt: %s\n"), _(prop->text));
   527 	str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
   528 		prop->menu->lineno);
   529 	if (!expr_is_yes(prop->visible.expr)) {
   530 		str_append(r, _("  Depends on: "));
   531 		expr_gstr_print(prop->visible.expr, r);
   532 		str_append(r, "\n");
   533 	}
   534 	menu = prop->menu->parent;
   535 	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
   536 		submenu[i++] = menu;
   537 	if (i > 0) {
   538 		str_printf(r, _("  Location:\n"));
   539 		for (j = 4; --i >= 0; j += 2) {
   540 			menu = submenu[i];
   541 			str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
   542 			if (menu->sym) {
   543 				str_printf(r, " (%s [=%s])", menu->sym->name ?
   544 					menu->sym->name : _("<choice>"),
   545 					sym_get_string_value(menu->sym));
   546 			}
   547 			str_append(r, "\n");
   548 		}
   549 	}
   550 }
   551 
   552 void get_symbol_str(struct gstr *r, struct symbol *sym)
   553 {
   554 	bool hit;
   555 	struct property *prop;
   556 
   557 	if (sym && sym->name) {
   558 		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
   559 			   sym_get_string_value(sym));
   560 		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
   561 		if (sym->type == S_INT || sym->type == S_HEX) {
   562 			prop = sym_get_range_prop(sym);
   563 			if (prop) {
   564 				str_printf(r, "Range : ");
   565 				expr_gstr_print(prop->expr, r);
   566 				str_append(r, "\n");
   567 			}
   568 		}
   569 	}
   570 	for_all_prompts(sym, prop)
   571 		get_prompt_str(r, prop);
   572 	hit = false;
   573 	for_all_properties(sym, prop, P_SELECT) {
   574 		if (!hit) {
   575 			str_append(r, "  Selects: ");
   576 			hit = true;
   577 		} else
   578 			str_printf(r, " && ");
   579 		expr_gstr_print(prop->expr, r);
   580 	}
   581 	if (hit)
   582 		str_append(r, "\n");
   583 	if (sym->rev_dep.expr) {
   584 		str_append(r, _("  Selected by: "));
   585 		expr_gstr_print(sym->rev_dep.expr, r);
   586 		str_append(r, "\n");
   587 	}
   588 	str_append(r, "\n\n");
   589 }
   590 
   591 struct gstr get_relations_str(struct symbol **sym_arr)
   592 {
   593 	struct symbol *sym;
   594 	struct gstr res = str_new();
   595 	int i;
   596 
   597 	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
   598 		get_symbol_str(&res, sym);
   599 	if (!i)
   600 		str_append(&res, _("No matches found.\n"));
   601 	return res;
   602 }
   603 
   604 
   605 void menu_get_ext_help(struct menu *menu, struct gstr *help)
   606 {
   607 	struct symbol *sym = menu->sym;
   608 
   609 	if (menu_has_help(menu)) {
   610 		if (sym->name) {
   611 			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
   612 			str_append(help, _(menu_get_help(menu)));
   613 			str_append(help, "\n");
   614 		}
   615 	} else {
   616 		str_append(help, nohelp_text);
   617 	}
   618 	if (sym)
   619 		get_symbol_str(help, sym);
   620 }