kconfig/symbol.c
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Sun May 11 23:43:52 2014 +0200 (2014-05-11)
changeset 3320 78af1c99bc6d
parent 2448 a103abae1560
permissions -rw-r--r--
scripts/functions: add target_endian_le and target_endian_be

We currently define target_endian_el and target_endian_eb to be the
tuple extension depending on endianness, defined to be respectively
'el' or 'eb' according to the endianness.

Some architecture do not use 'el' or 'eb', but use 'le' or 'be'.

Provide that as well, as two new variables: target_endian_le and
target_endian_be.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
Cc: Cody P Schafer <dev@codyps.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 <ctype.h>
yann@1
     7
#include <stdlib.h>
yann@1
     8
#include <string.h>
yann@1
     9
#include <regex.h>
yann@1
    10
#include <sys/utsname.h>
yann@1
    11
yann@1
    12
#define LKC_DIRECT_LINK
yann@1
    13
#include "lkc.h"
yann@1
    14
yann@1
    15
struct symbol symbol_yes = {
yann@1
    16
	.name = "y",
yann@1
    17
	.curr = { "y", yes },
yann@1
    18
	.flags = SYMBOL_CONST|SYMBOL_VALID,
yann@1
    19
}, symbol_mod = {
yann@1
    20
	.name = "m",
yann@1
    21
	.curr = { "m", mod },
yann@1
    22
	.flags = SYMBOL_CONST|SYMBOL_VALID,
yann@1
    23
}, symbol_no = {
yann@1
    24
	.name = "n",
yann@1
    25
	.curr = { "n", no },
yann@1
    26
	.flags = SYMBOL_CONST|SYMBOL_VALID,
yann@1
    27
}, symbol_empty = {
yann@1
    28
	.name = "",
yann@1
    29
	.curr = { "", no },
yann@1
    30
	.flags = SYMBOL_VALID,
yann@1
    31
};
yann@1
    32
yann@1
    33
struct symbol *sym_defconfig_list;
yann@1
    34
struct symbol *modules_sym;
yann@1
    35
tristate modules_val;
yann@1
    36
yann@943
    37
struct expr *sym_env_list;
yann@943
    38
yann@2448
    39
static void sym_add_default(struct symbol *sym, const char *def)
yann@1
    40
{
yann@1
    41
	struct property *prop = prop_alloc(P_DEFAULT, sym);
yann@1
    42
yann@943
    43
	prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
yann@1
    44
}
yann@1
    45
yann@1
    46
void sym_init(void)
yann@1
    47
{
yann@1
    48
	struct symbol *sym;
yann@1
    49
	struct utsname uts;
yann@1
    50
	static bool inited = false;
yann@1
    51
yann@1
    52
	if (inited)
yann@1
    53
		return;
yann@1
    54
	inited = true;
yann@1
    55
yann@1
    56
	uname(&uts);
yann@1
    57
yann@943
    58
	sym = sym_lookup("UNAME_RELEASE", 0);
yann@1
    59
	sym->type = S_STRING;
yann@1
    60
	sym->flags |= SYMBOL_AUTO;
yann@943
    61
	sym_add_default(sym, uts.release);
yann@1
    62
}
yann@1
    63
yann@1
    64
enum symbol_type sym_get_type(struct symbol *sym)
yann@1
    65
{
yann@1
    66
	enum symbol_type type = sym->type;
yann@1
    67
yann@1
    68
	if (type == S_TRISTATE) {
yann@1
    69
		if (sym_is_choice_value(sym) && sym->visible == yes)
yann@1
    70
			type = S_BOOLEAN;
yann@1
    71
		else if (modules_val == no)
yann@1
    72
			type = S_BOOLEAN;
yann@1
    73
	}
yann@1
    74
	return type;
yann@1
    75
}
yann@1
    76
yann@1
    77
const char *sym_type_name(enum symbol_type type)
yann@1
    78
{
yann@1
    79
	switch (type) {
yann@1
    80
	case S_BOOLEAN:
yann@1
    81
		return "boolean";
yann@1
    82
	case S_TRISTATE:
yann@1
    83
		return "tristate";
yann@1
    84
	case S_INT:
yann@1
    85
		return "integer";
yann@1
    86
	case S_HEX:
yann@1
    87
		return "hex";
yann@1
    88
	case S_STRING:
yann@1
    89
		return "string";
yann@1
    90
	case S_UNKNOWN:
yann@1
    91
		return "unknown";
yann@1
    92
	case S_OTHER:
yann@1
    93
		break;
yann@1
    94
	}
yann@1
    95
	return "???";
yann@1
    96
}
yann@1
    97
yann@1
    98
struct property *sym_get_choice_prop(struct symbol *sym)
yann@1
    99
{
yann@1
   100
	struct property *prop;
yann@1
   101
yann@1
   102
	for_all_choices(sym, prop)
yann@1
   103
		return prop;
yann@1
   104
	return NULL;
yann@1
   105
}
yann@1
   106
yann@943
   107
struct property *sym_get_env_prop(struct symbol *sym)
yann@943
   108
{
yann@943
   109
	struct property *prop;
yann@943
   110
yann@943
   111
	for_all_properties(sym, prop, P_ENV)
yann@943
   112
		return prop;
yann@943
   113
	return NULL;
yann@943
   114
}
yann@943
   115
yann@1
   116
struct property *sym_get_default_prop(struct symbol *sym)
yann@1
   117
{
yann@1
   118
	struct property *prop;
yann@1
   119
yann@1
   120
	for_all_defaults(sym, prop) {
yann@1
   121
		prop->visible.tri = expr_calc_value(prop->visible.expr);
yann@1
   122
		if (prop->visible.tri != no)
yann@1
   123
			return prop;
yann@1
   124
	}
yann@1
   125
	return NULL;
yann@1
   126
}
yann@1
   127
yann@2448
   128
static struct property *sym_get_range_prop(struct symbol *sym)
yann@1
   129
{
yann@1
   130
	struct property *prop;
yann@1
   131
yann@1
   132
	for_all_properties(sym, prop, P_RANGE) {
yann@1
   133
		prop->visible.tri = expr_calc_value(prop->visible.expr);
yann@1
   134
		if (prop->visible.tri != no)
yann@1
   135
			return prop;
yann@1
   136
	}
yann@1
   137
	return NULL;
yann@1
   138
}
yann@1
   139
yann@1
   140
static int sym_get_range_val(struct symbol *sym, int base)
yann@1
   141
{
yann@1
   142
	sym_calc_value(sym);
yann@1
   143
	switch (sym->type) {
yann@1
   144
	case S_INT:
yann@1
   145
		base = 10;
yann@1
   146
		break;
yann@1
   147
	case S_HEX:
yann@1
   148
		base = 16;
yann@1
   149
		break;
yann@1
   150
	default:
yann@1
   151
		break;
yann@1
   152
	}
yann@1
   153
	return strtol(sym->curr.val, NULL, base);
yann@1
   154
}
yann@1
   155
yann@1
   156
