kconfig/symbol.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Apr 26 10:47:00 2009 +0000 (2009-04-26)
branch1.4
changeset 1307 39b1c755f19b
parent 39 af42eec9d383
child 1843 266166448ffd
permissions -rw-r--r--
1.4: update version to 1.4.0.

-------- diffstat follows --------
/branches/1.4/.version | 2 1 1 0 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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@1
    39
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@943
    51
	char* p;
yann@1
    52
yann@1
    53
	if (inited)
yann@1
    54
		return;
yann@1
    55
	inited = true;
yann@1
    56
yann@1
    57
	uname(&uts);
yann@1
    58
yann@943
    59
	sym = sym_lookup("UNAME_RELEASE", 0);
yann@1
    60
	sym->type = S_STRING;
yann@1
    61
	sym->flags |= SYMBOL_AUTO;
yann@943
    62
	sym_add_default(sym, uts.release);
yann@1
    63
yann@1
    64
	sym = sym_lookup("PROJECTVERSION", 0);
yann@1
    65
	sym->type = S_STRING;
yann@1
    66
	sym->flags |= SYMBOL_AUTO;
yann@1
    67
	p = getenv("PROJECTVERSION");
yann@1
    68
	if (p)
yann@1
    69
		sym_add_default(sym, p);
yann@1
    70
}
yann@1
    71
yann@1
    72
enum symbol_type sym_get_type(struct symbol *sym)
yann@1
    73
{
yann@1
    74
	enum symbol_type type = sym->type;
yann@1
    75
yann@1
    76
	if (type == S_TRISTATE) {
yann@1
    77
		if (sym_is_choice_value(sym) && sym->visible == yes)
yann@1
    78
			type = S_BOOLEAN;
yann@1
    79
		else if (modules_val == no)
yann@1
    80
			type = S_BOOLEAN;
yann@1
    81
	}
yann@1
    82
	return type;
yann@1
    83
}
yann@1
    84
yann@1
    85
const char *sym_type_name(enum symbol_type type)
yann@1
    86
{
yann@1
    87
	switch (type) {
yann@1
    88
	case S_BOOLEAN:
yann@1
    89
		return "boolean";
yann@1
    90
	case S_TRISTATE:
yann@1
    91
		return "tristate";
yann@1
    92
	case S_INT:
yann@1
    93
		return "integer";
yann@1
    94
	case S_HEX:
yann@1
    95
		return "hex";
yann@1
    96
	case S_STRING:
yann@1
    97
		return "string";
yann@1
    98
	case S_UNKNOWN:
yann@1
    99
		return "unknown";
yann@1
   100
	case S_OTHER:
yann@1
   101
		break;
yann@1
   102
	}
yann@1
   103
	return "???";
yann@1
   104
}
yann@1
   105
yann@1
   106
struct property *sym_get_choice_prop(struct symbol *sym)
yann@1
   107
{
yann@1
   108
	struct property *prop;
yann@1
   109
yann@1
   110
	for_all_choices(sym, prop)
yann@1
   111
		return prop;
yann@1
   112
	return NULL;
yann@1
   113
}
yann@1
   114
yann@943
   115
struct property *sym_get_env_prop(struct symbol *sym)
yann@943
   116
{
yann@943
   117
	struct property *prop;
yann@943
   118
yann@943
   119
	for_all_properties(sym, prop, P_ENV)
yann@943
   120
		return prop;
yann@943
   121
	return NULL;
yann@943
   122
}
yann@943
   123
yann@1
   124
struct property *sym_get_default_prop(struct symbol *sym)
yann@1
   125
{
yann@1
   126
	struct property *prop;
yann@1
   127
yann@1
   128
	for_all_defaults(sym, prop) {
yann@1
   129
		prop->visible.tri = expr_calc_value(prop->visible.expr);
yann@1
   130
		if (prop->visible.tri != no)
yann@1
   131
			return prop;
yann@1
   132
	}
yann@1
   133
	return NULL;
yann@1
   134
}
yann@1
   135
yann@1
   136
struct property *sym_get_range_prop(struct symbol *sym)
yann@1
   137
{
yann@1
   138
	struct property *prop;
yann@1
   139
yann@1
   140
	for_all_properties(sym, prop, P_RANGE) {
yann@1
   141
		prop->visible.tri = expr_calc_value(prop->visible.expr);
yann@1
   142
		if (prop->visible.tri != no)
yann@1
   143
			return prop;
yann@1
   144
	}
yann@1
   145
	return NULL;
yann@1
   146
}
yann@1
   147
yann@1
   148
static int sym_get_range_val(struct symbol *sym, int base)
yann@1
   149
{
yann@1
   150
	sym_calc_value(sym);
yann@1
   151
	switch (sym->type) {
yann@1
   152
	case S_INT:
yann@1
   153
		base = 10;
yann@1
   154
		break;
yann@1
   155
	case S_HEX:
yann@1
   156
		base = 16;
yann@1
   157
		break;
yann@1
   158
	default:
yann@1
   159
		break;
yann@1
   160
	}
yann@1
   161
	return strtol(sym->curr.val, NULL, base);
yann@1
   162
}
yann@1
   163
yann@1
   164
