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

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

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

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