static void sym_validate_range(struct symbol *sym)
yann@1
   157
{
yann@1
   158
	struct property *prop;
yann@1
   159
	int base, val, val2;
yann@1
   160
	char str[64];
yann@1
   161
yann@1
   162
	switch (sym->type) {
yann@1
   163
	case S_INT:
yann@1
   164
		base = 10;
yann@1
   165
		break;
yann@1
   166
	case S_HEX:
yann@1
   167
		base = 16;
yann@1
   168
		break;
yann@1
   169
	default:
yann@1
   170
		return;
yann@1
   171
	}
yann@1
   172
	prop = sym_get_range_prop(sym);
yann@1
   173
	if (!prop)
yann@1
   174
		return;
yann@1
   175
	val = strtol(sym->curr.val, NULL, base);
yann@1
   176
	val2 = sym_get_range_val(prop->expr->left.sym, base);
yann@1
   177
	if (val >= val2) {
yann@1
   178
		val2 = sym_get_range_val(prop->expr->right.sym, base);
yann@1
   179
		if (val <= val2)
yann@1
   180
			return;
yann@1
   181
	}
yann@1
   182
	if (sym->type == S_INT)
yann@1
   183
		sprintf(str, "%d", val2);
yann@1
   184
	else
yann@1
   185
		sprintf(str, "0x%x", val2);
yann@1
   186
	sym->curr.val = strdup(str);
yann@1
   187
}
yann@1
   188
yann@1
   189
static void sym_calc_visibility(struct symbol *sym)
yann@1
   190
{
yann@1
   191
	struct property *prop;
yann@1
   192
	tristate tri;
yann@1
   193
yann@1
   194
	/* any prompt visible? */
yann@1
   195
	tri = no;
yann@1
   196
	for_all_prompts(sym, prop) {
yann@1
   197
		prop->visible.tri = expr_calc_value(prop->visible.expr);
yann@943
   198
		tri = EXPR_OR(tri, prop->visible.tri);
yann@1
   199
	}
yann@1
   200
	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
yann@1
   201
		tri = yes;
yann@1
   202
	if (sym->visible != tri) {
yann@1
   203
		sym->visible = tri;
yann@1
   204
		sym_set_changed(sym);
yann@1
   205
	}
yann@1
   206
	if (sym_is_choice_value(sym))
yann@1
   207
		return;
yann@2448
   208
	/* defaulting to "yes" if no explicit "depends on" are given */
yann@2448
   209
	tri = yes;
yann@2448
   210
	if (sym->dir_dep.expr)
yann@2448
   211
		tri = expr_calc_value(sym->dir_dep.expr);
yann@2448
   212
	if (tri == mod)
yann@2448
   213
		tri = yes;
yann@2448
   214
	if (sym->dir_dep.tri != tri) {
yann@2448
   215
		sym->dir_dep.tri = tri;
yann@2448
   216
		sym_set_changed(sym);
yann@2448
   217
	}
yann@1
   218
	tri = no;
yann@1
   219
	if (sym->rev_dep.expr)
yann@1
   220
		tri = expr_calc_value(sym->rev_dep.expr);
yann@1
   221
	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
yann@1
   222
		tri = yes;
yann@1
   223
	if (sym->rev_dep.tri != tri) {
yann@1
   224
		sym->rev_dep.tri = tri;
yann@1
   225
		sym_set_changed(sym);
yann@1
   226
	}
yann@1
   227
}
yann@1
   228
yann@2448
   229
/*
yann@2448
   230
 * Find the default symbol for a choice.
yann@2448
   231
 * First try the default values for the choice symbol
yann@2448
   232
 * Next locate the first visible choice value
yann@2448
   233
 * Return NULL if none was found
yann@2448
   234
 */
yann@2448
   235
struct symbol *sym_choice_default(struct symbol *sym)
yann@1
   236
{
yann@1
   237
	struct symbol *def_sym;
yann@1
   238
	struct property *prop;
yann@1
   239
	struct expr *e;
yann@1
   240
yann@1
   241
	/* any of the defaults visible? */
yann@1
   242
	for_all_defaults(sym, prop) {
yann@1
   243
		prop->visible.tri = expr_calc_value(prop->visible.expr);
yann@1
   244
		if (prop->visible.tri == no)
yann@1
   245
			continue;
yann@1
   246
		def_sym = prop_get_symbol(prop);
yann@1
   247
		if (def_sym->visible != no)
yann@1
   248
			return def_sym;
yann@1
   249
	}
yann@1
   250
yann@1
   251
	/* just get the first visible value */
yann@1
   252
	prop = sym_get_choice_prop(sym);
yann@2448
   253
	expr_list_for_each_sym(prop->expr, e, def_sym)
yann@1
   254
		if (def_sym->visible != no)
yann@1
   255
			return def_sym;
yann@1
   256
yann@2448
   257
	/* failed to locate any defaults */
yann@1
   258
	return NULL;
yann@1
   259
}
yann@1
   260
yann@2448
   261
static struct symbol *sym_calc_choice(struct symbol *sym)
yann@2448
   262
{
yann@2448
   263
	struct symbol *def_sym;
yann@2448
   264
	struct property *prop;
yann@2448
   265
	struct expr *e;
yann@2448
   266
yann@2448
   267
	/* first calculate all choice values' visibilities */
yann@2448
   268
	prop = sym_get_choice_prop(sym);
yann@2448
   269
	expr_list_for_each_sym(prop->expr, e, def_sym)
yann@2448
   270
		sym_calc_visibility(def_sym);
yann@2448
   271
yann@2448
   272
	/* is the user choice visible? */
yann@2448
   273
	def_sym = sym->def[S_DEF_USER].val;
yann@2448
   274
	if (def_sym && def_sym->visible != no)
yann@2448
   275
		return def_sym;
yann@2448
   276
yann@2448
   277
	def_sym = sym_choice_default(sym);
yann@2448
   278
yann@2448
   279
	if (def_sym == NULL)
yann@2448
   280
		/* no choice? reset tristate value */
yann@2448
   281
		sym->curr.tri = no;
yann@2448
   282
yann@2448
   283
	return def_sym;
yann@2448
   284
}
yann@2448
   285
yann@1
   286