static void sym_validate_range(struct symbol *sym)
yann@1
   165
{
yann@1
   166
	struct property *prop;
yann@1
   167
	int base, val, val2;
yann@1
   168
	char str[64];
yann@1
   169
yann@1
   170
	switch (sym->type) {
yann@1
   171
	case S_INT:
yann@1
   172
		base = 10;
yann@1
   173
		break;
yann@1
   174
	case S_HEX:
yann@1
   175
		base = 16;
yann@1
   176
		break;
yann@1
   177
	default:
yann@1
   178
		return;
yann@1
   179
	}
yann@1
   180
	prop = sym_get_range_prop(sym);
yann@1
   181
	if (!prop)
yann@1
   182
		return;
yann@1
   183
	val = strtol(sym->curr.val, NULL, base);
yann@1
   184
	val2 = sym_get_range_val(prop->expr->left.sym, base);
yann@1
   185
	if (val >= val2) {
yann@1
   186
		val2 = sym_get_range_val(prop->expr->right.sym, base);
yann@1
   187
		if (val <= val2)
yann@1
   188
			return;
yann@1
   189
	}
yann@1
   190
	if (sym->type == S_INT)
yann@1
   191
		sprintf(str, "%d", val2);
yann@1
   192
	else
yann@1
   193
		sprintf(str, "0x%x", val2);
yann@1
   194
	sym->curr.val = strdup(str);
yann@1
   195
}
yann@1
   196
yann@1
   197
static void sym_calc_visibility(struct symbol *sym)
yann@1
   198
{
yann@1
   199
	struct property *prop;
yann@1
   200
	tristate tri;
yann@1
   201
yann@1
   202
	/* any prompt visible? */
yann@1
   203
	tri = no;
yann@1
   204
	for_all_prompts(sym, prop) {
yann@1
   205
		prop->visible.tri = expr_calc_value(prop->visible.expr);
yann@943
   206
		tri = EXPR_OR(tri, prop->visible.tri);
yann@1
   207
	}
yann@1
   208
	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
yann@1
   209
		tri = yes;
yann@1
   210
	if (sym->visible != tri) {
yann@1
   211
		sym->visible = tri;
yann@1
   212
		sym_set_changed(sym);
yann@1
   213
	}
yann@1
   214
	if (sym_is_choice_value(sym))
yann@1
   215
		return;
yann@1
   216
	tri = no;
yann@1
   217
	if (sym->rev_dep.expr)
yann@1
   218
		tri = expr_calc_value(sym->rev_dep.expr);
yann@1
   219
	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
yann@1
   220
		tri = yes;
yann@1
   221
	if (sym->rev_dep.tri != tri) {
yann@1
   222
		sym->rev_dep.tri = tri;
yann@1
   223
		sym_set_changed(sym);
yann@1
   224
	}
yann@1
   225
}
yann@1
   226
yann@1
   227
static struct symbol *sym_calc_choice(struct symbol *sym)
yann@1
   228
{
yann@1
   229
	struct symbol *def_sym;
yann@1
   230
	struct property *prop;
yann@1
   231
	struct expr *e;
yann@1
   232
yann@1
   233
	/* is the user choice visible? */
yann@1
   234
	def_sym = sym->def[S_DEF_USER].val;
yann@1
   235
	if (def_sym) {
yann@1
   236
		sym_calc_visibility(def_sym);
yann@1
   237
		if (def_sym->visible != no)
yann@1
   238
			return def_sym;
yann@1
   239
	}
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
		sym_calc_visibility(def_sym);
yann@1
   248
		if (def_sym->visible != no)
yann@1
   249
			return def_sym;
yann@1
   250
	}
yann@1
   251
yann@1
   252
	/* just get the first visible value */
yann@1
   253
	prop = sym_get_choice_prop(sym);
yann@943
   254
	expr_list_for_each_sym(prop->expr, e, def_sym) {
yann@1
   255
		sym_calc_visibility(def_sym);
yann@1
   256
		if (def_sym->visible != no)
yann@1
   257
			return def_sym;
yann@1
   258
	}
yann@1
   259
yann@1
   260
	/* no choice? reset tristate value */
yann@1
   261
	sym->curr.tri = no;
yann@1
   262
	return NULL;
yann@1
   263
}
yann@1
   264
yann@1
   265
