kconfig/symbol.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Mon May 25 19:48:42 2009 +0000 (2009-05-25)
branchgcc-4.4
changeset 1387 a52504ffac55
parent 39 af42eec9d383
child 1843 266166448ffd
permissions -rw-r--r--
/devel/gcc-4.4:
- TODO: remove completed items

-------- diffstat follows --------
/devel/gcc-4.4/TODO | 1 0 1 0 -
1 file changed, 1 deletion(-)
     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 	else
   980 		menu_warn(current_entry, "environment variable %s undefined", env);
   981 }