void sym_calc_value(struct symbol *sym)
yann@1
   287
{
yann@1
   288
	struct symbol_value newval, oldval;
yann@1
   289
	struct property *prop;
yann@1
   290
	struct expr *e;
yann@1
   291
yann@1
   292
	if (!sym)
yann@1
   293
		return;
yann@1
   294
yann@1
   295
	if (sym->flags & SYMBOL_VALID)
yann@1
   296
		return;
yann@1
   297
	sym->flags |= SYMBOL_VALID;
yann@1
   298
yann@1
   299
	oldval = sym->curr;
yann@1
   300
yann@1
   301
	switch (sym->type) {
yann@1
   302
	case S_INT:
yann@1
   303
	case S_HEX:
yann@1
   304
	case S_STRING:
yann@1
   305
		newval = symbol_empty.curr;
yann@1
   306
		break;
yann@1
   307
	case S_BOOLEAN:
yann@1
   308
	case S_TRISTATE:
yann@1
   309
		newval = symbol_no.curr;
yann@1
   310
		break;
yann@1
   311
	default:
yann@1
   312
		sym->curr.val = sym->name;
yann@1
   313
		sym->curr.tri = no;
yann@1
   314
		return;
yann@1
   315
	}
yann@1
   316
	if (!sym_is_choice_value(sym))
yann@1
   317
		sym->flags &= ~SYMBOL_WRITE;
yann@1
   318
yann@1
   319
	sym_calc_visibility(sym);
yann@1
   320
yann@1
   321
	/* set default if recursively called */
yann@1
   322
	sym->curr = newval;
yann@1
   323
yann@1
   324
	switch (sym_get_type(sym)) {
yann@1
   325
	case S_BOOLEAN:
yann@1
   326
	case S_TRISTATE:
yann@1
   327
		if (sym_is_choice_value(sym) && sym->visible == yes) {
yann@1
   328
			prop = sym_get_choice_prop(sym);
yann@1
   329
			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
yann@943
   330
		} else {
yann@943
   331
			if (sym->visible != no) {
yann@943
   332
				/* if the symbol is visible use the user value
yann@943
   333
				 * if available, otherwise try the default value
yann@943
   334
				 */
yann@943
   335
				sym->flags |= SYMBOL_WRITE;
yann@943
   336
				if (sym_has_value(sym)) {
yann@943
   337
					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
yann@943
   338
							      sym->visible);
yann@943
   339
					goto calc_newval;
yann@943
   340
				}
yann@943
   341
			}
yann@943
   342
			if (sym->rev_dep.tri != no)
yann@943
   343
				sym->flags |= SYMBOL_WRITE;
yann@943
   344
			if (!sym_is_choice(sym)) {
yann@1
   345
				prop = sym_get_default_prop(sym);
yann@943
   346
				if (prop) {
yann@943
   347
					sym->flags |= SYMBOL_WRITE;
yann@943
   348
					newval.tri = EXPR_AND(expr_calc_value(prop->expr),
yann@943
   349
							      prop->visible.tri);
yann@943
   350
				}
yann@1
   351
			}
yann@943
   352
		calc_newval:
yann@2448
   353
			if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
yann@2448
   354
				struct expr *e;
yann@2448
   355
				e = expr_simplify_unmet_dep(sym->rev_dep.expr,
yann@2448
   356
				    sym->dir_dep.expr);
yann@2448
   357
				fprintf(stderr, "warning: (");
yann@2448
   358
				expr_fprint(e, stderr);
yann@2448
   359
				fprintf(stderr, ") selects %s which has unmet direct dependencies (",
yann@2448
   360
					sym->name);
yann@2448
   361
				expr_fprint(sym->dir_dep.expr, stderr);
yann@2448
   362
				fprintf(stderr, ")\n");
yann@2448
   363
				expr_free(e);
yann@2448
   364
			}
yann@943
   365
			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
yann@1
   366
		}
yann@1
   367
		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
yann@1
   368
			newval.tri = yes;
yann@1
   369
		break;
yann@1
   370
	case S_STRING:
yann@1
   371
	case S_HEX:
yann@1
   372
	case S_INT:
yann@1
   373
		if (sym->visible != no) {
yann@1
   374
			sym->flags |= SYMBOL_WRITE;
yann@1
   375
			if (sym_has_value(sym)) {
yann@1
   376
				newval.val = sym->def[S_DEF_USER].val;
yann@1
   377
				break;
yann@1
   378
			}
yann@1
   379
		}
yann@1
   380
		prop = sym_get_default_prop(sym);
yann@1
   381
		if (prop) {
yann@1
   382
			struct symbol *ds = prop_get_symbol(prop);
yann@1
   383
			if (ds) {
yann@1
   384
				sym->flags |= SYMBOL_WRITE;
yann@1
   385
				sym_calc_value(ds);
yann@1
   386
				newval.val = ds->curr.val;
yann@1
   387
			}
yann@1
   388
		}
yann@1
   389
		break;
yann@1
   390
	default:
yann@1
   391
		;
yann@1
   392
	}
yann@1
   393
yann@1
   394
	sym->curr = newval;
yann@1
   395
	if (sym_is_choice(sym) && newval.tri == yes)
yann@1
   396
		sym->curr.val = sym_calc_choice(sym);
yann@1
   397
	sym_validate_range(sym);
yann@1
   398
yann@1
   399
	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
yann@1
   400
		sym_set_changed(sym);
yann@1
   401
		if (modules_sym == sym) {
yann@1
   402
			sym_set_all_changed();
yann@1
   403
			modules_val = modules_sym->curr.tri;
yann@1
   404
		}
yann@1
   405
	}
yann@1
   406
yann@1
   407
	if (sym_is_choice(sym)) {
yann@943
   408
		struct symbol *choice_sym;
yann@943
   409
yann@1
   410
		prop = sym_get_choice_prop(sym);
yann@943
   411
		expr_list_for_each_sym(prop->expr, e, choice_sym) {
yann@2448
   412
			if ((sym->flags & SYMBOL_WRITE) &&
yann@2448
   413
			    choice_sym->visible != no)
yann@2448
   414
				choice_sym->flags |= SYMBOL_WRITE;
yann@2448
   415
			if (sym->flags & SYMBOL_CHANGED)
yann@943
   416
				sym_set_changed(choice_sym);
yann@1
   417
		}
yann@1
   418
	}
yann@943
   419
yann@943
   420
	if (sym->flags & SYMBOL_AUTO)
yann@943
   421
		sym->flags &= ~SYMBOL_WRITE;
yann@1
   422
}
yann@1
   423
yann@1
   424
void sym_clear_all_valid(void)
yann@1
   425
{
yann@1
   426
	struct symbol *sym;
yann@1
   427
	int i;
yann@1
   428
yann@1
   429
	for_all_symbols(i, sym)
yann@1
   430
		sym->flags &= ~SYMBOL_VALID;
yann@39
   431
	sym_add_change_count(1);
yann@1
   432
	if (modules_sym)
yann@1
   433
		sym_calc_value(modules_sym);
yann@1
   434
}
yann@1
   435
yann@1
   436
void sym_set_changed(struct symbol *sym)
yann@1
   437
{
yann@1
   438
	struct property *prop;
yann@1
   439
yann@1
   440
	sym->flags |= SYMBOL_CHANGED;
yann@1
   441
	for (prop = sym->prop; prop; prop = prop->next) {
yann@1
   442
		if (prop->menu)
yann@1
   443
			prop->menu->flags |= MENU_CHANGED;
yann@1
   444
	}
yann@1
   445
}
yann@1
   446
yann@1
   447
void sym_set_all_changed(void)
yann@1
   448
{
yann@1
   449
	struct symbol *sym;
yann@1
   450
	int i;
yann@1
   451
yann@1
   452
	for_all_symbols(i, sym)
yann@1
   453
		sym_set_changed(sym);
yann@1
   454
}
yann@1
   455
yann@1
   456
bool sym_tristate_within_range(struct symbol *sym, tristate val)
yann@1
   457
{
yann@1
   458
	int type = sym_get_type(sym);
yann@1
   459
yann@1
   460
	if (sym->visible == no)
yann@1
   461
		return false;
yann@1
   462
yann@1
   463
	if (type != S_BOOLEAN && type != S_TRISTATE)
yann@1
   464
		return false;
yann@1
   465
yann@1
   466
	if (type == S_BOOLEAN && val == mod)
yann@1
   467
		return false;
yann@1
   468
	if (sym->visible <= sym->rev_dep.tri)
yann@1
   469
		return false;
yann@1
   470
	if (sym_is_choice_value(sym) && sym->visible == yes)
yann@1
   471
		return val == yes;
yann@1
   472
	return val >= sym->rev_dep.tri && val <= sym->visible;
yann@1
   473
}
yann@1
   474
