kconfig/symbol.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Jan 17 23:06:02 2010 +0100 (2010-01-17)
changeset 1740 c57458bb354d
parent 39 af42eec9d383
child 1843 266166448ffd
permissions -rw-r--r--
configure: do not require hg when configuring in an hg clone

When configuring in an hg clone, we need hg to compute the version string.
It can happen that users do not have Mercurial (eg. if they got a snapshot
rather that they did a full clone). In this case, we can still run, of
course, so simply fill the version string with a sufficiently explicit
value, that does not require hg. The date is a good candidate.
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
}