void sym_calc_value(struct symbol *sym)
yann@1
   266
{
yann@1
   267
	struct symbol_value newval, oldval;
yann@1
   268
	struct property *prop;
yann@1
   269
	struct expr *e;
yann@1
   270
yann@1
   271
	if (!sym)
yann@1
   272
		return;
yann@1
   273
yann@1
   274
	if (sym->flags & SYMBOL_VALID)
yann@1
   275
		return;
yann@1
   276
	sym->flags |= SYMBOL_VALID;
yann@1
   277
yann@1
   278
	oldval = sym->curr;
yann@1
   279
yann@1
   280
	switch (sym->type) {
yann@1
   281
	case S_INT:
yann@1
   282
	case S_HEX:
yann@1
   283
	case S_STRING:
yann@1
   284
		newval = symbol_empty.curr;
yann@1
   285
		break;
yann@1
   286
	case S_BOOLEAN:
yann@1
   287
	case S_TRISTATE:
yann@1
   288
		newval = symbol_no.curr;
yann@1
   289
		break;
yann@1
   290
	default:
yann@1
   291
		sym->curr.val = sym->name;
yann@1
   292
		sym->curr.tri = no;
yann@1
   293
		return;
yann@1
   294
	}
yann@1
   295
	if (!sym_is_choice_value(sym))
yann@1
   296
		sym->flags &= ~SYMBOL_WRITE;
yann@1
   297
yann@1
   298
	sym_calc_visibility(sym);
yann@1
   299
yann@1
   300
	/* set default if recursively called */
yann@1
   301
	sym->curr = newval;
yann@1
   302
yann@1
   303
	switch (sym_get_type(sym)) {
yann@1
   304
	case S_BOOLEAN:
yann@1
   305
	case S_TRISTATE:
yann@1
   306
		if (sym_is_choice_value(sym) && sym->visible == yes) {
yann@1
   307
			prop = sym_get_choice_prop(sym);
yann@1
   308
			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
yann@943
   309
		} else {
yann@943
   310
			if (sym->visible != no) {
yann@943
   311
				/* if the symbol is visible use the user value
yann@943
   312
				 * if available, otherwise try the default value
yann@943
   313
				 */
yann@943
   314
				sym->flags |= SYMBOL_WRITE;
yann@943
   315
				if (sym_has_value(sym)) {
yann@943
   316
					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
yann@943
   317
							      sym->visible);
yann@943
   318
					goto calc_newval;
yann@943
   319
				}
yann@943
   320
			}
yann@943
   321
			if (sym->rev_dep.tri != no)
yann@943
   322
				sym->flags |= SYMBOL_WRITE;
yann@943
   323
			if (!sym_is_choice(sym)) {
yann@1
   324
				prop = sym_get_default_prop(sym);
yann@943
   325
				if (prop) {
yann@943
   326
					sym->flags |= SYMBOL_WRITE;
yann@943
   327
					newval.tri = EXPR_AND(expr_calc_value(prop->expr),
yann@943
   328
							      prop->visible.tri);
yann@943
   329
				}
yann@1
   330
			}
yann@943
   331
		calc_newval:
yann@943
   332
			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
yann@1
   333
		}
yann@1
   334
		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
yann@1
   335
			newval.tri = yes;
yann@1
   336
		break;
yann@1
   337
	case S_STRING:
yann@1
   338
	case S_HEX:
yann@1
   339
	case S_INT:
yann@1
   340
		if (sym->visible != no) {
yann@1
   341
			sym->flags |= SYMBOL_WRITE;
yann@1
   342
			if (sym_has_value(sym)) {
yann@1
   343
				newval.val = sym->def[S_DEF_USER].val;
yann@1
   344
				break;
yann@1
   345
			}
yann@1
   346
		}
yann@1
   347
		prop = sym_get_default_prop(sym);
yann@1
   348
		if (prop) {
yann@1
   349
			struct symbol *ds = prop_get_symbol(prop);
yann@1
   350
			if (ds) {
yann@1
   351
				sym->flags |= SYMBOL_WRITE;
yann@1
   352
				sym_calc_value(ds);
yann@1
   353
				newval.val = ds->curr.val;
yann@1
   354
			}
yann@1
   355
		}
yann@1
   356
		break;
yann@1
   357
	default:
yann@1
   358
		;
yann@1
   359
	}
yann@1
   360
yann@1
   361
	sym->curr = newval;
yann@1
   362
	if (sym_is_choice(sym) && newval.tri == yes)
yann@1
   363
		sym->curr.val = sym_calc_choice(sym);
yann@1
   364
	sym_validate_range(sym);
yann@1
   365
yann@1
   366
	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
yann@1
   367
		sym_set_changed(sym);
yann@1
   368
		if (modules_sym == sym) {
yann@1
   369
			sym_set_all_changed();
yann@1
   370
			modules_val = modules_sym->curr.tri;
yann@1
   371
		}
yann@1
   372
	}
yann@1
   373
yann@1
   374
	if (sym_is_choice(sym)) {
yann@943
   375
		struct symbol *choice_sym;
yann@1
   376
		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
yann@943
   377
yann@1
   378
		prop = sym_get_choice_prop(sym);
yann@943
   379
		expr_list_for_each_sym(prop->expr, e, choice_sym) {
yann@943
   380
			choice_sym->flags |= flags;
yann@1
   381
			if (flags & SYMBOL_CHANGED)
yann@943
   382
				sym_set_changed(choice_sym);
yann@1
   383
		}
yann@1
   384
	}
yann@943
   385
yann@943
   386
	if (sym->flags & SYMBOL_AUTO)
yann@943
   387
		sym->flags &= ~SYMBOL_WRITE;
yann@1
   388
}
yann@1
   389
yann@1
   390
void sym_clear_all_valid(void)
yann@1
   391
{
yann@1
   392
	struct symbol *sym;
yann@1
   393
	int i;
yann@1
   394
yann@1
   395
	for_all_symbols(i, sym)
yann@1
   396
		sym->flags &= ~SYMBOL_VALID;
yann@39
   397
	sym_add_change_count(1);
yann@1
   398
	if (modules_sym)
yann@1
   399
		sym_calc_value(modules_sym);
yann@1
   400
}
yann@1
   401