yann@1
   475
bool sym_set_tristate_value(struct symbol *sym, tristate val)
yann@1
   476
{
yann@1
   477
	tristate oldval = sym_get_tristate_value(sym);
yann@1
   478
yann@1
   479
	if (oldval != val && !sym_tristate_within_range(sym, val))
yann@1
   480
		return false;
yann@1
   481
yann@1
   482
	if (!(sym->flags & SYMBOL_DEF_USER)) {
yann@1
   483
		sym->flags |= SYMBOL_DEF_USER;
yann@1
   484
		sym_set_changed(sym);
yann@1
   485
	}
yann@1
   486
	/*
yann@1
   487
	 * setting a choice value also resets the new flag of the choice
yann@1
   488
	 * symbol and all other choice values.
yann@1
   489
	 */
yann@1
   490
	if (sym_is_choice_value(sym) && val == yes) {
yann@1
   491
		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
yann@1
   492
		struct property *prop;
yann@1
   493
		struct expr *e;
yann@1
   494
yann@1
   495
		cs->def[S_DEF_USER].val = sym;
yann@1
   496
		cs->flags |= SYMBOL_DEF_USER;
yann@1
   497
		prop = sym_get_choice_prop(cs);
yann@1
   498
		for (e = prop->expr; e; e = e->left.expr) {
yann@1
   499
			if (e->right.sym->visible != no)
yann@1
   500
				e->right.sym->flags |= SYMBOL_DEF_USER;
yann@1
   501
		}
yann@1
   502
	}
yann@1
   503
yann@1
   504
	sym->def[S_DEF_USER].tri = val;
yann@1
   505
	if (oldval != val)
yann@1
   506
		sym_clear_all_valid();
yann@1
   507
yann@1
   508
	return true;
yann@1
   509
}
yann@1
   510
yann@1
   511
tristate sym_toggle_tristate_value(struct symbol *sym)
yann@1
   512
{
yann@1
   513
	tristate oldval, newval;
yann@1
   514
yann@1
   515
	oldval = newval = sym_get_tristate_value(sym);
yann@1
   516
	do {
yann@1
   517
		switch (newval) {
yann@1
   518
		case no:
yann@1
   519
			newval = mod;
yann@1
   520
			break;
yann@1
   521
		case mod:
yann@1
   522
			newval = yes;
yann@1
   523
			break;
yann@1
   524
		case yes:
yann@1
   525
			newval = no;
yann@1
   526
			break;
yann@1
   527
		}
yann@1
   528
		if (sym_set_tristate_value(sym, newval))
yann@1
   529
			break;
yann@1
   530
	} while (oldval != newval);
yann@1
   531
	return newval;
yann@1
   532
}
yann@1
   533
yann@1
   534
bool sym_string_valid(struct symbol *sym, const char *str)
yann@1
   535
{
yann@1
   536
	signed char ch;
yann@1
   537
yann@1
   538
	switch (sym->type) {
yann@1
   539
	case S_STRING:
yann@1
   540
		return true;
yann@1
   541
	case S_INT:
yann@1
   542
		ch = *str++;
yann@1
   543
		if (ch == '-')
yann@1
   544
			ch = *str++;
yann@1
   545
		if (!isdigit(ch))
yann@1
   546
			return false;
yann@1
   547
		if (ch == '0' && *str != 0)
yann@1
   548
			return false;
yann@1
   549
		while ((ch = *str++)) {
yann@1
   550
			if (!isdigit(ch))
yann@1
   551
				return false;
yann@1
   552
		}
yann@1
   553
		return true;
yann@1
   554
	case S_HEX:
yann@1
   555
		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
yann@1
   556
			str += 2;
yann@1
   557
		ch = *str++;
yann@1
   558
		do {
yann@1
   559
			if (!isxdigit(ch))
yann@1
   560
				return false;
yann@1
   561
		} while ((ch = *str++));
yann@1
   562
		return true;
yann@1
   563
	case S_BOOLEAN:
yann@1
   564
	case S_TRISTATE:
yann@1
   565
		switch (str[0]) {
yann@1
   566
		case 'y': case 'Y':
yann@1
   567
		case 'm': case 'M':
yann@1
   568
		case 'n': case 'N':
yann@1
   569
			return true;
yann@1
   570
		}
yann@1
   571
		return false;
yann@1
   572
	default:
yann@1
   573
		return false;
yann@1
   574
	}
yann@1
   575
}
yann@1
   576
yann@1
   577
bool sym_string_within_range(struct symbol *sym, const char *str)
yann@1
   578
{
yann@1
   579
	struct property *prop;
yann@1
   580
	int val;
yann@1
   581
yann@1
   582
	switch (sym->type) {
yann@1
   583
	case S_STRING:
yann@1
   584
		return sym_string_valid(sym, str);
yann@1
   585
	case S_INT:
yann@1
   586
		if (!sym_string_valid(sym, str))
yann@1
   587
			return false;
yann@1
   588
		prop = sym_get_range_prop(sym);
yann@1
   589
		if (!prop)
yann@1
   590
			return true;
yann@1
   591
		val = strtol(str, NULL, 10);
yann@1
   592
		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
yann@1
   593
		       val <= sym_get_range_val(prop->expr->right.sym, 10);
yann@1
   594
	case S_HEX:
yann@1
   595
		if (!sym_string_valid(sym, str))
yann@1
   596
			return false;
yann@1
   597
		prop = sym_get_range_prop(sym);
yann@1
   598
		if (!prop)
yann@1
   599
			return true;
yann@1
   600
		val = strtol(str, NULL, 16);
yann@1
   601
		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
yann@1
   602
		       val <= sym_get_range_val(prop->expr->right.sym, 16);
yann@1
   603
	case S_BOOLEAN:
yann@1
   604
	case S_TRISTATE:
yann@1
   605
		switch (str[0]) {
yann@1
   606
		case 'y': case 'Y':
yann@1
   607
			return sym_tristate_within_range(sym, yes);
yann@1
   608
		case 'm': case 'M':
yann@1
   609
			return sym_tristate_within_range(sym, mod);
yann@1
   610
		case 'n': case 'N':
yann@1
   611
			return sym_tristate_within_range(sym, no);
yann@1
   612
		}
yann@1
   613
		return false;
yann@1
   614
	default:
yann@1
   615
		return false;
yann@1
   616
	}
yann@1
   617
}
yann@1
   618
yann@1
   619
