kconfig/menu.c
author Arnaud Lacombe <lacombar@gmail.com>
Tue Aug 03 06:17:51 2010 +0200 (2010-08-03)
changeset 2064 f5ebe8c429dc
parent 943 1cca90ce0481
child 2448 a103abae1560
permissions -rw-r--r--
libc/uClibc: add uClibc 0.9.30.3

This version has been released a couple of month ago, but it never reached
crosstool-ng tree. This may be linked to the fact that the current 0.9.30.2,
once patched, has nothing much different from 0.9.30.3, released.

I'm not including any patch with this upgrade, on purpose.

Signed-off-by: Arnaud Lacombe <lacombar@gmail.com>
yann@1
     1
/*
yann@1
     2
 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
yann@1
     3
 * Released under the terms of the GNU GPL v2.0.
yann@1
     4
 */
yann@1
     5
yann@1
     6
#include <stdlib.h>
yann@1
     7
#include <string.h>
yann@1
     8
yann@1
     9
#define LKC_DIRECT_LINK
yann@1
    10
#include "lkc.h"
yann@1
    11
yann@1
    12
struct menu rootmenu;
yann@1
    13
static struct menu **last_entry_ptr;
yann@1
    14
yann@1
    15
struct file *file_list;
yann@1
    16
struct file *current_file;
yann@1
    17
yann@943
    18
void menu_warn(struct menu *menu, const char *fmt, ...)
yann@1
    19
{
yann@1
    20
	va_list ap;
yann@1
    21
	va_start(ap, fmt);
yann@1
    22
	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
yann@1
    23
	vfprintf(stderr, fmt, ap);
yann@1
    24
	fprintf(stderr, "\n");
yann@1
    25
	va_end(ap);
yann@1
    26
}
yann@1
    27
yann@1
    28
static void prop_warn(struct property *prop, const char *fmt, ...)
yann@1
    29
{
yann@1
    30
	va_list ap;
yann@1
    31
	va_start(ap, fmt);
yann@1
    32
	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
yann@1
    33
	vfprintf(stderr, fmt, ap);
yann@1
    34
	fprintf(stderr, "\n");
yann@1
    35
	va_end(ap);
yann@1
    36
}
yann@1
    37
yann@1
    38
void menu_init(void)
yann@1
    39
{
yann@1
    40
	current_entry = current_menu = &rootmenu;
yann@1
    41
	last_entry_ptr = &rootmenu.list;
yann@1
    42
}
yann@1
    43
yann@1
    44
void menu_add_entry(struct symbol *sym)
yann@1
    45
{
yann@1
    46
	struct menu *menu;
yann@1
    47
yann@1
    48
	menu = malloc(sizeof(*menu));
yann@1
    49
	memset(menu, 0, sizeof(*menu));
yann@1
    50
	menu->sym = sym;
yann@1
    51
	menu->parent = current_menu;
yann@1
    52
	menu->file = current_file;
yann@1
    53
	menu->lineno = zconf_lineno();
yann@1
    54
yann@1
    55
	*last_entry_ptr = menu;
yann@1
    56
	last_entry_ptr = &menu->next;
yann@1
    57
	current_entry = menu;
yann@1
    58
}
yann@1
    59
yann@1
    60
void menu_end_entry(void)
yann@1
    61
{
yann@1
    62
}
yann@1
    63
yann@1
    64
struct menu *menu_add_menu(void)
yann@1
    65
{
yann@1
    66
	menu_end_entry();
yann@1
    67
	last_entry_ptr = &current_entry->list;
yann@1
    68
	return current_menu = current_entry;
yann@1
    69
}
yann@1
    70
yann@1
    71
void menu_end_menu(void)
yann@1
    72
{
yann@1
    73
	last_entry_ptr = &current_menu->next;
yann@1
    74
	current_menu = current_menu->parent;
yann@1
    75
}
yann@1
    76
yann@1
    77
