blob: 99e3d02d1cfc26b2b0d8489377860d62b4fe7807 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
15struct symbol symbol_yes = {
16 .name = "y",
17 .curr = { "y", yes },
Roman Zippelc0e150ac2006-06-08 22:12:40 -070018 .flags = SYMBOL_CONST|SYMBOL_VALID,
Linus Torvalds1da177e2005-04-16 15:20:36 -070019}, symbol_mod = {
20 .name = "m",
21 .curr = { "m", mod },
Roman Zippelc0e150ac2006-06-08 22:12:40 -070022 .flags = SYMBOL_CONST|SYMBOL_VALID,
Linus Torvalds1da177e2005-04-16 15:20:36 -070023}, symbol_no = {
24 .name = "n",
25 .curr = { "n", no },
Roman Zippelc0e150ac2006-06-08 22:12:40 -070026 .flags = SYMBOL_CONST|SYMBOL_VALID,
Linus Torvalds1da177e2005-04-16 15:20:36 -070027}, symbol_empty = {
28 .name = "",
29 .curr = { "", no },
30 .flags = SYMBOL_VALID,
31};
32
Roman Zippelface4372006-06-08 22:12:45 -070033struct symbol *sym_defconfig_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034struct symbol *modules_sym;
35tristate modules_val;
36
Roman Zippel93449082008-01-14 04:50:54 +010037struct expr *sym_env_list;
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039void 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, 1));
44}
45
46void sym_init(void)
47{
48 struct symbol *sym;
49 struct utsname uts;
50 char *p;
51 static bool inited = false;
52
53 if (inited)
54 return;
55 inited = true;
56
57 uname(&uts);
58
59 sym = sym_lookup("ARCH", 0);
60 sym->type = S_STRING;
61 sym->flags |= SYMBOL_AUTO;
62 p = getenv("ARCH");
63 if (p)
64 sym_add_default(sym, p);
65
Sam Ravnborg2244cbd2006-01-16 12:12:12 +010066 sym = sym_lookup("KERNELVERSION", 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 sym->type = S_STRING;
68 sym->flags |= SYMBOL_AUTO;
Sam Ravnborg2244cbd2006-01-16 12:12:12 +010069 p = getenv("KERNELVERSION");
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 if (p)
71 sym_add_default(sym, p);
72
73 sym = sym_lookup("UNAME_RELEASE", 0);
74 sym->type = S_STRING;
75 sym->flags |= SYMBOL_AUTO;
76 sym_add_default(sym, uts.release);
77}
78
79enum symbol_type sym_get_type(struct symbol *sym)
80{
81 enum symbol_type type = sym->type;
82
83 if (type == S_TRISTATE) {
84 if (sym_is_choice_value(sym) && sym->visible == yes)
85 type = S_BOOLEAN;
86 else if (modules_val == no)
87 type = S_BOOLEAN;
88 }
89 return type;
90}
91
92const char *sym_type_name(enum symbol_type type)
93{
94 switch (type) {
95 case S_BOOLEAN:
96 return "boolean";
97 case S_TRISTATE:
98 return "tristate";
99 case S_INT:
100 return "integer";
101 case S_HEX:
102 return "hex";
103 case S_STRING:
104 return "string";
105 case S_UNKNOWN:
106 return "unknown";
107 case S_OTHER:
108 break;
109 }
110 return "???";
111}
112
113struct property *sym_get_choice_prop(struct symbol *sym)
114{
115 struct property *prop;
116
117 for_all_choices(sym, prop)
118 return prop;
119 return NULL;
120}
121
Roman Zippel93449082008-01-14 04:50:54 +0100122struct property *sym_get_env_prop(struct symbol *sym)
123{
124 struct property *prop;
125
126 for_all_properties(sym, prop, P_ENV)
127 return prop;
128 return NULL;
129}
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131struct property *sym_get_default_prop(struct symbol *sym)
132{
133 struct property *prop;
134
135 for_all_defaults(sym, prop) {
136 prop->visible.tri = expr_calc_value(prop->visible.expr);
137 if (prop->visible.tri != no)
138 return prop;
139 }
140 return NULL;
141}
142
143struct property *sym_get_range_prop(struct symbol *sym)
144{
145 struct property *prop;
146
147 for_all_properties(sym, prop, P_RANGE) {
148 prop->visible.tri = expr_calc_value(prop->visible.expr);
149 if (prop->visible.tri != no)
150 return prop;
151 }
152 return NULL;
153}
154
Roman Zippel4cf3cbe2005-11-08 21:34:49 -0800155static int sym_get_range_val(struct symbol *sym, int base)
156{
157 sym_calc_value(sym);
158 switch (sym->type) {
159 case S_INT:
160 base = 10;
161 break;
162 case S_HEX:
163 base = 16;
164 break;
165 default:
166 break;
167 }
168 return strtol(sym->curr.val, NULL, base);
169}
170
171static void sym_validate_range(struct symbol *sym)
172{
173 struct property *prop;
174 int base, val, val2;
175 char str[64];
176
177 switch (sym->type) {
178 case S_INT:
179 base = 10;
180 break;
181 case S_HEX:
182 base = 16;
183 break;
184 default:
185 return;
186 }
187 prop = sym_get_range_prop(sym);
188 if (!prop)
189 return;
190 val = strtol(sym->curr.val, NULL, base);
191 val2 = sym_get_range_val(prop->expr->left.sym, base);
192 if (val >= val2) {
193 val2 = sym_get_range_val(prop->expr->right.sym, base);
194 if (val <= val2)
195 return;
196 }
197 if (sym->type == S_INT)
198 sprintf(str, "%d", val2);
199 else
200 sprintf(str, "0x%x", val2);
201 sym->curr.val = strdup(str);
202}
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static void sym_calc_visibility(struct symbol *sym)
205{
206 struct property *prop;
207 tristate tri;
208
209 /* any prompt visible? */
210 tri = no;
211 for_all_prompts(sym, prop) {
212 prop->visible.tri = expr_calc_value(prop->visible.expr);
Sam Ravnborgd6ee3572008-01-07 21:09:55 +0100213 tri = EXPR_OR(tri, prop->visible.tri);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 }
215 if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
216 tri = yes;
217 if (sym->visible != tri) {
218 sym->visible = tri;
219 sym_set_changed(sym);
220 }
221 if (sym_is_choice_value(sym))
222 return;
223 tri = no;
224 if (sym->rev_dep.expr)
225 tri = expr_calc_value(sym->rev_dep.expr);
226 if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
227 tri = yes;
228 if (sym->rev_dep.tri != tri) {
229 sym->rev_dep.tri = tri;
230 sym_set_changed(sym);
231 }
232}
233
234static struct symbol *sym_calc_choice(struct symbol *sym)
235{
236 struct symbol *def_sym;
237 struct property *prop;
238 struct expr *e;
239
240 /* is the user choice visible? */
Roman Zippel0c1822e2006-06-08 22:12:41 -0700241 def_sym = sym->def[S_DEF_USER].val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 if (def_sym) {
243 sym_calc_visibility(def_sym);
244 if (def_sym->visible != no)
245 return def_sym;
246 }
247
248 /* any of the defaults visible? */
249 for_all_defaults(sym, prop) {
250 prop->visible.tri = expr_calc_value(prop->visible.expr);
251 if (prop->visible.tri == no)
252 continue;
253 def_sym = prop_get_symbol(prop);
254 sym_calc_visibility(def_sym);
255 if (def_sym->visible != no)
256 return def_sym;
257 }
258
259 /* just get the first visible value */
260 prop = sym_get_choice_prop(sym);
Roman Zippel7a962922008-01-14 04:50:23 +0100261 expr_list_for_each_sym(prop->expr, e, def_sym) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 sym_calc_visibility(def_sym);
263 if (def_sym->visible != no)
264 return def_sym;
265 }
266
267 /* no choice? reset tristate value */
268 sym->curr.tri = no;
269 return NULL;
270}
271
272void sym_calc_value(struct symbol *sym)
273{
274 struct symbol_value newval, oldval;
275 struct property *prop;
276 struct expr *e;
277
278 if (!sym)
279 return;
280
281 if (sym->flags & SYMBOL_VALID)
282 return;
283 sym->flags |= SYMBOL_VALID;
284
285 oldval = sym->curr;
286
287 switch (sym->type) {
288 case S_INT:
289 case S_HEX:
290 case S_STRING:
291 newval = symbol_empty.curr;
292 break;
293 case S_BOOLEAN:
294 case S_TRISTATE:
295 newval = symbol_no.curr;
296 break;
297 default:
298 sym->curr.val = sym->name;
299 sym->curr.tri = no;
300 return;
301 }
302 if (!sym_is_choice_value(sym))
303 sym->flags &= ~SYMBOL_WRITE;
304
305 sym_calc_visibility(sym);
306
307 /* set default if recursively called */
308 sym->curr = newval;
309
310 switch (sym_get_type(sym)) {
311 case S_BOOLEAN:
312 case S_TRISTATE:
313 if (sym_is_choice_value(sym) && sym->visible == yes) {
314 prop = sym_get_choice_prop(sym);
315 newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
Sam Ravnborgd6ee3572008-01-07 21:09:55 +0100316 } else if (EXPR_OR(sym->visible, sym->rev_dep.tri) != no) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 sym->flags |= SYMBOL_WRITE;
318 if (sym_has_value(sym))
Roman Zippel0c1822e2006-06-08 22:12:41 -0700319 newval.tri = sym->def[S_DEF_USER].tri;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 else if (!sym_is_choice(sym)) {
321 prop = sym_get_default_prop(sym);
322 if (prop)
323 newval.tri = expr_calc_value(prop->expr);
324 }
Sam Ravnborgd6ee3572008-01-07 21:09:55 +0100325 newval.tri = EXPR_OR(EXPR_AND(newval.tri, sym->visible), sym->rev_dep.tri);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 } else if (!sym_is_choice(sym)) {
327 prop = sym_get_default_prop(sym);
328 if (prop) {
329 sym->flags |= SYMBOL_WRITE;
330 newval.tri = expr_calc_value(prop->expr);
331 }
332 }
333 if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
334 newval.tri = yes;
335 break;
336 case S_STRING:
337 case S_HEX:
338 case S_INT:
339 if (sym->visible != no) {
340 sym->flags |= SYMBOL_WRITE;
341 if (sym_has_value(sym)) {
Roman Zippel0c1822e2006-06-08 22:12:41 -0700342 newval.val = sym->def[S_DEF_USER].val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 break;
344 }
345 }
346 prop = sym_get_default_prop(sym);
347 if (prop) {
348 struct symbol *ds = prop_get_symbol(prop);
349 if (ds) {
350 sym->flags |= SYMBOL_WRITE;
351 sym_calc_value(ds);
352 newval.val = ds->curr.val;
353 }
354 }
355 break;
356 default:
357 ;
358 }
359
Roman Zippel93449082008-01-14 04:50:54 +0100360 if (sym->flags & SYMBOL_AUTO)
361 sym->flags &= ~SYMBOL_WRITE;
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 sym->curr = newval;
364 if (sym_is_choice(sym) && newval.tri == yes)
365 sym->curr.val = sym_calc_choice(sym);
Roman Zippel4cf3cbe2005-11-08 21:34:49 -0800366 sym_validate_range(sym);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Roman Zippelface4372006-06-08 22:12:45 -0700368 if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 sym_set_changed(sym);
Roman Zippelface4372006-06-08 22:12:45 -0700370 if (modules_sym == sym) {
371 sym_set_all_changed();
372 modules_val = modules_sym->curr.tri;
373 }
374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 if (sym_is_choice(sym)) {
Roman Zippel7a962922008-01-14 04:50:23 +0100377 struct symbol *choice_sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
Roman Zippel7a962922008-01-14 04:50:23 +0100379
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 prop = sym_get_choice_prop(sym);
Roman Zippel7a962922008-01-14 04:50:23 +0100381 expr_list_for_each_sym(prop->expr, e, choice_sym) {
382 choice_sym->flags |= flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 if (flags & SYMBOL_CHANGED)
Roman Zippel7a962922008-01-14 04:50:23 +0100384 sym_set_changed(choice_sym);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386 }
387}
388
389void sym_clear_all_valid(void)
390{
391 struct symbol *sym;
392 int i;
393
394 for_all_symbols(i, sym)
395 sym->flags &= ~SYMBOL_VALID;
Karsten Wiesebfc10002006-12-13 00:34:07 -0800396 sym_add_change_count(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (modules_sym)
398 sym_calc_value(modules_sym);
399}
400
401void sym_set_changed(struct symbol *sym)
402{
403 struct property *prop;
404
405 sym->flags |= SYMBOL_CHANGED;
406 for (prop = sym->prop; prop; prop = prop->next) {
407 if (prop->menu)
408 prop->menu->flags |= MENU_CHANGED;
409 }
410}
411
412void sym_set_all_changed(void)
413{
414 struct symbol *sym;
415 int i;
416
417 for_all_symbols(i, sym)
418 sym_set_changed(sym);
419}
420
421bool sym_tristate_within_range(struct symbol *sym, tristate val)
422{
423 int type = sym_get_type(sym);
424
425 if (sym->visible == no)
426 return false;
427
428 if (type != S_BOOLEAN && type != S_TRISTATE)
429 return false;
430
431 if (type == S_BOOLEAN && val == mod)
432 return false;
433 if (sym->visible <= sym->rev_dep.tri)
434 return false;
435 if (sym_is_choice_value(sym) && sym->visible == yes)
436 return val == yes;
437 return val >= sym->rev_dep.tri && val <= sym->visible;
438}
439
440bool sym_set_tristate_value(struct symbol *sym, tristate val)
441{
442 tristate oldval = sym_get_tristate_value(sym);
443
444 if (oldval != val && !sym_tristate_within_range(sym, val))
445 return false;
446
Roman Zippel669bfad2006-06-08 22:12:42 -0700447 if (!(sym->flags & SYMBOL_DEF_USER)) {
448 sym->flags |= SYMBOL_DEF_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 sym_set_changed(sym);
450 }
Roman Zippel3f23ca22005-11-08 21:34:48 -0800451 /*
452 * setting a choice value also resets the new flag of the choice
453 * symbol and all other choice values.
454 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if (sym_is_choice_value(sym) && val == yes) {
456 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
Roman Zippel3f23ca22005-11-08 21:34:48 -0800457 struct property *prop;
458 struct expr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Roman Zippel0c1822e2006-06-08 22:12:41 -0700460 cs->def[S_DEF_USER].val = sym;
Roman Zippel669bfad2006-06-08 22:12:42 -0700461 cs->flags |= SYMBOL_DEF_USER;
Roman Zippel3f23ca22005-11-08 21:34:48 -0800462 prop = sym_get_choice_prop(cs);
463 for (e = prop->expr; e; e = e->left.expr) {
464 if (e->right.sym->visible != no)
Roman Zippel669bfad2006-06-08 22:12:42 -0700465 e->right.sym->flags |= SYMBOL_DEF_USER;
Roman Zippel3f23ca22005-11-08 21:34:48 -0800466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 }
468
Roman Zippel0c1822e2006-06-08 22:12:41 -0700469 sym->def[S_DEF_USER].tri = val;
Roman Zippelface4372006-06-08 22:12:45 -0700470 if (oldval != val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 sym_clear_all_valid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
473 return true;
474}
475
476tristate sym_toggle_tristate_value(struct symbol *sym)
477{
478 tristate oldval, newval;
479
480 oldval = newval = sym_get_tristate_value(sym);
481 do {
482 switch (newval) {
483 case no:
484 newval = mod;
485 break;
486 case mod:
487 newval = yes;
488 break;
489 case yes:
490 newval = no;
491 break;
492 }
493 if (sym_set_tristate_value(sym, newval))
494 break;
495 } while (oldval != newval);
496 return newval;
497}
498
499bool sym_string_valid(struct symbol *sym, const char *str)
500{
501 signed char ch;
502
503 switch (sym->type) {
504 case S_STRING:
505 return true;
506 case S_INT:
507 ch = *str++;
508 if (ch == '-')
509 ch = *str++;
510 if (!isdigit(ch))
511 return false;
512 if (ch == '0' && *str != 0)
513 return false;
514 while ((ch = *str++)) {
515 if (!isdigit(ch))
516 return false;
517 }
518 return true;
519 case S_HEX:
520 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
521 str += 2;
522 ch = *str++;
523 do {
524 if (!isxdigit(ch))
525 return false;
526 } while ((ch = *str++));
527 return true;
528 case S_BOOLEAN:
529 case S_TRISTATE:
530 switch (str[0]) {
531 case 'y': case 'Y':
532 case 'm': case 'M':
533 case 'n': case 'N':
534 return true;
535 }
536 return false;
537 default:
538 return false;
539 }
540}
541
542bool sym_string_within_range(struct symbol *sym, const char *str)
543{
544 struct property *prop;
545 int val;
546
547 switch (sym->type) {
548 case S_STRING:
549 return sym_string_valid(sym, str);
550 case S_INT:
551 if (!sym_string_valid(sym, str))
552 return false;
553 prop = sym_get_range_prop(sym);
554 if (!prop)
555 return true;
556 val = strtol(str, NULL, 10);
Roman Zippel4cf3cbe2005-11-08 21:34:49 -0800557 return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
558 val <= sym_get_range_val(prop->expr->right.sym, 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 case S_HEX:
560 if (!sym_string_valid(sym, str))
561 return false;
562 prop = sym_get_range_prop(sym);
563 if (!prop)
564 return true;
565 val = strtol(str, NULL, 16);
Roman Zippel4cf3cbe2005-11-08 21:34:49 -0800566 return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
567 val <= sym_get_range_val(prop->expr->right.sym, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 case S_BOOLEAN:
569 case S_TRISTATE:
570 switch (str[0]) {
571 case 'y': case 'Y':
572 return sym_tristate_within_range(sym, yes);
573 case 'm': case 'M':
574 return sym_tristate_within_range(sym, mod);
575 case 'n': case 'N':
576 return sym_tristate_within_range(sym, no);
577 }
578 return false;
579 default:
580 return false;
581 }
582}
583
584bool sym_set_string_value(struct symbol *sym, const char *newval)
585{
586 const char *oldval;
587 char *val;
588 int size;
589
590 switch (sym->type) {
591 case S_BOOLEAN:
592 case S_TRISTATE:
593 switch (newval[0]) {
594 case 'y': case 'Y':
595 return sym_set_tristate_value(sym, yes);
596 case 'm': case 'M':
597 return sym_set_tristate_value(sym, mod);
598 case 'n': case 'N':
599 return sym_set_tristate_value(sym, no);
600 }
601 return false;
602 default:
603 ;
604 }
605
606 if (!sym_string_within_range(sym, newval))
607 return false;
608
Roman Zippel669bfad2006-06-08 22:12:42 -0700609 if (!(sym->flags & SYMBOL_DEF_USER)) {
610 sym->flags |= SYMBOL_DEF_USER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 sym_set_changed(sym);
612 }
613
Roman Zippel0c1822e2006-06-08 22:12:41 -0700614 oldval = sym->def[S_DEF_USER].val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 size = strlen(newval) + 1;
616 if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
617 size += 2;
Roman Zippel0c1822e2006-06-08 22:12:41 -0700618 sym->def[S_DEF_USER].val = val = malloc(size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 *val++ = '0';
620 *val++ = 'x';
621 } else if (!oldval || strcmp(oldval, newval))
Roman Zippel0c1822e2006-06-08 22:12:41 -0700622 sym->def[S_DEF_USER].val = val = malloc(size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 else
624 return true;
625
626 strcpy(val, newval);
627 free((void *)oldval);
628 sym_clear_all_valid();
629
630 return true;
631}
632
633const char *sym_get_string_value(struct symbol *sym)
634{
635 tristate val;
636
637 switch (sym->type) {
638 case S_BOOLEAN:
639 case S_TRISTATE:
640 val = sym_get_tristate_value(sym);
641 switch (val) {
642 case no:
643 return "n";
644 case mod:
645 return "m";
646 case yes:
647 return "y";
648 }
649 break;
650 default:
651 ;
652 }
653 return (const char *)sym->curr.val;
654}
655
656bool sym_is_changable(struct symbol *sym)
657{
658 return sym->visible > sym->rev_dep.tri;
659}
660
661struct symbol *sym_lookup(const char *name, int isconst)
662{
663 struct symbol *symbol;
664 const char *ptr;
665 char *new_name;
666 int hash = 0;
667
668 if (name) {
669 if (name[0] && !name[1]) {
670 switch (name[0]) {
671 case 'y': return &symbol_yes;
672 case 'm': return &symbol_mod;
673 case 'n': return &symbol_no;
674 }
675 }
676 for (ptr = name; *ptr; ptr++)
677 hash += *ptr;
678 hash &= 0xff;
679
680 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
681 if (!strcmp(symbol->name, name)) {
682 if ((isconst && symbol->flags & SYMBOL_CONST) ||
683 (!isconst && !(symbol->flags & SYMBOL_CONST)))
684 return symbol;
685 }
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 if (isconst)
698 symbol->flags |= SYMBOL_CONST;
699
700 symbol->next = symbol_hash[hash];
701 symbol_hash[hash] = symbol;
702
703 return symbol;
704}
705
706struct symbol *sym_find(const char *name)
707{
708 struct symbol *symbol = NULL;
709 const char *ptr;
710 int hash = 0;
711
712 if (!name)
713 return NULL;
714
715 if (name[0] && !name[1]) {
716 switch (name[0]) {
717 case 'y': return &symbol_yes;
718 case 'm': return &symbol_mod;
719 case 'n': return &symbol_no;
720 }
721 }
722 for (ptr = name; *ptr; ptr++)
723 hash += *ptr;
724 hash &= 0xff;
725
726 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
727 if (!strcmp(symbol->name, name) &&
728 !(symbol->flags & SYMBOL_CONST))
729 break;
730 }
731
732 return symbol;
733}
734
735struct symbol **sym_re_search(const char *pattern)
736{
737 struct symbol *sym, **sym_arr = NULL;
738 int i, cnt, size;
739 regex_t re;
740
741 cnt = size = 0;
742 /* Skip if empty */
743 if (strlen(pattern) == 0)
744 return NULL;
745 if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
746 return NULL;
747
748 for_all_symbols(i, sym) {
749 if (sym->flags & SYMBOL_CONST || !sym->name)
750 continue;
751 if (regexec(&re, sym->name, 0, NULL, 0))
752 continue;
753 if (cnt + 1 >= size) {
754 void *tmp = sym_arr;
755 size += 16;
756 sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
757 if (!sym_arr) {
758 free(tmp);
759 return NULL;
760 }
761 }
762 sym_arr[cnt++] = sym;
763 }
764 if (sym_arr)
765 sym_arr[cnt] = NULL;
766 regfree(&re);
767
768 return sym_arr;
769}
770
771
772struct symbol *sym_check_deps(struct symbol *sym);
773
774static struct symbol *sym_check_expr_deps(struct expr *e)
775{
776 struct symbol *sym;
777
778 if (!e)
779 return NULL;
780 switch (e->type) {
781 case E_OR:
782 case E_AND:
783 sym = sym_check_expr_deps(e->left.expr);
784 if (sym)
785 return sym;
786 return sym_check_expr_deps(e->right.expr);
787 case E_NOT:
788 return sym_check_expr_deps(e->left.expr);
789 case E_EQUAL:
790 case E_UNEQUAL:
791 sym = sym_check_deps(e->left.sym);
792 if (sym)
793 return sym;
794 return sym_check_deps(e->right.sym);
795 case E_SYMBOL:
796 return sym_check_deps(e->left.sym);
797 default:
798 break;
799 }
800 printf("Oops! How to check %d?\n", e->type);
801 return NULL;
802}
803
Sam Ravnborg5447d342007-05-06 09:20:10 +0200804/* return NULL when dependencies are OK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805struct symbol *sym_check_deps(struct symbol *sym)
806{
807 struct symbol *sym2;
808 struct property *prop;
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (sym->flags & SYMBOL_CHECK) {
Sam Ravnborg5447d342007-05-06 09:20:10 +0200811 fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
812 sym->prop->file->name, sym->prop->lineno, sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 return sym;
814 }
David Gibson3f04e7d2005-11-08 21:34:46 -0800815 if (sym->flags & SYMBOL_CHECKED)
816 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
819 sym2 = sym_check_expr_deps(sym->rev_dep.expr);
820 if (sym2)
821 goto out;
822
823 for (prop = sym->prop; prop; prop = prop->next) {
824 if (prop->type == P_CHOICE || prop->type == P_SELECT)
825 continue;
826 sym2 = sym_check_expr_deps(prop->visible.expr);
827 if (sym2)
828 goto out;
829 if (prop->type != P_DEFAULT || sym_is_choice(sym))
830 continue;
831 sym2 = sym_check_expr_deps(prop->expr);
832 if (sym2)
833 goto out;
834 }
835out:
Sam Ravnborg5447d342007-05-06 09:20:10 +0200836 if (sym2)
837 fprintf(stderr, " -> %s%s", sym->name, sym2 == sym? "\n": "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 sym->flags &= ~SYMBOL_CHECK;
839 return sym2;
840}
841
842struct property *prop_alloc(enum prop_type type, struct symbol *sym)
843{
844 struct property *prop;
845 struct property **propp;
846
847 prop = malloc(sizeof(*prop));
848 memset(prop, 0, sizeof(*prop));
849 prop->type = type;
850 prop->sym = sym;
851 prop->file = current_file;
852 prop->lineno = zconf_lineno();
853
854 /* append property to the prop list of symbol */
855 if (sym) {
856 for (propp = &sym->prop; *propp; propp = &(*propp)->next)
857 ;
858 *propp = prop;
859 }
860
861 return prop;
862}
863
864struct symbol *prop_get_symbol(struct property *prop)
865{
866 if (prop->expr && (prop->expr->type == E_SYMBOL ||
Roman Zippel7a962922008-01-14 04:50:23 +0100867 prop->expr->type == E_LIST))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 return prop->expr->left.sym;
869 return NULL;
870}
871
872const char *prop_get_type_name(enum prop_type type)
873{
874 switch (type) {
875 case P_PROMPT:
876 return "prompt";
Roman Zippel93449082008-01-14 04:50:54 +0100877 case P_ENV:
878 return "env";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 case P_COMMENT:
880 return "comment";
881 case P_MENU:
882 return "menu";
883 case P_DEFAULT:
884 return "default";
885 case P_CHOICE:
886 return "choice";
887 case P_SELECT:
888 return "select";
889 case P_RANGE:
890 return "range";
891 case P_UNKNOWN:
892 break;
893 }
894 return "unknown";
895}
Roman Zippel93449082008-01-14 04:50:54 +0100896
897void prop_add_env(const char *env)
898{
899 struct symbol *sym, *sym2;
900 struct property *prop;
901 char *p;
902
903 sym = current_entry->sym;
904 sym->flags |= SYMBOL_AUTO;
905 for_all_properties(sym, prop, P_ENV) {
906 sym2 = prop_get_symbol(prop);
907 if (strcmp(sym2->name, env))
908 menu_warn(current_entry, "redefining environment symbol from %s",
909 sym2->name);
910 return;
911 }
912
913 prop = prop_alloc(P_ENV, sym);
914 prop->expr = expr_alloc_symbol(sym_lookup(env, 1));
915
916 sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
917 sym_env_list->right.sym = sym;
918
919 p = getenv(env);
920 if (p)
921 sym_add_default(sym, p);
922 else
923 menu_warn(current_entry, "environment variable %s undefined", env);
924}