bool sym_set_string_value(struct symbol *sym, const char *newval)
yann@1
   620
{
yann@1
   621
	const char *oldval;
yann@1
   622
	char *val;
yann@1
   623
	int size;
yann@1
   624
yann@1
   625
	switch (sym->type) {
yann@1
   626
	case S_BOOLEAN:
yann@1
   627
	case S_TRISTATE:
yann@1
   628
		switch (newval[0]) {
yann@1
   629
		case 'y': case 'Y':
yann@1
   630
			return sym_set_tristate_value(sym, yes);
yann@1
   631
		case 'm': case 'M':
yann@1
   632
			return sym_set_tristate_value(sym, mod);
yann@1
   633
		case 'n': case 'N':
yann@1
   634
			return sym_set_tristate_value(sym, no);
yann@1
   635
		}
yann@1
   636
		return false;
yann@1
   637
	default:
yann@1
   638
		;
yann@1
   639
	}
yann@1
   640
yann@1
   641
	if (!sym_string_within_range(sym, newval))
yann@1
   642
		return false;
yann@1
   643
yann@1
   644
	if (!(sym->flags & SYMBOL_DEF_USER)) {
yann@1
   645
		sym->flags |= SYMBOL_DEF_USER;
yann@1
   646
		sym_set_changed(sym);
yann@1
   647
	}
yann@1
   648
yann@1
   649
	oldval = sym->def[S_DEF_USER].val;
yann@1
   650
	size = strlen(newval) + 1;
yann@1
   651
	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
yann@1
   652
		size += 2;
yann@1
   653
		sym->def[S_DEF_USER].val = val = malloc(size);
yann@1
   654
		*val++ = '0';
yann@1
   655
		*val++ = 'x';
yann@1
   656
	} else if (!oldval || strcmp(oldval, newval))
yann@1
   657
		sym->def[S_DEF_USER].val = val = malloc(size);
yann@1
   658
	else
yann@1
   659
		return true;
yann@1
   660
yann@1
   661
	strcpy(val, newval);
yann@1
   662
	free((void *)oldval);
yann@1
   663
	sym_clear_all_valid();
yann@1
   664
yann@1
   665
	return true;
yann@1
   666
}
yann@1
   667
yann@2448
   668
/*
yann@2448
   669
 * Find the default value associated to a symbol.
yann@2448
   670
 * For tristate symbol handle the modules=n case
yann@2448
   671
 * in which case "m" becomes "y".
yann@2448
   672
 * If the symbol does not have any default then fallback
yann@2448
   673
 * to the fixed default values.
yann@2448
   674
 */
yann@2448
   675
const char *sym_get_string_default(struct symbol *sym)
yann@2448
   676
{
yann@2448
   677
	struct property *prop;
yann@2448
   678
	struct symbol *ds;
yann@2448
   679
	const char *str;
yann@2448
   680
	tristate val;
yann@2448
   681
yann@2448
   682
	sym_calc_visibility(sym);
yann@2448
   683
	sym_calc_value(modules_sym);
yann@2448
   684
	val = symbol_no.curr.tri;
yann@2448
   685
	str = symbol_empty.curr.val;
yann@2448
   686
yann@2448
   687
	/* If symbol has a default value look it up */
yann@2448
   688
	prop = sym_get_default_prop(sym);
yann@2448
   689
	if (prop != NULL) {
yann@2448
   690
		switch (sym->type) {
yann@2448
   691
		case S_BOOLEAN:
yann@2448
   692
		case S_TRISTATE:
yann@2448
   693
			/* The visibility may limit the value from yes => mod */
yann@2448
   694
			val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
yann@2448
   695
			break;
yann@2448
   696
		default:
yann@2448
   697
			/*
yann@2448
   698
			 * The following fails to handle the situation
yann@2448
   699
			 * where a default value is further limited by
yann@2448
   700
			 * the valid range.
yann@2448
   701
			 */
yann@2448
   702
			ds = prop_get_symbol(prop);
yann@2448
   703
			if (ds != NULL) {
yann@2448
   704
				sym_calc_value(ds);
yann@2448
   705
				str = (const char *)ds->curr.val;
yann@2448
   706
			}
yann@2448
   707
		}
yann@2448
   708
	}
yann@2448
   709
yann@2448
   710
	/* Handle select statements */
yann@2448
   711
	val = EXPR_OR(val, sym->rev_dep.tri);
yann@2448
   712
yann@2448
   713
	/* transpose mod to yes if modules are not enabled */
yann@2448
   714
	if (val == mod)
yann@2448
   715
		if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
yann@2448
   716
			val = yes;
yann@2448
   717
yann@2448
   718
	/* transpose mod to yes if type is bool */
yann@2448
   719
	if (sym->type == S_BOOLEAN && val == mod)
yann@2448
   720
		val = yes;
yann@2448
   721
yann@2448
   722
	switch (sym->type) {
yann@2448
   723
	case S_BOOLEAN:
yann@2448
   724
	case S_TRISTATE:
yann@2448
   725
		switch (val) {
yann@2448
   726
		case no: return "n";
yann@2448
   727
		case mod: return "m";
yann@2448
   728
		case yes: return "y";
yann@2448
   729
		}
yann@2448
   730
	case S_INT:
yann@2448
   731
	case S_HEX:
yann@2448
   732
		return str;
yann@2448
   733
	case S_STRING:
yann@2448
   734
		return str;
yann@2448
   735
	case S_OTHER:
yann@2448
   736
	case S_UNKNOWN:
yann@2448
   737
		break;
yann@2448
   738
	}
yann@2448
   739
	return "";
yann@2448
   740
}
yann@2448
   741
yann@1
   742
const char *sym_get_string_value(struct symbol *sym)
yann@1
   743
{
yann@1
   744
	tristate val;
yann@1
   745
yann@1
   746
	switch (sym->type) {
yann@1
   747
	case S_BOOLEAN:
yann@1
   748
	case S_TRISTATE:
yann@1
   749
		val = sym_get_tristate_value(sym);
yann@1
   750
		switch (val) {
yann@1
   751
		case no:
yann@1
   752
			return "n";
yann@1
   753
		case mod:
yann@1
   754
			return "m";
yann@1
   755
		case yes:
yann@1
   756
			return "y";
yann@1
   757
		}
yann@1
   758
		break;
yann@1
   759
	default:
yann@1
   760
		;
yann@1
   761
	}
yann@1
   762
	return (const char *)sym->curr.val;
yann@1
   763
}
yann@1
   764
yann@1
   765
bool sym_is_changable(struct symbol *sym)
yann@1
   766
{
yann@1
   767
	return sym->visible > sym->rev_dep.tri;
yann@1
   768
}
yann@1
   769
yann@2448
   770
static unsigned strhash(const char *s)
yann@2448
   771
{
yann@2448
   772
	/* fnv32 hash */
yann@2448
   773
	unsigned hash = 2166136261U;
yann@2448
   774
	for (; *s; s++)
yann@2448
   775
		hash = (hash ^ *s) * 0x01000193;
yann@2448
   776
	return hash;
yann@2448
   777
}
yann@2448
   778
yann@943
   779