struct expr *menu_check_dep(struct expr *e)
yann@1
    78
{
yann@1
    79
	if (!e)
yann@1
    80
		return e;
yann@1
    81
yann@1
    82
	switch (e->type) {
yann@1
    83
	case E_NOT:
yann@1
    84
		e->left.expr = menu_check_dep(e->left.expr);
yann@1
    85
		break;
yann@1
    86
	case E_OR:
yann@1
    87
	case E_AND:
yann@1
    88
		e->left.expr = menu_check_dep(e->left.expr);
yann@1
    89
		e->right.expr = menu_check_dep(e->right.expr);
yann@1
    90
		break;
yann@1
    91
	case E_SYMBOL:
yann@1
    92
		/* change 'm' into 'm' && MODULES */
yann@1
    93
		if (e->left.sym == &symbol_mod)
yann@1
    94
			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
yann@1
    95
		break;
yann@1
    96
	default:
yann@1
    97
		break;
yann@1
    98
	}
yann@1
    99
	return e;
yann@1
   100
}
yann@1
   101
yann@1
   102
void menu_add_dep(struct expr *dep)
yann@1
   103
{
yann@1
   104
	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
yann@1
   105
}
yann@1
   106
yann@1
   107
void menu_set_type(int type)
yann@1
   108
{
yann@1
   109
	struct symbol *sym = current_entry->sym;
yann@1
   110
yann@1
   111
	if (sym->type == type)
yann@1
   112
		return;
yann@1
   113
	if (sym->type == S_UNKNOWN) {
yann@1
   114
		sym->type = type;
yann@1
   115
		return;
yann@1
   116
	}
yann@1
   117
	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
yann@1
   118
	    sym->name ? sym->name : "<choice>",
yann@1
   119
	    sym_type_name(sym->type), sym_type_name(type));
yann@1
   120
}
yann@1
   121
yann@1
   122
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
yann@1
   123
{
yann@1
   124
	struct property *prop = prop_alloc(type, current_entry->sym);
yann@1
   125
yann@1
   126
	prop->menu = current_entry;
yann@1
   127
	prop->expr = expr;
yann@1
   128
	prop->visible.expr = menu_check_dep(dep);
yann@1
   129
yann@1
   130
	if (prompt) {
yann@1040
   131
		/* For crostool-NG, a leading pipe followed with spaces
yann@1040
   132
		 * means that pipe shall be removed, and the spaces should
yann@1040
   133
		 * not be trimmed.
yann@1040
   134
		 */
yann@1040
   135
		if (*prompt == '|')
yann@1040
   136
			prompt++;
yann@1040
   137
		else if (isspace(*prompt)) {
yann@1040
   138
			/* Silently trim leading spaces */
yann@1
   139
			while (isspace(*prompt))
yann@1
   140
				prompt++;
yann@1
   141
		}
yann@1
   142
		if (current_entry->prompt)
yann@1
   143
			prop_warn(prop, "prompt redefined");
yann@1
   144
		current_entry->prompt = prop;
yann@1
   145
	}
yann@1
   146
	prop->text = prompt;
yann@1
   147
yann@1
   148
	return prop;
yann@1
   149
}
yann@1
   150
yann@1
   151
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
yann@1
   152
{
yann@1
   153
	return menu_add_prop(type, prompt, NULL, dep);
yann@1
   154
}
yann@1
   155
yann@1
   156
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
yann@1
   157
{
yann@1
   158
	menu_add_prop(type, NULL, expr, dep);
yann@1
   159
}
yann@1
   160
yann@1
   161
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
yann@1
   162
{
yann@1
   163
	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
yann@1
   164
}
yann@1
   165
yann@1
   166
void menu_add_option(int token, char *arg)
yann@1
   167
{
yann@1
   168
	struct property *prop;
yann@1
   169
yann@1
   170
	switch (token) {
yann@1
   171
	case T_OPT_MODULES:
yann@1
   172
		prop = prop_alloc(P_DEFAULT, modules_sym);
yann@1
   173
		prop->expr = expr_alloc_symbol(current_entry->sym);
yann@1
   174
		break;
yann@1
   175
	case T_OPT_DEFCONFIG_LIST:
yann@1
   176
		if (!sym_defconfig_list)
yann@1
   177
			sym_defconfig_list = current_entry->sym;
yann@1
   178
		else if (sym_defconfig_list != current_entry->sym)
yann@1
   179
			zconf_error("trying to redefine defconfig symbol");
yann@1
   180
		break;
yann@943
   181
	case T_OPT_ENV:
yann@943
   182
		prop_add_env(arg);
yann@943
   183
		break;
yann@1
   184
	}
yann@1
   185
}
yann@1
   186
yann@1
   187
static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
yann@1
   188
{
yann@1
   189
	return sym2->type == S_INT || sym2->type == S_HEX ||
yann@1
   190
	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
yann@1
   191
}
yann@1
   192
