kconfig/menu.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Feb 17 22:08:06 2008 +0000 (2008-02-17)
changeset 431 8bde4c6ea47a
child 943 1cca90ce0481
permissions -rw-r--r--
Robert P. J. DAY says:

apparently, the patchset for gcc 4.2.1 applies properly to the
source for gcc 4.2.2 and gcc 4.2.3. so, if you want, you can simply
add support for those last two just by augmenting menuconfig and
adding a couple symlinks for those two directories. seems like a
cheap way to add a couple new versions.
     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 struct menu rootmenu;
    13 static struct menu **last_entry_ptr;
    14 
    15 struct file *file_list;
    16 struct file *current_file;
    17 
    18 static void menu_warn(struct menu *menu, const char *fmt, ...)
    19 {
    20 	va_list ap;
    21 	va_start(ap, fmt);
    22 	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
    23 	vfprintf(stderr, fmt, ap);
    24 	fprintf(stderr, "\n");
    25 	va_end(ap);
    26 }
    27 
    28 static void prop_warn(struct property *prop, const char *fmt, ...)
    29 {
    30 	va_list ap;
    31 	va_start(ap, fmt);
    32 	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
    33 	vfprintf(stderr, fmt, ap);
    34 	fprintf(stderr, "\n");
    35 	va_end(ap);
    36 }
    37 
    38 void menu_init(void)
    39 {
    40 	current_entry = current_menu = &rootmenu;
    41 	last_entry_ptr = &rootmenu.list;
    42 }
    43 
    44 void menu_add_entry(struct symbol *sym)
    45 {
    46 	struct menu *menu;
    47 
    48 	menu = malloc(sizeof(*menu));
    49 	memset(menu, 0, sizeof(*menu));
    50 	menu->sym = sym;
    51 	menu->parent = current_menu;
    52 	menu->file = current_file;
    53 	menu->lineno = zconf_lineno();
    54 
    55 	*last_entry_ptr = menu;
    56 	last_entry_ptr = &menu->next;
    57 	current_entry = menu;
    58 }
    59 
    60 void menu_end_entry(void)
    61 {
    62 }
    63 
    64 struct menu *menu_add_menu(void)
    65 {
    66 	menu_end_entry();
    67 	last_entry_ptr = &current_entry->list;
    68 	return current_menu = current_entry;
    69 }
    70 
    71 void menu_end_menu(void)
    72 {
    73 	last_entry_ptr = &current_menu->next;
    74 	current_menu = current_menu->parent;
    75 }
    76 
    77 struct expr *menu_check_dep(struct expr *e)
    78 {
    79 	if (!e)
    80 		return e;
    81 
    82 	switch (e->type) {
    83 	case E_NOT:
    84 		e->left.expr = menu_check_dep(e->left.expr);
    85 		break;
    86 	case E_OR:
    87 	case E_AND:
    88 		e->left.expr = menu_check_dep(e->left.expr);
    89 		e->right.expr = menu_check_dep(e->right.expr);
    90 		break;
    91 	case E_SYMBOL:
    92 		/* change 'm' into 'm' && MODULES */
    93 		if (e->left.sym == &symbol_mod)
    94 			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
    95 		break;
    96 	default:
    97 		break;
    98 	}
    99 	return e;
   100 }
   101 
   102 void menu_add_dep(struct expr *dep)
   103 {
   104 	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
   105 }
   106 
   107 void menu_set_type(int type)
   108 {
   109 	struct symbol *sym = current_entry->sym;
   110 
   111 	if (sym->type == type)
   112 		return;
   113 	if (sym->type == S_UNKNOWN) {
   114 		sym->type = type;
   115 		return;
   116 	}
   117 	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
   118 	    sym->name ? sym->name : "<choice>",
   119 	    sym_type_name(sym->type), sym_type_name(type));
   120 }
   121 
   122 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
   123 {
   124 	struct property *prop = prop_alloc(type, current_entry->sym);
   125 
   126 	prop->menu = current_entry;
   127 	prop->expr = expr;
   128 	prop->visible.expr = menu_check_dep(dep);
   129 
   130 	if (prompt) {
   131 		if (isspace(*prompt)) {
   132 			prop_warn(prop, "leading whitespace ignored");
   133 			while (isspace(*prompt))
   134 				prompt++;
   135 		}
   136 		if (current_entry->prompt)
   137 			prop_warn(prop, "prompt redefined");
   138 		current_entry->prompt = prop;
   139 	}
   140 	prop->text = prompt;
   141 
   142 	return prop;
   143 }
   144 
   145 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
   146 {
   147 	return menu_add_prop(type, prompt, NULL, dep);
   148 }
   149 
   150 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
   151 {
   152 	menu_add_prop(type, NULL, expr, dep);
   153 }
   154 
   155 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
   156 {
   157 	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
   158 }
   159 
   160 void menu_add_option(int token, char *arg)
   161 {
   162 	struct property *prop;
   163 
   164 	switch (token) {
   165 	case T_OPT_MODULES:
   166 		prop = prop_alloc(P_DEFAULT, modules_sym);
   167 		prop->expr = expr_alloc_symbol(current_entry->sym);
   168 		break;
   169 	case T_OPT_DEFCONFIG_LIST:
   170 		if (!sym_defconfig_list)
   171 			sym_defconfig_list = current_entry->sym;
   172 		else if (sym_defconfig_list != current_entry->sym)
   173 			zconf_error("trying to redefine defconfig symbol");
   174 		break;
   175 	}
   176 }
   177 
   178 static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
   179 {
   180 	return sym2->type == S_INT || sym2->type == S_HEX ||
   181 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
   182 }
   183 
   184 void sym_check_prop(struct symbol *sym)
   185 {
   186 	struct property *prop;
   187 	struct symbol *sym2;
   188 	for (prop = sym->prop; prop; prop = prop->next) {
   189 		switch (prop->type) {
   190 		case P_DEFAULT:
   191 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
   192 			    prop->expr->type != E_SYMBOL)
   193 				prop_warn(prop,
   194 				    "default for config symbol '%'"
   195 				    " must be a single symbol", sym->name);
   196 			break;
   197 		case P_SELECT:
   198 			sym2 = prop_get_symbol(prop);
   199 			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
   200 				prop_warn(prop,
   201 				    "config symbol '%s' uses select, but is "
   202 				    "not boolean or tristate", sym->name);
   203 			else if (sym2->type == S_UNKNOWN)
   204 				prop_warn(prop,
   205 				    "'select' used by config symbol '%s' "
   206 				    "refer to undefined symbol '%s'",
   207 				    sym->name, sym2->name);
   208 			else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
   209 				prop_warn(prop,
   210 				    "'%s' has wrong type. 'select' only "
   211 				    "accept arguments of boolean and "
   212 				    "tristate type", sym2->name);
   213 			break;
   214 		case P_RANGE:
   215 			if (sym->type != S_INT && sym->type != S_HEX)
   216 				prop_warn(prop, "range is only allowed "
   217 				                "for int or hex symbols");
   218 			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
   219 			    !menu_range_valid_sym(sym, prop->expr->right.sym))
   220 				prop_warn(prop, "range is invalid");
   221 			break;
   222 		default:
   223 			;
   224 		}
   225 	}
   226 }
   227 
   228 void menu_finalize(struct menu *parent)
   229 {
   230 	struct menu *menu, *last_menu;
   231 	struct symbol *sym;
   232 	struct property *prop;
   233 	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
   234 
   235 	sym = parent->sym;
   236 	if (parent->list) {
   237 		if (sym && sym_is_choice(sym)) {
   238 			/* find the first choice value and find out choice type */
   239 			for (menu = parent->list; menu; menu = menu->next) {
   240 				if (menu->sym) {
   241 					current_entry = parent;
   242 					menu_set_type(menu->sym->type);
   243 					current_entry = menu;
   244 					menu_set_type(sym->type);
   245 					break;
   246 				}
   247 			}
   248 			parentdep = expr_alloc_symbol(sym);
   249 		} else if (parent->prompt)
   250 			parentdep = parent->prompt->visible.expr;
   251 		else
   252 			parentdep = parent->dep;
   253 
   254 		for (menu = parent->list; menu; menu = menu->next) {
   255 			basedep = expr_transform(menu->dep);
   256 			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
   257 			basedep = expr_eliminate_dups(basedep);
   258 			menu->dep = basedep;
   259 			if (menu->sym)
   260 				prop = menu->sym->prop;
   261 			else
   262 				prop = menu->prompt;
   263 			for (; prop; prop = prop->next) {
   264 				if (prop->menu != menu)
   265 					continue;
   266 				dep = expr_transform(prop->visible.expr);
   267 				dep = expr_alloc_and(expr_copy(basedep), dep);
   268 				dep = expr_eliminate_dups(dep);
   269 				if (menu->sym && menu->sym->type != S_TRISTATE)
   270 					dep = expr_trans_bool(dep);
   271 				prop->visible.expr = dep;
   272 				if (prop->type == P_SELECT) {
   273 					struct symbol *es = prop_get_symbol(prop);
   274 					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
   275 							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
   276 				}
   277 			}
   278 		}
   279 		for (menu = parent->list; menu; menu = menu->next)
   280 			menu_finalize(menu);
   281 	} else if (sym) {
   282 		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
   283 		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
   284 		basedep = expr_eliminate_dups(expr_transform(basedep));
   285 		last_menu = NULL;
   286 		for (menu = parent->next; menu; menu = menu->next) {
   287 			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
   288 			if (!expr_contains_symbol(dep, sym))
   289 				break;
   290 			if (expr_depends_symbol(dep, sym))
   291 				goto next;
   292 			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
   293 			dep = expr_eliminate_dups(expr_transform(dep));
   294 			dep2 = expr_copy(basedep);
   295 			expr_eliminate_eq(&dep, &dep2);
   296 			expr_free(dep);
   297 			if (!expr_is_yes(dep2)) {
   298 				expr_free(dep2);
   299 				break;
   300 			}
   301 			expr_free(dep2);
   302 		next:
   303 			menu_finalize(menu);
   304 			menu->parent = parent;
   305 			last_menu = menu;
   306 		}
   307 		if (last_menu) {
   308 			parent->list = parent->next;
   309 			parent->next = last_menu->next;
   310 			last_menu->next = NULL;
   311 		}
   312 	}
   313 	for (menu = parent->list; menu; menu = menu->next) {
   314 		if (sym && sym_is_choice(sym) && menu->sym) {
   315 			menu->sym->flags |= SYMBOL_CHOICEVAL;
   316 			if (!menu->prompt)
   317 				menu_warn(menu, "choice value must have a prompt");
   318 			for (prop = menu->sym->prop; prop; prop = prop->next) {
   319 				if (prop->type == P_PROMPT && prop->menu != menu) {
   320 					prop_warn(prop, "choice values "
   321 					    "currently only support a "
   322 					    "single prompt");
   323 				}
   324 				if (prop->type == P_DEFAULT)
   325 					prop_warn(prop, "defaults for choice "
   326 					    "values not supported");
   327 			}
   328 			current_entry = menu;
   329 			menu_set_type(sym->type);
   330 			menu_add_symbol(P_CHOICE, sym, NULL);
   331 			prop = sym_get_choice_prop(sym);
   332 			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
   333 				;
   334 			*ep = expr_alloc_one(E_CHOICE, NULL);
   335 			(*ep)->right.sym = menu->sym;
   336 		}
   337 		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
   338 			for (last_menu = menu->list; ; last_menu = last_menu->next) {
   339 				last_menu->parent = parent;
   340 				if (!last_menu->next)
   341 					break;
   342 			}
   343 			last_menu->next = menu->next;
   344 			menu->next = menu->list;
   345 			menu->list = NULL;
   346 		}
   347 	}
   348 
   349 	if (sym && !(sym->flags & SYMBOL_WARNED)) {
   350 		if (sym->type == S_UNKNOWN)
   351 			menu_warn(parent, "config symbol defined without type");
   352 
   353 		if (sym_is_choice(sym) && !parent->prompt)
   354 			menu_warn(parent, "choice must have a prompt");
   355 
   356 		/* Check properties connected to this symbol */
   357 		sym_check_prop(sym);
   358 		sym->flags |= SYMBOL_WARNED;
   359 	}
   360 
   361 	if (sym && !sym_is_optional(sym) && parent->prompt) {
   362 		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
   363 				expr_alloc_and(parent->prompt->visible.expr,
   364 					expr_alloc_symbol(&symbol_mod)));
   365 	}
   366 }
   367 
   368 bool menu_is_visible(struct menu *menu)
   369 {
   370 	struct menu *child;
   371 	struct symbol *sym;
   372 	tristate visible;
   373 
   374 	if (!menu->prompt)
   375 		return false;
   376 	sym = menu->sym;
   377 	if (sym) {
   378 		sym_calc_value(sym);
   379 		visible = menu->prompt->visible.tri;
   380 	} else
   381 		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
   382 
   383 	if (visible != no)
   384 		return true;
   385 	if (!sym || sym_get_tristate_value(menu->sym) == no)
   386 		return false;
   387 
   388 	for (child = menu->list; child; child = child->next)
   389 		if (menu_is_visible(child))
   390 			return true;
   391 	return false;
   392 }
   393 
   394 const char *menu_get_prompt(struct menu *menu)
   395 {
   396 	if (menu->prompt)
   397 		return _(menu->prompt->text);
   398 	else if (menu->sym)
   399 		return _(menu->sym->name);
   400 	return NULL;
   401 }
   402 
   403 struct menu *menu_get_root_menu(struct menu *menu)
   404 {
   405 	return &rootmenu;
   406 }
   407 
   408 struct menu *menu_get_parent_menu(struct menu *menu)
   409 {
   410 	enum prop_type type;
   411 
   412 	for (; menu != &rootmenu; menu = menu->parent) {
   413 		type = menu->prompt ? menu->prompt->type : 0;
   414 		if (type == P_MENU)
   415 			break;
   416 	}
   417 	return menu;
   418 }
   419