struct symbol *sym_lookup(const char *name, int flags)
yann@1
   780
{
yann@1
   781
	struct symbol *symbol;
yann@1
   782
	char *new_name;
yann@2448
   783
	int hash;
yann@1
   784
yann@1
   785
	if (name) {
yann@1
   786
		if (name[0] && !name[1]) {
yann@1
   787
			switch (name[0]) {
yann@1
   788
			case 'y': return &symbol_yes;
yann@1
   789
			case 'm': return &symbol_mod;
yann@1
   790
			case 'n': return &symbol_no;
yann@1
   791
			}
yann@1
   792
		}
yann@2448
   793
		hash = strhash(name) % SYMBOL_HASHSIZE;
yann@1
   794
yann@1
   795
		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
yann@2448
   796
			if (symbol->name &&
yann@2448
   797
			    !strcmp(symbol->name, name) &&
yann@943
   798
			    (flags ? symbol->flags & flags
yann@943
   799
				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
yann@943
   800
				return symbol;
yann@1
   801
		}
yann@1
   802
		new_name = strdup(name);
yann@1
   803
	} else {
yann@1
   804
		new_name = NULL;
yann@2448
   805
		hash = 0;
yann@1
   806
	}
yann@1
   807
yann@1
   808
	symbol = malloc(sizeof(*symbol));
yann@1
   809
	memset(symbol, 0, sizeof(*symbol));
yann@1
   810
	symbol->name = new_name;
yann@1
   811
	symbol->type = S_UNKNOWN;
yann@943
   812
	symbol->flags |= flags;
yann@1
   813
yann@1
   814
	symbol->next = symbol_hash[hash];
yann@1
   815
	symbol_hash[hash] = symbol;
yann@1
   816
yann@1
   817
	return symbol;
yann@1
   818
}
yann@1
   819
yann@1
   820
struct symbol *sym_find(const char *name)
yann@1
   821
{
yann@1
   822
	struct symbol *symbol = NULL;
yann@1
   823
	int hash = 0;
yann@1
   824
yann@1
   825
	if (!name)
yann@1
   826
		return NULL;
yann@1
   827
yann@1
   828
	if (name[0] && !name[1]) {
yann@1
   829
		switch (name[0]) {
yann@1
   830
		case 'y': return &symbol_yes;
yann@1
   831
		case 'm': return &symbol_mod;
yann@1
   832
		case 'n': return &symbol_no;
yann@1
   833
		}
yann@1
   834
	}
yann@2448
   835
	hash = strhash(name) % SYMBOL_HASHSIZE;
yann@1
   836
yann@1
   837
	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
yann@2448
   838
		if (symbol->name &&
yann@2448
   839
		    !strcmp(symbol->name, name) &&
yann@1
   840
		    !(symbol->flags & SYMBOL_CONST))
yann@1
   841
				break;
yann@1
   842
	}
yann@1
   843
yann@1
   844
	return symbol;
yann@1
   845
}
yann@1
   846
yann@2448
   847
/*
yann@2448
   848
 * Expand symbol's names embedded in the string given in argument. Symbols'
yann@2448
   849
 * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
yann@2448
   850
 * the empty string.
yann@2448
   851
 */
yann@2448
   852
const char *sym_expand_string_value(const char *in)
yann@2448
   853
{
yann@2448
   854
	const char *src;
yann@2448
   855
	char *res;
yann@2448
   856
	size_t reslen;
yann@2448
   857
yann@2448
   858
	reslen = strlen(in) + 1;
yann@2448
   859
	res = malloc(reslen);
yann@2448
   860
	res[0] = '\0';
yann@2448
   861
yann@2448
   862
	while ((src = strchr(in, '$'))) {
yann@2448
   863
		char *p, name[SYMBOL_MAXLENGTH];
yann@2448
   864
		const char *symval = "";
yann@2448
   865
		struct symbol *sym;
yann@2448
   866
		size_t newlen;
yann@2448
   867
yann@2448
   868
		strncat(res, in, src - in);
yann@2448
   869
		src++;
yann@2448
   870
yann@2448
   871
		p = name;
yann@2448
   872
		while (isalnum(*src) || *src == '_')
yann@2448
   873
			*p++ = *src++;
yann@2448
   874
		*p = '\0';
yann@2448
   875
yann@2448
   876
		sym = sym_find(name);
yann@2448
   877
		if (sym != NULL) {
yann@2448
   878
			sym_calc_value(sym);
yann@2448
   879
			symval = sym_get_string_value(sym);
yann@2448
   880
		}
yann@2448
   881
yann@2448
   882
		newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
yann@2448
   883
		if (newlen > reslen) {
yann@2448
   884
			reslen = newlen;
yann@2448
   885
			res = realloc(res, reslen);
yann@2448
   886
		}
yann@2448
   887
yann@2448
   888
		strcat(res, symval);
yann@2448
   889
		in = src;
yann@2448
   890
	}
yann@2448
   891
	strcat(res, in);
yann@2448
   892
yann@2448
   893
	return res;
yann@2448
   894
}
yann@2448
   895
yann@1
   896
struct symbol **sym_re_search(const char *pattern)
yann@1
   897
{
yann@1
   898
	struct symbol *sym, **sym_arr = NULL;
yann@1
   899
	int i, cnt, size;
yann@1
   900
	regex_t re;
yann@1
   901
yann@1
   902
	cnt = size = 0;
yann@1
   903
	/* Skip if empty */
yann@1
   904
	if (strlen(pattern) == 0)
yann@1
   905
		return NULL;
yann@1
   906
	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
yann@1
   907
		return NULL;
yann@1
   908
yann@1
   909
	for_all_symbols(i, sym) {
yann@1
   910
		if (sym->flags & SYMBOL_CONST || !sym->name)
yann@1
   911
			continue;
yann@1
   912
		if (regexec(&re, sym->name, 0, NULL, 0))
yann@1
   913
			continue;
yann@1
   914
		if (cnt + 1 >= size) {
yann@1
   915
			void *tmp = sym_arr;
yann@1
   916
			size += 16;
yann@1
   917
			sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
yann@1
   918
			if (!sym_arr) {
yann@1
   919
				free(tmp);
yann@1
   920
				return NULL;
yann@1
   921
			}
yann@1
   922
		}
yann@2448
   923
		sym_calc_value(sym);
yann@1
   924
		sym_arr[cnt++] = sym;
yann@1
   925
	}
yann@1
   926
	if (sym_arr)
yann@1
   927
		sym_arr[cnt] = NULL;
yann@1
   928
	regfree(&re);
yann@1
   929
yann@1
   930
	return sym_arr;
yann@1
   931
}
yann@1
   932
yann@2448
   933
/*
yann@2448
   934
 * When we check for recursive dependencies we use a stack to save
yann@2448
   935
 * current state so we can print out relevant info to user.
yann@2448
   936
 * The entries are located on the call stack so no need to free memory.
yann@2448
   937
 * Note inser() remove() must always match to properly clear the stack.
yann@2448
   938
 */
yann@2448
   939
static struct dep_stack {
yann@2448
   940
	struct dep_stack *prev, *next;
yann@2448
   941
	struct symbol *sym;
yann@2448
   942
	struct property *prop;
yann@2448
   943
	struct expr *expr;
yann@2448
   944
} *check_top;
yann@2448
   945
yann@2448
   946
static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
yann@2448
   947
{
yann@2448
   948
	memset(stack, 0, sizeof(*stack));
yann@2448
   949
	if (check_top)
yann@2448
   950
		check_top->next = stack;
yann@2448
   951
	stack->prev = check_top;
yann@2448
   952
	stack->sym = sym;
yann@2448
   953
	check_top = stack;
yann@2448
   954
}
yann@2448
   955
yann@2448
   956
static void dep_stack_remove(void)
yann@2448
   957
{
yann@2448
   958
	check_top = check_top->prev;
yann@2448
   959
	if (check_top)
yann@2448
   960
		check_top->next = NULL;
yann@2448
   961
}
yann@2448
   962
yann@2448
   963