yann@1
   193
void sym_check_prop(struct symbol *sym)
yann@1
   194
{
yann@1
   195
	struct property *prop;
yann@1
   196
	struct symbol *sym2;
yann@1
   197
	for (prop = sym->prop; prop; prop = prop->next) {
yann@1
   198
		switch (prop->type) {
yann@1
   199
		case P_DEFAULT:
yann@1
   200
			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
yann@1
   201
			    prop->expr->type != E_SYMBOL)
yann@1
   202
				prop_warn(prop,
yann@1
   203
				    "default for config symbol '%'"
yann@1
   204
				    " must be a single symbol", sym->name);
yann@1
   205
			break;
yann@1
   206
		case P_SELECT:
yann@1
   207
			sym2 = prop_get_symbol(prop);
yann@1
   208
			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
yann@1
   209
				prop_warn(prop,
yann@1
   210
				    "config symbol '%s' uses select, but is "
yann@1
   211
				    "not boolean or tristate", sym->name);
yann@943
   212
			else if (sym2->type != S_UNKNOWN &&
yann@943
   213
			         sym2->type != S_BOOLEAN &&
yann@943
   214
			         sym2->type != S_TRISTATE)
yann@1
   215
				prop_warn(prop,
yann@1
   216
				    "'%s' has wrong type. 'select' only "
yann@1
   217
				    "accept arguments of boolean and "
yann@1
   218
				    "tristate type", sym2->name);
yann@1
   219
			break;
yann@1
   220
		case P_RANGE:
yann@1
   221
			if (sym->type != S_INT && sym->type != S_HEX)
yann@1
   222
				prop_warn(prop, "range is only allowed "
yann@1
   223
				                "for int or hex symbols");
yann@1
   224
			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
yann@1
   225
			    !menu_range_valid_sym(sym, prop->expr->right.sym))
yann@1
   226
				prop_warn(prop, "range is invalid");
yann@1
   227
			break;
yann@1
   228
		default:
yann@1
   229
			;
yann@1
   230
		}
yann@1
   231
	}
yann@1
   232
}
yann@1
   233
yann@1
   234
