kconfig/menu.c
changeset 2448 a103abae1560
parent 1040 dc17e615de2c
child 2450 68cc5a0d3191
     1.1 --- a/kconfig/menu.c	Thu Nov 13 17:55:16 2008 +0000
     1.2 +++ b/kconfig/menu.c	Sun May 08 14:14:40 2011 +0200
     1.3 @@ -9,6 +9,9 @@
     1.4  #define LKC_DIRECT_LINK
     1.5  #include "lkc.h"
     1.6  
     1.7 +static const char nohelp_text[] = N_(
     1.8 +	"There is no help available for this option.\n");
     1.9 +
    1.10  struct menu rootmenu;
    1.11  static struct menu **last_entry_ptr;
    1.12  
    1.13 @@ -35,7 +38,7 @@
    1.14  	va_end(ap);
    1.15  }
    1.16  
    1.17 -void menu_init(void)
    1.18 +void _menu_init(void)
    1.19  {
    1.20  	current_entry = current_menu = &rootmenu;
    1.21  	last_entry_ptr = &rootmenu.list;
    1.22 @@ -55,6 +58,8 @@
    1.23  	*last_entry_ptr = menu;
    1.24  	last_entry_ptr = &menu->next;
    1.25  	current_entry = menu;
    1.26 +	if (sym)
    1.27 +		menu_add_symbol(P_SYMBOL, sym, NULL);
    1.28  }
    1.29  
    1.30  void menu_end_entry(void)
    1.31 @@ -74,7 +79,7 @@
    1.32  	current_menu = current_menu->parent;
    1.33  }
    1.34  
    1.35 -struct expr *menu_check_dep(struct expr *e)
    1.36 +static struct expr *menu_check_dep(struct expr *e)
    1.37  {
    1.38  	if (!e)
    1.39  		return e;
    1.40 @@ -128,19 +133,27 @@
    1.41  	prop->visible.expr = menu_check_dep(dep);
    1.42  
    1.43  	if (prompt) {
    1.44 -		/* For crostool-NG, a leading pipe followed with spaces
    1.45 -		 * means that pipe shall be removed, and the spaces should
    1.46 -		 * not be trimmed.
    1.47 -		 */
    1.48 -		if (*prompt == '|')
    1.49 -			prompt++;
    1.50 -		else if (isspace(*prompt)) {
    1.51 -			/* Silently trim leading spaces */
    1.52 +		if (isspace(*prompt)) {
    1.53 +			prop_warn(prop, "leading whitespace ignored");
    1.54  			while (isspace(*prompt))
    1.55  				prompt++;
    1.56  		}
    1.57 -		if (current_entry->prompt)
    1.58 +		if (current_entry->prompt && current_entry != &rootmenu)
    1.59  			prop_warn(prop, "prompt redefined");
    1.60 +
    1.61 +		/* Apply all upper menus' visibilities to actual prompts. */
    1.62 +		if(type == P_PROMPT) {
    1.63 +			struct menu *menu = current_entry;
    1.64 +
    1.65 +			while ((menu = menu->parent) != NULL) {
    1.66 +				if (!menu->visibility)
    1.67 +					continue;
    1.68 +				prop->visible.expr
    1.69 +					= expr_alloc_and(prop->visible.expr,
    1.70 +							 menu->visibility);
    1.71 +			}
    1.72 +		}
    1.73 +
    1.74  		current_entry->prompt = prop;
    1.75  	}
    1.76  	prop->text = prompt;
    1.77 @@ -153,6 +166,12 @@
    1.78  	return menu_add_prop(type, prompt, NULL, dep);
    1.79  }
    1.80  
    1.81 +void menu_add_visibility(struct expr *expr)
    1.82 +{
    1.83 +	current_entry->visibility = expr_alloc_and(current_entry->visibility,
    1.84 +	    expr);
    1.85 +}
    1.86 +
    1.87  void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
    1.88  {
    1.89  	menu_add_prop(type, NULL, expr, dep);
    1.90 @@ -184,13 +203,13 @@
    1.91  	}
    1.92  }
    1.93  
    1.94 -static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
    1.95 +static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
    1.96  {
    1.97  	return sym2->type == S_INT || sym2->type == S_HEX ||
    1.98  	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
    1.99  }
   1.100  
   1.101 -void sym_check_prop(struct symbol *sym)
   1.102 +static void sym_check_prop(struct symbol *sym)
   1.103  {
   1.104  	struct property *prop;
   1.105  	struct symbol *sym2;
   1.106 @@ -200,8 +219,17 @@
   1.107  			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
   1.108  			    prop->expr->type != E_SYMBOL)
   1.109  				prop_warn(prop,
   1.110 -				    "default for config symbol '%'"
   1.111 +				    "default for config symbol '%s'"
   1.112  				    " must be a single symbol", sym->name);
   1.113 +			if (prop->expr->type != E_SYMBOL)
   1.114 +				break;
   1.115 +			sym2 = prop_get_symbol(prop);
   1.116 +			if (sym->type == S_HEX || sym->type == S_INT) {
   1.117 +				if (!menu_validate_number(sym, sym2))
   1.118 +					prop_warn(prop,
   1.119 +					    "'%s': number is invalid",
   1.120 +					    sym->name);
   1.121 +			}
   1.122  			break;
   1.123  		case P_SELECT:
   1.124  			sym2 = prop_get_symbol(prop);
   1.125 @@ -221,8 +249,8 @@
   1.126  			if (sym->type != S_INT && sym->type != S_HEX)
   1.127  				prop_warn(prop, "range is only allowed "
   1.128  				                "for int or hex symbols");
   1.129 -			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
   1.130 -			    !menu_range_valid_sym(sym, prop->expr->right.sym))
   1.131 +			if (!menu_validate_number(sym, prop->expr->left.sym) ||
   1.132 +			    !menu_validate_number(sym, prop->expr->right.sym))
   1.133  				prop_warn(prop, "range is invalid");
   1.134  			break;
   1.135  		default:
   1.136 @@ -321,6 +349,8 @@
   1.137  			parent->next = last_menu->next;
   1.138  			last_menu->next = NULL;
   1.139  		}
   1.140 +
   1.141 +		sym->dir_dep.expr = parent->dep;
   1.142  	}
   1.143  	for (menu = parent->list; menu; menu = menu->next) {
   1.144  		if (sym && sym_is_choice(sym) &&
   1.145 @@ -393,6 +423,13 @@
   1.146  	}
   1.147  }
   1.148  
   1.149 +bool menu_has_prompt(struct menu *menu)
   1.150 +{
   1.151 +	if (!menu->prompt)
   1.152 +		return false;
   1.153 +	return true;
   1.154 +}
   1.155 +
   1.156  bool menu_is_visible(struct menu *menu)
   1.157  {
   1.158  	struct menu *child;
   1.159 @@ -401,6 +438,12 @@
   1.160  
   1.161  	if (!menu->prompt)
   1.162  		return false;
   1.163 +
   1.164 +	if (menu->visibility) {
   1.165 +		if (expr_calc_value(menu->visibility) == no)
   1.166 +			return no;
   1.167 +	}
   1.168 +
   1.169  	sym = menu->sym;
   1.170  	if (sym) {
   1.171  		sym_calc_value(sym);
   1.172 @@ -410,12 +453,18 @@
   1.173  
   1.174  	if (visible != no)
   1.175  		return true;
   1.176 +
   1.177  	if (!sym || sym_get_tristate_value(menu->sym) == no)
   1.178  		return false;
   1.179  
   1.180 -	for (child = menu->list; child; child = child->next)
   1.181 -		if (menu_is_visible(child))
   1.182 +	for (child = menu->list; child; child = child->next) {
   1.183 +		if (menu_is_visible(child)) {
   1.184 +			if (sym)
   1.185 +				sym->flags |= SYMBOL_DEF_USER;
   1.186  			return true;
   1.187 +		}
   1.188 +	}
   1.189 +
   1.190  	return false;
   1.191  }
   1.192  
   1.193 @@ -457,3 +506,104 @@
   1.194  	else
   1.195  		return "";
   1.196  }
   1.197 +
   1.198 +static void get_prompt_str(struct gstr *r, struct property *prop)
   1.199 +{
   1.200 +	int i, j;
   1.201 +	struct menu *submenu[8], *menu;
   1.202 +
   1.203 +	str_printf(r, _("Prompt: %s\n"), _(prop->text));
   1.204 +	str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
   1.205 +		prop->menu->lineno);
   1.206 +	if (!expr_is_yes(prop->visible.expr)) {
   1.207 +		str_append(r, _("  Depends on: "));
   1.208 +		expr_gstr_print(prop->visible.expr, r);
   1.209 +		str_append(r, "\n");
   1.210 +	}
   1.211 +	menu = prop->menu->parent;
   1.212 +	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
   1.213 +		submenu[i++] = menu;
   1.214 +	if (i > 0) {
   1.215 +		str_printf(r, _("  Location:\n"));
   1.216 +		for (j = 4; --i >= 0; j += 2) {
   1.217 +			menu = submenu[i];
   1.218 +			str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
   1.219 +			if (menu->sym) {
   1.220 +				str_printf(r, " (%s [=%s])", menu->sym->name ?
   1.221 +					menu->sym->name : _("<choice>"),
   1.222 +					sym_get_string_value(menu->sym));
   1.223 +			}
   1.224 +			str_append(r, "\n");
   1.225 +		}
   1.226 +	}
   1.227 +}
   1.228 +
   1.229 +void get_symbol_str(struct gstr *r, struct symbol *sym)
   1.230 +{
   1.231 +	bool hit;
   1.232 +	struct property *prop;
   1.233 +
   1.234 +	if (sym && sym->name) {
   1.235 +		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
   1.236 +			   sym_get_string_value(sym));
   1.237 +		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
   1.238 +		if (sym->type == S_INT || sym->type == S_HEX) {
   1.239 +			prop = sym_get_range_prop(sym);
   1.240 +			if (prop) {
   1.241 +				str_printf(r, "Range : ");
   1.242 +				expr_gstr_print(prop->expr, r);
   1.243 +				str_append(r, "\n");
   1.244 +			}
   1.245 +		}
   1.246 +	}
   1.247 +	for_all_prompts(sym, prop)
   1.248 +		get_prompt_str(r, prop);
   1.249 +	hit = false;
   1.250 +	for_all_properties(sym, prop, P_SELECT) {
   1.251 +		if (!hit) {
   1.252 +			str_append(r, "  Selects: ");
   1.253 +			hit = true;
   1.254 +		} else
   1.255 +			str_printf(r, " && ");
   1.256 +		expr_gstr_print(prop->expr, r);
   1.257 +	}
   1.258 +	if (hit)
   1.259 +		str_append(r, "\n");
   1.260 +	if (sym->rev_dep.expr) {
   1.261 +		str_append(r, _("  Selected by: "));
   1.262 +		expr_gstr_print(sym->rev_dep.expr, r);
   1.263 +		str_append(r, "\n");
   1.264 +	}
   1.265 +	str_append(r, "\n\n");
   1.266 +}
   1.267 +
   1.268 +struct gstr get_relations_str(struct symbol **sym_arr)
   1.269 +{
   1.270 +	struct symbol *sym;
   1.271 +	struct gstr res = str_new();
   1.272 +	int i;
   1.273 +
   1.274 +	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
   1.275 +		get_symbol_str(&res, sym);
   1.276 +	if (!i)
   1.277 +		str_append(&res, _("No matches found.\n"));
   1.278 +	return res;
   1.279 +}
   1.280 +
   1.281 +
   1.282 +void menu_get_ext_help(struct menu *menu, struct gstr *help)
   1.283 +{
   1.284 +	struct symbol *sym = menu->sym;
   1.285 +
   1.286 +	if (menu_has_help(menu)) {
   1.287 +		if (sym->name) {
   1.288 +			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
   1.289 +			str_append(help, _(menu_get_help(menu)));
   1.290 +			str_append(help, "\n");
   1.291 +		}
   1.292 +	} else {
   1.293 +		str_append(help, nohelp_text);
   1.294 +	}
   1.295 +	if (sym)
   1.296 +		get_symbol_str(help, sym);
   1.297 +}