/*
yann@2448
   964
 * Called when we have detected a recursive dependency.
yann@2448
   965
 * check_top point to the top of the stact so we use
yann@2448
   966
 * the ->prev pointer to locate the bottom of the stack.
yann@2448
   967
 */
yann@2448
   968
static void sym_check_print_recursive(struct symbol *last_sym)
yann@2448
   969
{
yann@2448
   970
	struct dep_stack *stack;
yann@2448
   971
	struct symbol *sym, *next_sym;
yann@2448
   972
	struct menu *menu = NULL;
yann@2448
   973
	struct property *prop;
yann@2448
   974
	struct dep_stack cv_stack;
yann@2448
   975
yann@2448
   976
	if (sym_is_choice_value(last_sym)) {
yann@2448
   977
		dep_stack_insert(&cv_stack, last_sym);
yann@2448
   978
		last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
yann@2448
   979
	}
yann@2448
   980
yann@2448
   981
	for (stack = check_top; stack != NULL; stack = stack->prev)
yann@2448
   982
		if (stack->sym == last_sym)
yann@2448
   983
			break;
yann@2448
   984
	if (!stack) {
yann@2448
   985
		fprintf(stderr, "unexpected recursive dependency error\n");
yann@2448
   986
		return;
yann@2448
   987
	}
yann@2448
   988
yann@2448
   989
	for (; stack; stack = stack->next) {
yann@2448
   990
		sym = stack->sym;
yann@2448
   991
		next_sym = stack->next ? stack->next->sym : last_sym;
yann@2448
   992
		prop = stack->prop;
yann@2448
   993
		if (prop == NULL)
yann@2448
   994
			prop = stack->sym->prop;
yann@2448
   995
yann@2448
   996
		/* for choice values find the menu entry (used below) */
yann@2448
   997
		if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
yann@2448
   998
			for (prop = sym->prop; prop; prop = prop->next) {
yann@2448
   999
				menu = prop->menu;
yann@2448
  1000
				if (prop->menu)
yann@2448
  1001
					break;
yann@2448
  1002
			}
yann@2448
  1003
		}
yann@2448
  1004
		if (stack->sym == last_sym)
yann@2448
  1005
			fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
yann@2448
  1006
				prop->file->name, prop->lineno);
yann@2448
  1007
		if (stack->expr) {
yann@2448
  1008
			fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
yann@2448
  1009
				prop->file->name, prop->lineno,
yann@2448
  1010
				sym->name ? sym->name : "<choice>",
yann@2448
  1011
				prop_get_type_name(prop->type),
yann@2448
  1012
				next_sym->name ? next_sym->name : "<choice>");
yann@2448
  1013
		} else if (stack->prop) {
yann@2448
  1014
			fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
yann@2448
  1015
				prop->file->name, prop->lineno,
yann@2448
  1016
				sym->name ? sym->name : "<choice>",
yann@2448
  1017
				next_sym->name ? next_sym->name : "<choice>");
yann@2448
  1018
		} else if (sym_is_choice(sym)) {
yann@2448
  1019
			fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
yann@2448
  1020
				menu->file->name, menu->lineno,
yann@2448
  1021
				sym->name ? sym->name : "<choice>",
yann@2448
  1022
				next_sym->name ? next_sym->name : "<choice>");
yann@2448
  1023
		} else if (sym_is_choice_value(sym)) {
yann@2448
  1024
			fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
yann@2448
  1025
				menu->file->name, menu->lineno,
yann@2448
  1026
				sym->name ? sym->name : "<choice>",
yann@2448
  1027
				next_sym->name ? next_sym->name : "<choice>");
yann@2448
  1028
		} else {
yann@2448
  1029
			fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
yann@2448
  1030
				prop->file->name, prop->lineno,
yann@2448
  1031
				sym->name ? sym->name : "<choice>",
yann@2448
  1032
				next_sym->name ? next_sym->name : "<choice>");
yann@2448
  1033
		}
yann@2448
  1034
	}
yann@2448
  1035
yann@2448
  1036
	if (check_top == &cv_stack)
yann@2448
  1037
		dep_stack_remove();
yann@2448
  1038
}
yann@1
  1039
yann@1
  1040
static struct symbol *sym_check_expr_deps(struct expr *e)
yann@1
  1041
{
yann@1
  1042
	struct symbol *sym;
yann@1
  1043
yann@1
  1044
	if (!e)
yann@1
  1045
		return NULL;
yann@1
  1046
	switch (e->type) {
yann@1
  1047
	case E_OR:
yann@1
  1048
	case E_AND:
yann@1
  1049
		sym = sym_check_expr_deps(e->left.expr);
yann@1
  1050
		if (sym)
yann@1
  1051
			return sym;
yann@1
  1052
		return sym_check_expr_deps(e->right.expr);
yann@1
  1053
	case E_NOT:
yann@1
  1054
		return sym_check_expr_deps(e->left.expr);
yann@1
  1055
	case E_EQUAL:
yann@1
  1056
	case E_UNEQUAL:
yann@1
  1057
		sym = sym_check_deps(e->left.sym);
yann@1
  1058
		if (sym)
yann@1
  1059
			return sym;
yann@1
  1060
		return sym_check_deps(e->right.sym);
yann@1
  1061
	case E_SYMBOL:
yann@1
  1062
		return sym_check_deps(e->left.sym);
yann@1
  1063
	default:
yann@1
  1064
		break;
yann@1
  1065
	}
yann@1
  1066
	printf("Oops! How to check %d?\n", e->type);
yann@1
  1067
	return NULL;
yann@1
  1068
}
yann@1
  1069
yann@943
  1070
/* return NULL when dependencies are OK */
yann@943
  1071
static struct symbol *sym_check_sym_deps(struct symbol *sym)
yann@943
  1072
{
yann@943
  1073
	struct symbol *sym2;
yann@943
  1074
	struct property *prop;
yann@2448
  1075
	struct dep_stack stack;
yann@2448
  1076
yann@2448
  1077
	dep_stack_insert(&stack, sym);
yann@943
  1078
yann@943
  1079
	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
yann@943
  1080
	if (sym2)
yann@2448
  1081
		goto out;
yann@943
  1082
yann@943
  1083
	for (prop = sym->prop; prop; prop = prop->next) {
yann@943
  1084
		if (prop->type == P_CHOICE || prop->type == P_SELECT)
yann@943
  1085
			continue;
yann@2448
  1086
		stack.prop = prop;
yann@943
  1087
		sym2 = sym_check_expr_deps(prop->visible.expr);
yann@943
  1088
		if (sym2)
yann@943
  1089
			break;
yann@943
  1090
		if (prop->type != P_DEFAULT || sym_is_choice(sym))
yann@943
  1091
			continue;
yann@2448
  1092
		stack.expr = prop->expr;
yann@943
  1093
		sym2 = sym_check_expr_deps(prop->expr);
yann@943
  1094
		if (sym2)
yann@943
  1095
			break;
yann@2448
  1096
		stack.expr = NULL;
yann@943
  1097
	}
yann@943
  1098
yann@2448
  1099
out:
yann@2448
  1100
	dep_stack_remove();
yann@2448
  1101
yann@943
  1102
	return sym2;
yann@943
  1103
}
yann@943
  1104
yann@943
  1105