void menu_finalize(struct menu *parent)
yann@1
   235
{
yann@1
   236
	struct menu *menu, *last_menu;
yann@1
   237
	struct symbol *sym;
yann@1
   238
	struct property *prop;
yann@1
   239
	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
yann@1
   240
yann@1
   241
	sym = parent->sym;
yann@1
   242
	if (parent->list) {
yann@1
   243
		if (sym && sym_is_choice(sym)) {
yann@943
   244
			if (sym->type == S_UNKNOWN) {
yann@943
   245
				/* find the first choice value to find out choice type */
yann@943
   246
				current_entry = parent;
yann@943
   247
				for (menu = parent->list; menu; menu = menu->next) {
yann@943
   248
					if (menu->sym && menu->sym->type != S_UNKNOWN) {
yann@943
   249
						menu_set_type(menu->sym->type);
yann@943
   250
						break;
yann@943
   251
					}
yann@943
   252
				}
yann@943
   253
			}
yann@943
   254
			/* set the type of the remaining choice values */
yann@1
   255
			for (menu = parent->list; menu; menu = menu->next) {
yann@943
   256
				current_entry = menu;
yann@943
   257
				if (menu->sym && menu->sym->type == S_UNKNOWN)
yann@1
   258
					menu_set_type(sym->type);
yann@1
   259
			}
yann@1
   260
			parentdep = expr_alloc_symbol(sym);
yann@1
   261
		} else if (parent->prompt)
yann@1
   262
			parentdep = parent->prompt->visible.expr;
yann@1
   263
		else
yann@1
   264
			parentdep = parent->dep;
yann@1
   265
yann@1
   266
		for (menu = parent->list; menu; menu = menu->next) {
yann@1
   267
			basedep = expr_transform(menu->dep);
yann@1
   268
			basedep = expr_alloc_and(expr_copy(parentdep), basedep);
yann@1
   269
			basedep = expr_eliminate_dups(basedep);
yann@1
   270
			menu->dep = basedep;
yann@1
   271
			if (menu->sym)
yann@1
   272
				prop = menu->sym->prop;
yann@1
   273
			else
yann@1
   274
				prop = menu->prompt;
yann@1
   275
			for (; prop; prop = prop->next) {
yann@1
   276
				if (prop->menu != menu)
yann@1
   277
					continue;
yann@1
   278
				dep = expr_transform(prop->visible.expr);
yann@1
   279
				dep = expr_alloc_and(expr_copy(basedep), dep);
yann@1
   280
				dep = expr_eliminate_dups(dep);
yann@1
   281
				if (menu->sym && menu->sym->type != S_TRISTATE)
yann@1
   282
					dep = expr_trans_bool(dep);
yann@1
   283
				prop->visible.expr = dep;
yann@1
   284
				if (prop->type == P_SELECT) {
yann@1
   285
					struct symbol *es = prop_get_symbol(prop);
yann@1
   286
					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
yann@1
   287
							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
yann@1
   288
				}
yann@1
   289
			}
yann@1
   290
		}
yann@1
   291
		for (menu = parent->list; menu; menu = menu->next)
yann@1
   292
			menu_finalize(menu);
yann@1
   293
	} else if (sym) {
yann@1
   294
		basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
yann@1
   295
		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
yann@1
   296
		basedep = expr_eliminate_dups(expr_transform(basedep));
yann@1
   297
		last_menu = NULL;
yann@1
   298
		for (menu = parent->next; menu; menu = menu->next) {
yann@1
   299
			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
yann@1
   300
			if (!expr_contains_symbol(dep, sym))
yann@1
   301
				break;
yann@1
   302
			if (expr_depends_symbol(dep, sym))
yann@1
   303
				goto next;
yann@1
   304
			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
yann@1
   305
			dep = expr_eliminate_dups(expr_transform(dep));
yann@1
   306
			dep2 = expr_copy(basedep);
yann@1
   307
			expr_eliminate_eq(&dep, &dep2);
yann@1
   308
			expr_free(dep);
yann@1
   309
			if (!expr_is_yes(dep2)) {
yann@1
   310
				expr_free(dep2);
yann@1
   311
				break;
yann@1
   312
			}
yann@1
   313
			expr_free(dep2);
yann@1
   314
		next:
yann@1
   315
			menu_finalize(menu);
yann@1
   316
			menu->parent = parent;
yann@1
   317
			last_menu = menu;
yann@1
   318
		}
yann@1
   319
		if (last_menu) {
yann@1
   320
			parent->list = parent->next;
yann@1
   321
			parent->next = last_menu->next;
yann@1
   322
			last_menu->next = NULL;
yann@1
   323
		}
yann@1
   324
	}
yann@1
   325
	for (menu = parent->list; menu; menu = menu->next) {
yann@943
   326
		if (sym && sym_is_choice(sym) &&
yann@943
   327
		    menu->sym && !sym_is_choice_value(menu->sym)) {
yann@943
   328
			current_entry = menu;
yann@1
   329
			menu->sym->flags |= SYMBOL_CHOICEVAL;
yann@1
   330
			if (!menu->prompt)
yann@1
   331
				menu_warn(menu, "choice value must have a prompt");
yann@1
   332
			for (prop = menu->sym->prop; prop; prop = prop->next) {
yann@1
   333
				if (prop->type == P_DEFAULT)
yann@1
   334
					prop_warn(prop, "defaults for choice "
yann@943
   335
						  "values not supported");
yann@943
   336
				if (prop->menu == menu)
yann@943
   337
					continue;
yann@943
   338
				if (prop->type == P_PROMPT &&
yann@943
   339
				    prop->menu->parent->sym != sym)
yann@943
   340
					prop_warn(prop, "choice value used outside its choice group");
yann@1
   341
			}
yann@943
   342
			/* Non-tristate choice values of tristate choices must
yann@943
   343
			 * depend on the choice being set to Y. The choice
yann@943
   344
			 * values' dependencies were propagated to their
yann@943
   345
			 * properties above, so the change here must be re-
yann@943
   346
			 * propagated.
yann@943
   347
			 */
yann@943
   348
			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
yann@943
   349
				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
yann@943
   350
				menu->dep = expr_alloc_and(basedep, menu->dep);
yann@943
   351
				for (prop = menu->sym->prop; prop; prop = prop->next) {
yann@943
   352
					if (prop->menu != menu)
yann@943
   353
						continue;
yann@943
   354
					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
yann@943
   355
									    prop->visible.expr);
yann@943
   356
				}
yann@943
   357
			}
yann@1
   358
			menu_add_symbol(P_CHOICE, sym, NULL);
yann@1
   359
			prop = sym_get_choice_prop(sym);
yann@1
   360
			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
yann@1
   361
				;
yann@943
   362
			*ep = expr_alloc_one(E_LIST, NULL);
yann@1
   363
			(*ep)->right.sym = menu->sym;
yann@1
   364
		}