yann@1
   402
void sym_set_changed(struct symbol *sym)
yann@1
   403
{
yann@1
   404
	struct property *prop;
yann@1
   405
yann@1
   406
	sym->flags |= SYMBOL_CHANGED;
yann@1
   407
	for (prop = sym->prop; prop; prop = prop->next) {
yann@1
   408
		if (prop->menu)
yann@1
   409
			prop->menu->flags |= MENU_CHANGED;
yann@1
   410
	}
yann@1
   411
}
yann@1
   412
yann@1
   413
void sym_set_all_changed(void)
yann@1
   414
{
yann@1
   415
	struct symbol *sym;
yann@1
   416
	int i;
yann@1
   417
yann@1
   418
	for_all_symbols(i, sym)
yann@1
   419
		sym_set_changed(sym);
yann@1
   420
}
yann@1
   421
yann@1
   422
bool sym_tristate_within_range(struct symbol *sym, tristate val)
yann@1
   423
{
yann@1
   424
	int type = sym_get_type(sym);
yann@1
   425
yann@1
   426
	if (sym->visible == no)
yann@1
   427
		return false;
yann@1
   428
yann@1
   429
	if (type != S_BOOLEAN && type != S_TRISTATE)
yann@1
   430
		return false;
yann@1
   431
yann@1
   432
	if (type == S_BOOLEAN && val == mod)
yann@1
   433
		return false;
yann@1
   434
	if (sym->visible <= sym->rev_dep.tri)
yann@1
   435
		return false;
yann@1
   436
	if (sym_is_choice_value(sym) && sym->visible == yes)
yann@1
   437
		return val == yes;
yann@1
   438
	return val >= sym->rev_dep.tri && val <= sym->visible;
yann@1
   439
}
yann@1
   440
yann@1
   441
bool sym_set_tristate_value(struct symbol *sym, tristate val)
yann@1
   442
{
yann@1
   443
	tristate oldval = sym_get_tristate_value(sym);
yann@1
   444
yann@1
   445
	if (oldval != val && !sym_tristate_within_range(sym, val))
yann@1
   446
		return false;
yann@1
   447
yann@1
   448
	if (!(sym->flags & SYMBOL_DEF_USER)) {
yann@1
   449
		sym->flags |= SYMBOL_DEF_USER;
yann@1
   450
		sym_set_changed(sym);
yann@1
   451
	}
yann@1
   452
	/*
yann@1
   453
	 * setting a choice value also resets the new flag of the choice
yann@1
   454
	 * symbol and all other choice values.
yann@1
   455
	 */
yann@1
   456
	if (sym_is_choice_value(sym) && val == yes) {
yann@1
   457
		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
yann@1
   458
		struct property *prop;
yann@1
   459
		struct expr *e;
yann@1
   460
yann@1
   461
		cs->def[S_DEF_USER].val = sym;
yann@1
   462
		cs->flags |= SYMBOL_DEF_USER;
yann@1
   463
		prop = sym_get_choice_prop(cs);
yann@1
   464
		for (e = prop->expr; e; e = e->left.expr) {
yann@1
   465
			if (e->right.sym->visible != no)
yann@1
   466
				e->right.sym->flags |= SYMBOL_DEF_USER;
yann@1
   467
		}
yann@1
   468
	}
yann@1
   469
yann@1
   470
	sym->def[S_DEF_USER].tri = val;
yann@1
   471
	if (oldval != val)
yann@1
   472
		sym_clear_all_valid();
yann@1
   473
yann@1
   474
	return true;
yann@1
   475
}
yann@1
   476
yann@1
   477
tristate sym_toggle_tristate_value(struct symbol *sym)
yann@1
   478
{
yann@1
   479
	tristate oldval, newval;
yann@1
   480
yann@1
   481
	oldval = newval = sym_get_tristate_value(sym);
yann@1
   482
	do {
yann@1
   483
		switch (newval) {
yann@1
   484
		case no:
yann@1
   485
			newval = mod;
yann@1
   486
			break;
yann@1
   487
		case mod:
yann@1
   488
			newval = yes;
yann@1
   489
			break;
yann@1
   490
		case yes:
yann@1
   491
			newval = no;
yann@1
   492
			break;
yann@1
   493
		}
yann@1
   494
		if (sym_set_tristate_value(sym, newval))
yann@1
   495
			break;
yann@1
   496
	} while (oldval != newval);
yann@1
   497
	return newval;
yann@1
   498
}
yann@1
   499
yann@1
   500