static struct symbol *sym_check_choice_deps(struct symbol *choice)
yann@943
  1106
{
yann@943
  1107
	struct symbol *sym, *sym2;
yann@943
  1108
	struct property *prop;
yann@943
  1109
	struct expr *e;
yann@2448
  1110
	struct dep_stack stack;
yann@2448
  1111
yann@2448
  1112
	dep_stack_insert(&stack, choice);
yann@943
  1113
yann@943
  1114
	prop = sym_get_choice_prop(choice);
yann@943
  1115
	expr_list_for_each_sym(prop->expr, e, sym)
yann@943
  1116
		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
yann@943
  1117
yann@943
  1118
	choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
yann@943
  1119
	sym2 = sym_check_sym_deps(choice);
yann@943
  1120
	choice->flags &= ~SYMBOL_CHECK;
yann@943
  1121
	if (sym2)
yann@943
  1122
		goto out;
yann@943
  1123
yann@943
  1124
	expr_list_for_each_sym(prop->expr, e, sym) {
yann@943
  1125
		sym2 = sym_check_sym_deps(sym);
yann@2448
  1126
		if (sym2)
yann@943
  1127
			break;
yann@943
  1128
	}
yann@943
  1129
out:
yann@943
  1130
	expr_list_for_each_sym(prop->expr, e, sym)
yann@943
  1131
		sym->flags &= ~SYMBOL_CHECK;
yann@943
  1132
yann@943
  1133
	if (sym2 && sym_is_choice_value(sym2) &&
yann@943
  1134
	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
yann@943
  1135
		sym2 = choice;
yann@943
  1136
yann@2448
  1137
	dep_stack_remove();
yann@2448
  1138
yann@943
  1139
	return sym2;
yann@943
  1140
}
yann@943
  1141
yann@1
  1142
struct symbol *sym_check_deps(struct symbol *sym)
yann@1
  1143
{
yann@1
  1144
	struct symbol *sym2;
yann@1
  1145
	struct property *prop;
yann@1
  1146
yann@1
  1147
	if (sym->flags & SYMBOL_CHECK) {
yann@2448
  1148
		sym_check_print_recursive(sym);
yann@1
  1149
		return sym;
yann@1
  1150
	}
yann@1
  1151
	if (sym->flags & SYMBOL_CHECKED)
yann@1
  1152
		return NULL;
yann@1
  1153
yann@943
  1154
	if (sym_is_choice_value(sym)) {
yann@2448
  1155
		struct dep_stack stack;
yann@2448
  1156
yann@943
  1157
		/* for choice groups start the check with main choice symbol */
yann@2448
  1158
		dep_stack_insert(&stack, sym);
yann@943
  1159
		prop = sym_get_choice_prop(sym);
yann@943
  1160
		sym2 = sym_check_deps(prop_get_symbol(prop));
yann@2448
  1161
		dep_stack_remove();
yann@943
  1162
	} else if (sym_is_choice(sym)) {
yann@943
  1163
		sym2 = sym_check_choice_deps(sym);
yann@943
  1164
	} else {
yann@943
  1165
		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
yann@943
  1166
		sym2 = sym_check_sym_deps(sym);
yann@943
  1167
		sym->flags &= ~SYMBOL_CHECK;
yann@943
  1168
	}
yann@1
  1169
yann@2448
  1170
	if (sym2 && sym2 == sym)
yann@2448
  1171
		sym2 = NULL;
yann@943
  1172
yann@1
  1173
	return sym2;
yann@1
  1174
}
yann@1
  1175
yann@1
  1176
struct property *prop_alloc(enum prop_type type, struct symbol *sym)
yann@1
  1177
{
yann@1
  1178
	struct property *prop;
yann@1
  1179
	struct property **propp;
yann@1
  1180
yann@1
  1181
	prop = malloc(sizeof(*prop));
yann@1
  1182
	memset(prop, 0, sizeof(*prop));
yann@1
  1183
	prop->type = type;
yann@1
  1184
	prop->sym = sym;
yann@1
  1185
	prop->file = current_file;
yann@1
  1186
	prop->lineno = zconf_lineno();
yann@1
  1187
yann@1
  1188
	/* append property to the prop list of symbol */
yann@1
  1189
	if (sym) {
yann@1
  1190
		for (propp = &sym->prop; *propp; propp = &(*propp)->next)
yann@1
  1191
			;
yann@1
  1192
		*propp = prop;
yann@1
  1193
	}
yann@1
  1194
yann@1
  1195
	return prop;
yann@1
  1196
}
yann@1
  1197
yann@1
  1198
struct symbol *prop_get_symbol(struct property *prop)
yann@1
  1199
{
yann@1
  1200
	if (prop->expr && (prop->expr->type == E_SYMBOL ||
yann@943
  1201
			   prop->expr->type == E_LIST))
yann@1
  1202
		return prop->expr->left.sym;
yann@1
  1203
	return NULL;
yann@1
  1204
}
yann@1
  1205
yann@1
  1206
const char *prop_get_type_name(enum prop_type type)
yann@1
  1207
{
yann@1
  1208
	switch (type) {
yann@1
  1209
	case P_PROMPT:
yann@1
  1210
		return "prompt";
yann@943
  1211
	case P_ENV:
yann@943
  1212
		return "env";
yann@1
  1213
	case P_COMMENT:
yann@1
  1214
		return "comment";
yann@1
  1215
	case P_MENU:
yann@1
  1216
		return "menu";
yann@1
  1217
	case P_DEFAULT:
yann@1
  1218
		return "default";
yann@1
  1219
	case P_CHOICE:
yann@1
  1220
		return "choice";
yann@1
  1221
	case P_SELECT:
yann@1
  1222
		return "select";
yann@1
  1223
	case P_RANGE:
yann@1
  1224
		return "range";
yann@2448
  1225
	case P_SYMBOL:
yann@2448
  1226
		return "symbol";
yann@1
  1227
	case P_UNKNOWN:
yann@1
  1228
		break;
yann@1
  1229
	}
yann@1
  1230
	return "unknown";
yann@1
  1231
}
yann@943
  1232
yann@2448
  1233
static void prop_add_env(const char *env)
yann@943
  1234
{
yann@943
  1235
	struct symbol *sym, *sym2;
yann@943
  1236
	struct property *prop;
yann@943
  1237
	char *p;
yann@943
  1238
yann@943
  1239
	sym = current_entry->sym;
yann@943
  1240
	sym->flags |= SYMBOL_AUTO;
yann@943
  1241
	for_all_properties(sym, prop, P_ENV) {
yann@943
  1242
		sym2 = prop_get_symbol(prop);
yann@943
  1243
		if (strcmp(sym2->name, env))
yann@943
  1244
			menu_warn(current_entry, "redefining environment symbol from %s",
yann@943
  1245
				  sym2->name);
yann@943
  1246
		return;
yann@943
  1247
	}
yann@943
  1248
yann@943
  1249
	prop = prop_alloc(P_ENV, sym);
yann@943
  1250
	prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
yann@943
  1251
yann@943
  1252
	sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
yann@943
  1253
	sym_env_list->right.sym = sym;
yann@943
  1254
yann@943
  1255
	p = getenv(env);
yann@943
  1256
	if (p)
yann@943
  1257
		sym_add_default(sym, p);
yann@943
  1258
}