yann@1
   365
		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
yann@1
   366
			for (last_menu = menu->list; ; last_menu = last_menu->next) {
yann@1
   367
				last_menu->parent = parent;
yann@1
   368
				if (!last_menu->next)
yann@1
   369
					break;
yann@1
   370
			}
yann@1
   371
			last_menu->next = menu->next;
yann@1
   372
			menu->next = menu->list;
yann@1
   373
			menu->list = NULL;
yann@1
   374
		}
yann@1
   375
	}
yann@1
   376
yann@1
   377
	if (sym && !(sym->flags & SYMBOL_WARNED)) {
yann@1
   378
		if (sym->type == S_UNKNOWN)
yann@1
   379
			menu_warn(parent, "config symbol defined without type");
yann@1
   380
yann@1
   381
		if (sym_is_choice(sym) && !parent->prompt)
yann@1
   382
			menu_warn(parent, "choice must have a prompt");
yann@1
   383
yann@1
   384
		/* Check properties connected to this symbol */
yann@1
   385
		sym_check_prop(sym);
yann@1
   386
		sym->flags |= SYMBOL_WARNED;
yann@1
   387
	}
yann@1
   388
yann@1
   389
	if (sym && !sym_is_optional(sym) && parent->prompt) {
yann@1
   390
		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
yann@1
   391
				expr_alloc_and(parent->prompt->visible.expr,
yann@1
   392
					expr_alloc_symbol(&symbol_mod)));
yann@1
   393
	}
yann@1
   394
}
yann@1
   395
yann@1
   396
bool menu_is_visible(struct menu *menu)
yann@1
   397
{
yann@1
   398
	struct menu *child;
yann@1
   399
	struct symbol *sym;
yann@1
   400
	tristate visible;
yann@1
   401
yann@1
   402
	if (!menu->prompt)
yann@1
   403
		return false;
yann@1
   404
	sym = menu->sym;
yann@1
   405
	if (sym) {
yann@1
   406
		sym_calc_value(sym);
yann@1
   407
		visible = menu->prompt->visible.tri;
yann@1
   408
	} else
yann@1
   409
		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
yann@1
   410
yann@1
   411
	if (visible != no)
yann@1
   412
		return true;
yann@1
   413
	if (!sym || sym_get_tristate_value(menu->sym) == no)
yann@1
   414
		return false;
yann@1
   415
yann@1
   416
	for (child = menu->list; child; child = child->next)
yann@1
   417
		if (menu_is_visible(child))
yann@1
   418
			return true;
yann@1
   419
	return false;
yann@1
   420
}
yann@1
   421
yann@1
   422
const char *menu_get_prompt(struct menu *menu)
yann@1
   423
{
yann@1
   424
	if (menu->prompt)
yann@943
   425
		return menu->prompt->text;
yann@1
   426
	else if (menu->sym)
yann@943
   427
		return menu->sym->name;
yann@1
   428
	return NULL;
yann@1
   429
}
yann@1
   430
yann@1
   431
struct menu *menu_get_root_menu(struct menu *menu)
yann@1
   432
{
yann@1
   433
	return &rootmenu;
yann@1
   434
}
yann@1
   435
yann@1
   436
struct menu *menu_get_parent_menu(struct menu *menu)
yann@1
   437
{
yann@1
   438
	enum prop_type type;
yann@1
   439
yann@1
   440
	for (; menu != &rootmenu; menu = menu->parent) {
yann@1
   441
		type = menu->prompt ? menu->prompt->type : 0;
yann@1
   442
		if (type == P_MENU)
yann@1
   443
			break;
yann@1
   444
	}
yann@1
   445
	return menu;
yann@1
   446
}
yann@1
   447
yann@943
   448
bool menu_has_help(struct menu *menu)
yann@943
   449
{
yann@943
   450
	return menu->help != NULL;
yann@943
   451
}
yann@943
   452
yann@943
   453
const char *menu_get_help(struct menu *menu)
yann@943
   454
{
yann@943
   455
	if (menu->help)
yann@943
   456
		return menu->help;
yann@943
   457
	else
yann@943
   458
		return "";
yann@943
   459
}