bool sym_string_valid(struct symbol *sym, const char *str)
yann@1
   501
{
yann@1
   502
	signed char ch;
yann@1
   503
yann@1
   504
	switch (sym->type) {
yann@1
   505
	case S_STRING:
yann@1
   506
		return true;
yann@1
   507
	case S_INT:
yann@1
   508
		ch = *str++;
yann@1
   509
		if (ch == '-')
yann@1
   510
			ch = *str++;
yann@1
   511
		if (!isdigit(ch))
yann@1
   512
			return false;
yann@1
   513
		if (ch == '0' && *str != 0)
yann@1
   514
			return false;
yann@1
   515
		while ((ch = *str++)) {
yann@1
   516
			if (!isdigit(ch))
yann@1
   517
				return false;
yann@1
   518
		}
yann@1
   519
		return true;
yann@1
   520
	case S_HEX:
yann@1
   521
		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
yann@1
   522
			str += 2;
yann@1
   523
		ch = *str++;
yann@1
   524
		do {
yann@1
   525
			if (!isxdigit(ch))
yann@1
   526
				return false;
yann@1
   527
		} while ((ch = *str++));
yann@1
   528
		return true;
yann@1
   529
	case S_BOOLEAN:
yann@1
   530
	case S_TRISTATE:
yann@1
   531
		switch (str[0]) {
yann@1
   532
		case 'y': case 'Y':
yann@1
   533
		case 'm': case 'M':
yann@1
   534
		case 'n': case 'N':
yann@1
   535
			return true;
yann@1
   536
		}
yann@1
   537
		return false;
yann@1
   538
	default:
yann@1
   539
		return false;
yann@1
   540
	}
yann@1
   541
}
yann@1
   542
yann@1
   543
bool sym_string_within_range(struct symbol *sym, const char *str)
yann@1
   544
{
yann@1
   545
	struct property *prop;
yann@1
   546
	int val;
yann@1
   547
yann@1
   548
	switch (sym->type) {
yann@1
   549
	case S_STRING:
yann@1
   550
		return sym_string_valid(sym, str);
yann@1
   551
	case S_INT:
yann@1
   552
		if (!sym_string_valid(sym, str))
yann@1
   553
			return false;
yann@1
   554
		prop = sym_get_range_prop(sym);
yann@1
   555
		if (!prop)
yann@1
   556
			return true;
yann@1
   557
		val = strtol(str, NULL, 10);
yann@1
   558
		return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
yann@1
   559
		       val <= sym_get_range_val(prop->expr->right.sym, 10);
yann@1
   560
	case S_HEX:
yann@1
   561
		if (!sym_string_valid(sym, str))
yann@1
   562
			return false;
yann@1
   563
		prop = sym_get_range_prop(sym);
yann@1
   564
		if (!prop)
yann@1
   565
			return true;
yann@1
   566
		val = strtol(str, NULL, 16);
yann@1
   567
		return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
yann@1
   568
		       val <= sym_get_range_val(prop->expr->right.sym, 16);
yann@1
   569
	case S_BOOLEAN:
yann@1
   570
	case S_TRISTATE:
yann@1
   571
		switch (str[0]) {
yann@1
   572
		case 'y': case 'Y':
yann@1
   573
			return sym_tristate_within_range(sym, yes);
yann@1
   574
		case 'm': case 'M':
yann@1
   575
			return sym_tristate_within_range(sym, mod);
yann@1
   576
		case 'n': case 'N':
yann@1
   577
			return sym_tristate_within_range(sym, no);
yann@1
   578
		}
yann@1
   579
		return false;
yann@1
   580
	default:
yann@1
   581
		return false;
yann@1
   582
	}
yann@1
   583
}
yann@1
   584
yann@1
   585
bool sym_set_string_value(struct symbol *sym, const char *newval)
yann@1
   586
{
yann@1
   587
	const char *oldval;
yann@1
   588
	char *val;
yann@1
   589
	int size;
yann@1
   590
yann@1
   591
	switch (sym->type) {
yann@1
   592
	case S_BOOLEAN:
yann@1
   593
	case S_TRISTATE:
yann@1
   594
		switch (newval[0]) {
yann@1
   595
		case 'y': case 'Y':
yann@1
   596
			return sym_set_tristate_value(sym, yes);
yann@1
   597
		case 'm': case 'M':
yann@1
   598
			return sym_set_tristate_value(sym, mod);
yann@1
   599
		case 'n': case 'N':
yann@1
   600
			return sym_set_tristate_value(sym, no);
yann@1
   601
		}
yann@1
   602
		return false;
yann@1
   603
	default:
yann@1
   604
		;
yann@1
   605
	}
yann@1
   606
yann@1
   607
	if (!sym_string_within_range(sym, newval))
yann@1
   608
		return false;
yann@1
   609
yann@1
   610
	if (!(sym->flags & SYMBOL_DEF_USER)) {
yann@1
   611
		sym->flags |= SYMBOL_DEF_USER;
yann@1
   612
		sym_set_changed(sym);
yann@1
   613
	}
yann@1
   614
yann@1
   615
	oldval = sym->def[S_DEF_USER].val;
yann@1
   616
	size = strlen(newval) + 1;
yann@1
   617
	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
yann@1
   618
		size += 2;
yann@1
   619
		sym->def[S_DEF_USER].val = val = malloc(size);
yann@1
   620
		*val++ = '0';
yann@1
   621
		*val++ = 'x';
yann@1
   622
	} else if (!oldval || strcmp(oldval, newval))
yann@1
   623
		sym->def[S_DEF_USER].val = val = malloc(size);
yann@1
   624
	else
yann@1
   625
		return true;
yann@1
   626
yann@1
   627
	strcpy(val, newval);
yann@1
   628
	free((void *)oldval);
