kconfig/symbol.c
author danielrubiob@gmail.com
Sun Feb 09 22:24:56 2014 +0100 (2014-02-09)
changeset 3284 f9dec799e51e
parent 2448 a103abae1560
permissions -rw-r--r--
complibs/mpc: bump version

Signed-off-by: Daniel Rubio Bonilla <danielrubiob@gmail.com>
Message-Id: <d78f3a4ba2df1e076851.1391984022@uemo>
Patchwork-Id: 318636
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
}