yann@1
   629
	sym_clear_all_valid();
yann@1
   630
yann@1
   631
	return true;
yann@1
   632
}
yann@1
   633
yann@1
   634
const char *sym_get_string_value(struct symbol *sym)
yann@1
   635
{
yann@1
   636
	tristate val;
yann@1
   637
yann@1
   638
	switch (sym->type) {
yann@1
   639
	case S_BOOLEAN:
yann@1
   640
	case S_TRISTATE:
yann@1
   641
		val = sym_get_tristate_value(sym);
yann@1
   642
		switch (val) {
yann@1
   643
		case no:
yann@1
   644
			return "n";
yann@1
   645
		case mod:
yann@1
   646
			return "m";
yann@1
   647
		case yes:
yann@1
   648
			return "y";
yann@1
   649
		}
yann@1
   650
		break;
yann@1
   651
	default:
yann@1
   652
		;
yann@1
   653
	}
yann@1
   654
	return (const char *)sym->curr.val;
yann@1
   655
}
yann@1
   656
yann@1
   657
bool sym_is_changable(struct symbol *sym)
yann@1
   658
{
yann@1
   659
	return sym->visible > sym->rev_dep.tri;
yann@1
   660
}
yann@1
   661
yann@943
   662
struct symbol *sym_lookup(const char *name, int flags)
yann@1
   663
{
yann@1
   664
	struct symbol *symbol;
yann@1
   665
	const char *ptr;
yann@1
   666
	char *new_name;
yann@1
   667
	int hash = 0;
yann@1
   668
yann@1
   669
	if (name) {
yann@1
   670
		if (name[0] && !name[1]) {
yann@1
   671
			switch (name[0]) {
yann@1
   672
			case 'y': return &symbol_yes;
yann@1
   673
			case 'm': return &symbol_mod;
yann@1
   674
			case 'n': return &symbol_no;
yann@1
   675
			}
yann@1
   676
		}
yann@1
   677
		for (ptr = name; *ptr; ptr++)
yann@1
   678
			hash += *ptr;
yann@1
   679
		hash &= 0xff;
yann@1
   680
yann@1
   681
		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
yann@943
   682
			if (!strcmp(symbol->name, name) &&
yann@943
   683
			    (flags ? symbol->flags & flags
yann@943
   684
				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
yann@943
   685
				return symbol;
yann@1
   686
		}
yann@1
   687
		new_name = strdup(name);
yann@1
   688
	} else {
yann@1
   689
		new_name = NULL;
yann@1
   690
		hash = 256;
yann@1
   691
	}
yann@1
   692
yann@1
   693
	symbol = malloc(sizeof(*symbol));
yann@1
   694
	memset(symbol, 0, sizeof(*symbol));
yann@1
   695
	symbol->name = new_name;
yann@1
   696
	symbol->type = S_UNKNOWN;
yann@943
   697
	symbol->flags |= flags;
yann@1
   698
yann@1
   699
	symbol->next = symbol_hash[hash];
yann@1
   700
	symbol_hash[hash] = symbol;
yann@1
   701
yann@1
   702
	return symbol;
yann@1
   703
}
yann@1
   704
yann@1
   705
struct symbol *sym_find(const char *name)
yann@1
   706
{
yann@1
   707
	struct symbol *symbol = NULL;
yann@1
   708
	const char *ptr;
yann@1
   709
	int hash = 0;
yann@1
   710
yann@1
   711
	if (!name)
yann@1
   712
		return NULL;
yann@1
   713
yann@1
   714
	if (name[0] && !name[1]) {
yann@1
   715
		switch (name[0]) {
yann@1
   716
		case 'y': return &symbol_yes;
yann@1
   717
		case 'm': return &symbol_mod;
yann@1
   718
		case 'n': return &symbol_no;
yann@1
   719
		}
yann@1
   720
	}
yann@1
   721
	for (ptr = name; *ptr; ptr++)
yann@1
   722
		hash += *ptr;
yann@1
   723
	hash &= 0xff;
yann@1
   724
yann@1
   725
	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
yann@1
   726
		if (!strcmp(symbol->name, name) &&
yann@1
   727
		    !(symbol->flags & SYMBOL_CONST))
yann@1
   728
				break;
yann@1
   729
	}
yann@1
   730
yann@1
   731
	return symbol;
yann@1
   732
}
yann@1
   733
yann@1
   734
struct symbol **sym_re_search(const char *pattern)
yann@1
   735
{
yann@1
   736
	struct symbol *sym, **sym_arr = NULL;
yann@1
   737
	int i, cnt, size;
yann@1
   738
	regex_t re;
yann@1
   739
yann@1
   740
	cnt = size = 0;
yann@1
   741
	/* Skip if empty */
yann@1
   742
	if (strlen(pattern) == 0)
yann@1
   743
		return NULL;
yann@1
   744
	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
yann@1
   745
		return NULL;
yann@1
   746
yann@1
   747
	for_all_symbols(i, sym) {
yann@1
   748
		if (sym->flags & SYMBOL_CONST || !sym->name)
yann@1
   749
			continue;
yann@1
   750
		if (regexec(&re, sym->name, 0, NULL, 0))
yann@1
   751
			continue;
yann@1
   752
		if (cnt + 1 >= size) {
yann@1
   753
			void *tmp = sym_arr;
yann@1
   754
			size += 16;
yann@1
   755
			sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
yann@1
   756
			if (!sym_arr) {
yann@1
   757
				free(tmp);
yann@1
   758
				return NULL;
yann@1
   759
			}
yann@1
   760
		}
yann@1
   761
		sym_arr[cnt++] = sym;
yann@1
   762
	}
yann@1
   763
	if (sym_arr)
yann@1
   764
		sym_arr[cnt] = NULL;
yann@1
   765
	regfree(&re);
yann@1
   766
yann@1
   767
	return sym_arr;
yann@1
   768
}
yann@1
   769
yann@1
   770
yann@1
   771
static struct symbol *sym_check_expr_deps(struct expr *e)
yann@1
   772
{
yann@1
   773
	struct symbol *sym;
yann@1
   774
yann@1
   775
	if (!e)
yann@1
   776
		return NULL;
yann@1
   777
	switch (e->type) {
yann@1
   778
	case E_OR:
yann@1
   779
	case E_AND:
yann@1
   780
		sym = sym_check_expr_deps(e->left.expr);
yann@1
   781
		if (sym)
yann@1
   782
			return sym;
yann@1
   783
		return sym_check_expr_deps(e->right.expr);
yann@1
   784
	case E_NOT:
yann@1
   785
		return sym_check_expr_deps(e->left.expr);
yann@1
   786
	case E_EQUAL:
yann@1
   787
	case E_UNEQUAL:
yann@1
   788
		sym = sym_check_deps(e->left.sym);
yann@1
   789
		if (sym)
yann@1
   790
			return sym;
yann@1
   791
		return sym_check_deps(e->right.sym);
yann@1
   792
	case E_SYMBOL:
yann@1
   793
		return sym_check_deps(e->left.sym);
yann@1
   794
	default:
yann@1
   795
		break;
yann@1
   796
	}
yann@1
   797
	printf("Oops! How to check %d?\n", e->type);
yann@1
   798
	return NULL;
yann@1
   799
}
yann@1
   800
yann@943
   801
/* return NULL when dependencies are OK */
yann@943
   802
static struct symbol *sym_check_sym_deps(struct symbol *sym)
yann@943
   803
{
yann@943
   804
	struct symbol *sym2;
yann@943
   805
	struct property *prop;
yann@943
   806
yann@943
   807
	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
yann@943
   808
	if (sym2)
yann@943
   809
		return sym2;
yann@943
   810
yann@943
   811
	for (prop = sym->prop; prop; prop = prop->next) {
yann@943
   812
		if (prop->type == P_CHOICE || prop->type == P_SELECT)
yann@943
   813
			continue;
yann@943
   814
		sym2 = sym_check_expr_deps(prop->visible.expr);
yann@943
   815
		if (sym2)
yann@943
   816
			break;
yann@943
   817
		if (prop->type != P_DEFAULT || sym_is_choice(sym))
yann@943
   818
			continue;
yann@943
   819
		sym2 = sym_check_expr_deps(prop->expr);
yann@943
   820
		if (sym2)
yann@943
   821
			break;
yann@943
   822
	}
yann@943
   823
yann@943
   824
	return sym2;
yann@943
   825
}
yann@943
   826
yann@943
   827
static struct symbol *sym_check_choice_deps(struct symbol *choice)
yann@943
   828
{
yann@943
   829
	struct symbol *sym, *sym2;
yann@943
   830
	struct property *prop;
yann@943
   831
	struct expr *e;
yann@943
   832
yann@943
   833
	prop = sym_get_choice_prop(choice);
yann@943
   834
	expr_list_for_each_sym(prop->expr, e, sym)
yann@943
   835
		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
yann@943
   836
yann@943
   837
	choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
yann@943
   838
	sym2 = sym_check_sym_deps(choice);
yann@943
   839
	choice->flags &= ~SYMBOL_CHECK;
yann@943
   840
	if (sym2)
yann@943
   841
		goto out;
yann@943
   842
yann@943
   843
	expr_list_for_each_sym(prop->expr, e, sym) {
yann@943
   844
		sym2 = sym_check_sym_deps(sym);
yann@943
   845
		if (sym2) {
yann@943
   846
			fprintf(stderr, " -> %s", sym->name);
yann@943
   847
			break;
yann@943
   848
		}
yann@943
   849
	}
yann@943
   850
out:
yann@943
   851
	expr_list_for_each_sym(prop->expr, e, sym)
yann@943
   852
		sym->flags &= ~SYMBOL_CHECK;
yann@943
   853
yann@943
   854
	if (sym2 && sym_is_choice_value(sym2) &&
yann@943
   855
	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
yann@943
   856
		sym2 = choice;
yann@943
   857
yann@943
   858
	return sym2;
yann@943
   859
}
yann@943
   860
yann@1
   861
struct symbol *sym_check_deps(struct symbol *sym)
yann@1
   862
{
yann@1
   863
	struct symbol *sym2;
yann@1
   864
	struct property *prop;
yann@1
   865
yann@1
   866
	if (sym->flags & SYMBOL_CHECK) {
yann@943
   867
		fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
yann@943
   868
		        sym->prop->file->name, sym->prop->lineno,
yann@943
   869
			sym->name ? sym->name : "<choice>");
yann@1
   870
		return sym;
yann@1
   871
	}
yann@1
   872
	if (sym->flags & SYMBOL_CHECKED)
yann@1
   873
		return NULL;
yann@1
   874
yann@943
   875
	if (sym_is_choice_value(sym)) {
yann@943
   876
		/* for choice groups start the check with main choice symbol */
yann@943
   877
		prop = sym_get_choice_prop(sym);
yann@943
   878
		sym2 = sym_check_deps(prop_get_symbol(prop));
yann@943
   879
	} else if (sym_is_choice(sym)) {
yann@943
   880
		sym2 = sym_check_choice_deps(sym);
yann@943
   881
	} else {
yann@943
   882
		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
yann@943
   883
		sym2 = sym_check_sym_deps(sym);
yann@943
   884
		sym->flags &= ~SYMBOL_CHECK;
yann@943
   885
	}
yann@1
   886
yann@1
   887
	if (sym2) {
yann@943
   888
		fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>");
yann@1
   889
		if (sym2 == sym) {
yann@943
   890
			fprintf(stderr, "\n");
yann@943
   891
			zconfnerrs++;
yann@1
   892
			sym2 = NULL;
yann@1
   893
		}
yann@1
   894
	}
yann@943
   895
yann@1
   896
	return sym2;
yann@1
   897
}
yann@1
   898
yann@1
   899
struct property *prop_alloc(enum prop_type type, struct symbol *sym)
yann@1
   900
{
yann@1
   901
	struct property *prop;
yann@1
   902
	struct property **propp;
yann@1
   903
yann@1
   904
	prop = malloc(sizeof(*prop));
yann@1
   905
	memset(prop, 0, sizeof(*prop));
yann@1
   906
	prop->type = type;
yann@1
   907
	prop->sym = sym;
yann@1
   908
	prop->file = current_file;
yann@1
   909
	prop->lineno = zconf_lineno();
yann@1
   910
yann@1
   911
	/* append property to the prop list of symbol */
yann@1
   912
	if (sym) {
yann@1
   913
		for (propp = &sym->prop; *propp; propp = &(*propp)->next)
yann@1
   914
			;
yann@1
   915
		*propp = prop;
yann@1
   916
	}
yann@1
   917
yann@1
   918
	return prop;
yann@1
   919
}
yann@1
   920
yann@1
   921
struct symbol *prop_get_symbol(struct property *prop)
yann@1
   922
{
yann@1
   923
	if (prop->expr && (prop->expr->type == E_SYMBOL ||
yann@943
   924
			   prop->expr->type == E_LIST))
yann@1
   925
		return prop->expr->left.sym;
yann@1
   926
	return NULL;
yann@1
   927
}
yann@1
   928
yann@1
   929
const char *prop_get_type_name(enum prop_type type)
yann@1
   930
{
yann@1
   931
	switch (type) {
yann@1
   932
	case P_PROMPT:
yann@1
   933
		return "prompt";
yann@943
   934
	case P_ENV:
yann@943
   935
		return "env";
yann@1
   936
	case P_COMMENT:
yann@1
   937
		return "comment";
yann@1
   938
	case P_MENU:
yann@1
   939
		return "menu";
yann@1
   940
	case P_DEFAULT:
yann@1
   941
		return "default";
yann@1
   942
	case P_CHOICE:
yann@1
   943
		return "choice";
yann@1
   944
	case P_SELECT:
yann@1
   945
		return "select";
yann@1
   946
	case P_RANGE:
yann@1
   947
		return "range";
yann@1
   948
	case P_UNKNOWN:
yann@1
   949
		break;
yann@1
   950
	}
yann@1
   951
	return "unknown";
yann@1
   952
}
yann@943
   953
yann@943
   954
void prop_add_env(const char *env)
yann@943
   955
{
yann@943
   956
	struct symbol *sym, *sym2;
yann@943
   957
	struct property *prop;
yann@943
   958
	char *p;
yann@943
   959
yann@943
   960
	sym = current_entry->sym;
yann@943
   961
	sym->flags |= SYMBOL_AUTO;
yann@943
   962
	for_all_properties(sym, prop, P_ENV) {
yann@943
   963
		sym2 = prop_get_symbol(prop);
yann@943
   964
		if (strcmp(sym2->name, env))
yann@943
   965
			menu_warn(current_entry, "redefining environment symbol from %s",
yann@943
   966
				  sym2->name);
yann@943
   967
		return;
yann@943
   968
	}
yann@943
   969
yann@943
   970
	prop = prop_alloc(P_ENV, sym);
yann@943
   971
	prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
yann@943
   972
yann@943
   973
	sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
yann@943
   974
	sym_env_list->right.sym = sym;
yann@943
   975
yann@943
   976
	p = getenv(env);
yann@943
   977
	if (p)
yann@943
   978
		sym_add_default(sym, p);
yann@943
   979
	else
yann@943
   980
		menu_warn(current_entry, "environment variable %s undefined", env);
yann@943
   981
}