OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | #include "lkc.h" |
||
13 | |||
14 | struct symbol symbol_yes = { |
||
15 | .name = "y", |
||
16 | .curr = { "y", yes }, |
||
17 | .flags = SYMBOL_CONST|SYMBOL_VALID, |
||
18 | }, symbol_mod = { |
||
19 | .name = "m", |
||
20 | .curr = { "m", mod }, |
||
21 | .flags = SYMBOL_CONST|SYMBOL_VALID, |
||
22 | }, symbol_no = { |
||
23 | .name = "n", |
||
24 | .curr = { "n", no }, |
||
25 | .flags = SYMBOL_CONST|SYMBOL_VALID, |
||
26 | }, symbol_empty = { |
||
27 | .name = "", |
||
28 | .curr = { "", no }, |
||
29 | .flags = SYMBOL_VALID, |
||
30 | }; |
||
31 | |||
32 | struct symbol *sym_defconfig_list; |
||
33 | struct symbol *modules_sym; |
||
34 | tristate modules_val; |
||
35 | |||
36 | struct expr *sym_env_list; |
||
37 | |||
38 | static void sym_add_default(struct symbol *sym, const char *def) |
||
39 | { |
||
40 | struct property *prop = prop_alloc(P_DEFAULT, sym); |
||
41 | |||
42 | prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); |
||
43 | } |
||
44 | |||
45 | void sym_init(void) |
||
46 | { |
||
47 | struct symbol *sym; |
||
48 | struct utsname uts; |
||
49 | static bool inited = false; |
||
50 | |||
51 | if (inited) |
||
52 | return; |
||
53 | inited = true; |
||
54 | |||
55 | uname(&uts); |
||
56 | |||
57 | sym = sym_lookup("UNAME_RELEASE", 0); |
||
58 | sym->type = S_STRING; |
||
59 | sym->flags |= SYMBOL_AUTO; |
||
60 | sym_add_default(sym, uts.release); |
||
61 | } |
||
62 | |||
63 | enum symbol_type sym_get_type(struct symbol *sym) |
||
64 | { |
||
65 | enum symbol_type type = sym->type; |
||
66 | |||
67 | if (type == S_TRISTATE) { |
||
68 | if (sym_is_choice_value(sym) && sym->visible == yes) |
||
69 | type = S_BOOLEAN; |
||
70 | else if (modules_val == no) |
||
71 | type = S_BOOLEAN; |
||
72 | } |
||
73 | return type; |
||
74 | } |
||
75 | |||
76 | const char *sym_type_name(enum symbol_type type) |
||
77 | { |
||
78 | switch (type) { |
||
79 | case S_BOOLEAN: |
||
80 | return "boolean"; |
||
81 | case S_TRISTATE: |
||
82 | return "tristate"; |
||
83 | case S_INT: |
||
84 | return "integer"; |
||
85 | case S_HEX: |
||
86 | return "hex"; |
||
87 | case S_STRING: |
||
88 | return "string"; |
||
89 | case S_UNKNOWN: |
||
90 | return "unknown"; |
||
91 | case S_OTHER: |
||
92 | break; |
||
93 | } |
||
94 | return "???"; |
||
95 | } |
||
96 | |||
97 | struct property *sym_get_choice_prop(struct symbol *sym) |
||
98 | { |
||
99 | struct property *prop; |
||
100 | |||
101 | for_all_choices(sym, prop) |
||
102 | return prop; |
||
103 | return NULL; |
||
104 | } |
||
105 | |||
106 | struct property *sym_get_env_prop(struct symbol *sym) |
||
107 | { |
||
108 | struct property *prop; |
||
109 | |||
110 | for_all_properties(sym, prop, P_ENV) |
||
111 | return prop; |
||
112 | return NULL; |
||
113 | } |
||
114 | |||
115 | static struct property *sym_get_default_prop(struct symbol *sym) |
||
116 | { |
||
117 | struct property *prop; |
||
118 | |||
119 | for_all_defaults(sym, prop) { |
||
120 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
||
121 | if (prop->visible.tri != no) |
||
122 | return prop; |
||
123 | } |
||
124 | return NULL; |
||
125 | } |
||
126 | |||
127 | static struct property *sym_get_range_prop(struct symbol *sym) |
||
128 | { |
||
129 | struct property *prop; |
||
130 | |||
131 | for_all_properties(sym, prop, P_RANGE) { |
||
132 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
||
133 | if (prop->visible.tri != no) |
||
134 | return prop; |
||
135 | } |
||
136 | return NULL; |
||
137 | } |
||
138 | |||
139 | static long long sym_get_range_val(struct symbol *sym, int base) |
||
140 | { |
||
141 | sym_calc_value(sym); |
||
142 | switch (sym->type) { |
||
143 | case S_INT: |
||
144 | base = 10; |
||
145 | break; |
||
146 | case S_HEX: |
||
147 | base = 16; |
||
148 | break; |
||
149 | default: |
||
150 | break; |
||
151 | } |
||
152 | return strtoll(sym->curr.val, NULL, base); |
||
153 | } |
||
154 | |||
155 | static void sym_validate_range(struct symbol *sym) |
||
156 | { |
||
157 | struct property *prop; |
||
158 | int base; |
||
159 | long long val, val2; |
||
160 | char str[64]; |
||
161 | |||
162 | switch (sym->type) { |
||
163 | case S_INT: |
||
164 | base = 10; |
||
165 | break; |
||
166 | case S_HEX: |
||
167 | base = 16; |
||
168 | break; |
||
169 | default: |
||
170 | return; |
||
171 | } |
||
172 | prop = sym_get_range_prop(sym); |
||
173 | if (!prop) |
||
174 | return; |
||
175 | val = strtoll(sym->curr.val, NULL, base); |
||
176 | val2 = sym_get_range_val(prop->expr->left.sym, base); |
||
177 | if (val >= val2) { |
||
178 | val2 = sym_get_range_val(prop->expr->right.sym, base); |
||
179 | if (val <= val2) |
||
180 | return; |
||
181 | } |
||
182 | if (sym->type == S_INT) |
||
183 | sprintf(str, "%lld", val2); |
||
184 | else |
||
185 | sprintf(str, "0x%llx", val2); |
||
186 | sym->curr.val = strdup(str); |
||
187 | } |
||
188 | |||
189 | static void sym_set_changed(struct symbol *sym) |
||
190 | { |
||
191 | struct property *prop; |
||
192 | |||
193 | sym->flags |= SYMBOL_CHANGED; |
||
194 | for (prop = sym->prop; prop; prop = prop->next) { |
||
195 | if (prop->menu) |
||
196 | prop->menu->flags |= MENU_CHANGED; |
||
197 | } |
||
198 | } |
||
199 | |||
200 | static void sym_set_all_changed(void) |
||
201 | { |
||
202 | struct symbol *sym; |
||
203 | int i; |
||
204 | |||
205 | for_all_symbols(i, sym) |
||
206 | sym_set_changed(sym); |
||
207 | } |
||
208 | |||
209 | static void sym_calc_visibility(struct symbol *sym) |
||
210 | { |
||
211 | struct property *prop; |
||
212 | struct symbol *choice_sym = NULL; |
||
213 | tristate tri; |
||
214 | |||
215 | /* any prompt visible? */ |
||
216 | tri = no; |
||
217 | |||
218 | if (sym_is_choice_value(sym)) |
||
219 | choice_sym = prop_get_symbol(sym_get_choice_prop(sym)); |
||
220 | |||
221 | for_all_prompts(sym, prop) { |
||
222 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
||
223 | /* |
||
224 | * Tristate choice_values with visibility 'mod' are |
||
225 | * not visible if the corresponding choice's value is |
||
226 | * 'yes'. |
||
227 | */ |
||
228 | if (choice_sym && sym->type == S_TRISTATE && |
||
229 | prop->visible.tri == mod && choice_sym->curr.tri == yes) |
||
230 | prop->visible.tri = no; |
||
231 | |||
232 | tri = EXPR_OR(tri, prop->visible.tri); |
||
233 | } |
||
234 | if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) |
||
235 | tri = yes; |
||
236 | if (sym->visible != tri) { |
||
237 | sym->visible = tri; |
||
238 | sym_set_changed(sym); |
||
239 | } |
||
240 | if (sym_is_choice_value(sym)) |
||
241 | return; |
||
242 | /* defaulting to "yes" if no explicit "depends on" are given */ |
||
243 | tri = yes; |
||
244 | if (sym->dir_dep.expr) |
||
245 | tri = expr_calc_value(sym->dir_dep.expr); |
||
246 | if (tri == mod) |
||
247 | tri = yes; |
||
248 | if (sym->dir_dep.tri != tri) { |
||
249 | sym->dir_dep.tri = tri; |
||
250 | sym_set_changed(sym); |
||
251 | } |
||
252 | tri = no; |
||
253 | if (sym->rev_dep.expr) |
||
254 | tri = expr_calc_value(sym->rev_dep.expr); |
||
255 | if (tri == mod && sym_get_type(sym) == S_BOOLEAN) |
||
256 | tri = yes; |
||
257 | if (sym->rev_dep.tri != tri) { |
||
258 | sym->rev_dep.tri = tri; |
||
259 | sym_set_changed(sym); |
||
260 | } |
||
261 | } |
||
262 | |||
263 | /* |
||
264 | * Find the default symbol for a choice. |
||
265 | * First try the default values for the choice symbol |
||
266 | * Next locate the first visible choice value |
||
267 | * Return NULL if none was found |
||
268 | */ |
||
269 | struct symbol *sym_choice_default(struct symbol *sym) |
||
270 | { |
||
271 | struct symbol *def_sym; |
||
272 | struct property *prop; |
||
273 | struct expr *e; |
||
274 | |||
275 | /* any of the defaults visible? */ |
||
276 | for_all_defaults(sym, prop) { |
||
277 | prop->visible.tri = expr_calc_value(prop->visible.expr); |
||
278 | if (prop->visible.tri == no) |
||
279 | continue; |
||
280 | def_sym = prop_get_symbol(prop); |
||
281 | if (def_sym->visible != no) |
||
282 | return def_sym; |
||
283 | } |
||
284 | |||
285 | /* just get the first visible value */ |
||
286 | prop = sym_get_choice_prop(sym); |
||
287 | expr_list_for_each_sym(prop->expr, e, def_sym) |
||
288 | if (def_sym->visible != no) |
||
289 | return def_sym; |
||
290 | |||
291 | /* failed to locate any defaults */ |
||
292 | return NULL; |
||
293 | } |
||
294 | |||
295 | static struct symbol *sym_calc_choice(struct symbol *sym) |
||
296 | { |
||
297 | struct symbol *def_sym; |
||
298 | struct property *prop; |
||
299 | struct expr *e; |
||
300 | int flags; |
||
301 | |||
302 | /* first calculate all choice values' visibilities */ |
||
303 | flags = sym->flags; |
||
304 | prop = sym_get_choice_prop(sym); |
||
305 | expr_list_for_each_sym(prop->expr, e, def_sym) { |
||
306 | sym_calc_visibility(def_sym); |
||
307 | if (def_sym->visible != no) |
||
308 | flags &= def_sym->flags; |
||
309 | } |
||
310 | |||
311 | sym->flags &= flags | ~SYMBOL_DEF_USER; |
||
312 | |||
313 | /* is the user choice visible? */ |
||
314 | def_sym = sym->def[S_DEF_USER].val; |
||
315 | if (def_sym && def_sym->visible != no) |
||
316 | return def_sym; |
||
317 | |||
318 | def_sym = sym_choice_default(sym); |
||
319 | |||
320 | if (def_sym == NULL) |
||
321 | /* no choice? reset tristate value */ |
||
322 | sym->curr.tri = no; |
||
323 | |||
324 | return def_sym; |
||
325 | } |
||
326 | |||
327 | void sym_calc_value(struct symbol *sym) |
||
328 | { |
||
329 | struct symbol_value newval, oldval; |
||
330 | struct property *prop; |
||
331 | struct expr *e; |
||
332 | |||
333 | if (!sym) |
||
334 | return; |
||
335 | |||
336 | if (sym->flags & SYMBOL_VALID) |
||
337 | return; |
||
338 | |||
339 | if (sym_is_choice_value(sym) && |
||
340 | sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { |
||
341 | sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; |
||
342 | prop = sym_get_choice_prop(sym); |
||
343 | sym_calc_value(prop_get_symbol(prop)); |
||
344 | } |
||
345 | |||
346 | sym->flags |= SYMBOL_VALID; |
||
347 | |||
348 | oldval = sym->curr; |
||
349 | |||
350 | switch (sym->type) { |
||
351 | case S_INT: |
||
352 | case S_HEX: |
||
353 | case S_STRING: |
||
354 | newval = symbol_empty.curr; |
||
355 | break; |
||
356 | case S_BOOLEAN: |
||
357 | case S_TRISTATE: |
||
358 | newval = symbol_no.curr; |
||
359 | break; |
||
360 | default: |
||
361 | sym->curr.val = sym->name; |
||
362 | sym->curr.tri = no; |
||
363 | return; |
||
364 | } |
||
365 | if (!sym_is_choice_value(sym)) |
||
366 | sym->flags &= ~SYMBOL_WRITE; |
||
367 | |||
368 | sym_calc_visibility(sym); |
||
369 | |||
370 | /* set default if recursively called */ |
||
371 | sym->curr = newval; |
||
372 | |||
373 | switch (sym_get_type(sym)) { |
||
374 | case S_BOOLEAN: |
||
375 | case S_TRISTATE: |
||
376 | if (sym_is_choice_value(sym) && sym->visible == yes) { |
||
377 | prop = sym_get_choice_prop(sym); |
||
378 | newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; |
||
379 | } else { |
||
380 | if (sym->visible != no) { |
||
381 | /* if the symbol is visible use the user value |
||
382 | * if available, otherwise try the default value |
||
383 | */ |
||
384 | sym->flags |= SYMBOL_WRITE; |
||
385 | if (sym_has_value(sym)) { |
||
386 | newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, |
||
387 | sym->visible); |
||
388 | goto calc_newval; |
||
389 | } |
||
390 | } |
||
391 | if (sym->rev_dep.tri != no) |
||
392 | sym->flags |= SYMBOL_WRITE; |
||
393 | if (!sym_is_choice(sym)) { |
||
394 | prop = sym_get_default_prop(sym); |
||
395 | if (prop) { |
||
396 | sym->flags |= SYMBOL_WRITE; |
||
397 | newval.tri = EXPR_AND(expr_calc_value(prop->expr), |
||
398 | prop->visible.tri); |
||
399 | } |
||
400 | } |
||
401 | calc_newval: |
||
402 | if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { |
||
403 | newval.tri = no; |
||
404 | } else { |
||
405 | newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); |
||
406 | } |
||
407 | } |
||
408 | if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) |
||
409 | newval.tri = yes; |
||
410 | break; |
||
411 | case S_STRING: |
||
412 | case S_HEX: |
||
413 | case S_INT: |
||
414 | if (sym->visible != no) { |
||
415 | sym->flags |= SYMBOL_WRITE; |
||
416 | if (sym_has_value(sym)) { |
||
417 | newval.val = sym->def[S_DEF_USER].val; |
||
418 | break; |
||
419 | } |
||
420 | } |
||
421 | prop = sym_get_default_prop(sym); |
||
422 | if (prop) { |
||
423 | struct symbol *ds = prop_get_symbol(prop); |
||
424 | if (ds) { |
||
425 | sym->flags |= SYMBOL_WRITE; |
||
426 | sym_calc_value(ds); |
||
427 | newval.val = ds->curr.val; |
||
428 | } |
||
429 | } |
||
430 | break; |
||
431 | default: |
||
432 | ; |
||
433 | } |
||
434 | |||
435 | sym->curr = newval; |
||
436 | if (sym_is_choice(sym) && newval.tri == yes) |
||
437 | sym->curr.val = sym_calc_choice(sym); |
||
438 | sym_validate_range(sym); |
||
439 | |||
440 | if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { |
||
441 | sym_set_changed(sym); |
||
442 | if (modules_sym == sym) { |
||
443 | sym_set_all_changed(); |
||
444 | modules_val = modules_sym->curr.tri; |
||
445 | } |
||
446 | } |
||
447 | |||
448 | if (sym_is_choice(sym)) { |
||
449 | struct symbol *choice_sym; |
||
450 | |||
451 | prop = sym_get_choice_prop(sym); |
||
452 | expr_list_for_each_sym(prop->expr, e, choice_sym) { |
||
453 | if ((sym->flags & SYMBOL_WRITE) && |
||
454 | choice_sym->visible != no) |
||
455 | choice_sym->flags |= SYMBOL_WRITE; |
||
456 | if (sym->flags & SYMBOL_CHANGED) |
||
457 | sym_set_changed(choice_sym); |
||
458 | } |
||
459 | } |
||
460 | |||
461 | if (sym->flags & SYMBOL_AUTO) |
||
462 | sym->flags &= ~SYMBOL_WRITE; |
||
463 | |||
464 | if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) |
||
465 | set_all_choice_values(sym); |
||
466 | } |
||
467 | |||
468 | void sym_clear_all_valid(void) |
||
469 | { |
||
470 | struct symbol *sym; |
||
471 | int i; |
||
472 | |||
473 | for_all_symbols(i, sym) |
||
474 | sym->flags &= ~SYMBOL_VALID; |
||
475 | sym_add_change_count(1); |
||
476 | sym_calc_value(modules_sym); |
||
477 | } |
||
478 | |||
479 | bool sym_tristate_within_range(struct symbol *sym, tristate val) |
||
480 | { |
||
481 | int type = sym_get_type(sym); |
||
482 | |||
483 | if (sym->visible == no) |
||
484 | return false; |
||
485 | |||
486 | if (type != S_BOOLEAN && type != S_TRISTATE) |
||
487 | return false; |
||
488 | |||
489 | if (type == S_BOOLEAN && val == mod) |
||
490 | return false; |
||
491 | if (sym->visible <= sym->rev_dep.tri) |
||
492 | return false; |
||
493 | if (sym_is_choice_value(sym) && sym->visible == yes) |
||
494 | return val == yes; |
||
495 | return val >= sym->rev_dep.tri && val <= sym->visible; |
||
496 | } |
||
497 | |||
498 | bool sym_set_tristate_value(struct symbol *sym, tristate val) |
||
499 | { |
||
500 | tristate oldval = sym_get_tristate_value(sym); |
||
501 | |||
502 | if (oldval != val && !sym_tristate_within_range(sym, val)) |
||
503 | return false; |
||
504 | |||
505 | if (!(sym->flags & SYMBOL_DEF_USER)) { |
||
506 | sym->flags |= SYMBOL_DEF_USER; |
||
507 | sym_set_changed(sym); |
||
508 | } |
||
509 | /* |
||
510 | * setting a choice value also resets the new flag of the choice |
||
511 | * symbol and all other choice values. |
||
512 | */ |
||
513 | if (sym_is_choice_value(sym) && val == yes) { |
||
514 | struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); |
||
515 | struct property *prop; |
||
516 | struct expr *e; |
||
517 | |||
518 | cs->def[S_DEF_USER].val = sym; |
||
519 | cs->flags |= SYMBOL_DEF_USER; |
||
520 | prop = sym_get_choice_prop(cs); |
||
521 | for (e = prop->expr; e; e = e->left.expr) { |
||
522 | if (e->right.sym->visible != no) |
||
523 | e->right.sym->flags |= SYMBOL_DEF_USER; |
||
524 | } |
||
525 | } |
||
526 | |||
527 | sym->def[S_DEF_USER].tri = val; |
||
528 | if (oldval != val) |
||
529 | sym_clear_all_valid(); |
||
530 | |||
531 | return true; |
||
532 | } |
||
533 | |||
534 | tristate sym_toggle_tristate_value(struct symbol *sym) |
||
535 | { |
||
536 | tristate oldval, newval; |
||
537 | |||
538 | oldval = newval = sym_get_tristate_value(sym); |
||
539 | do { |
||
540 | switch (newval) { |
||
541 | case no: |
||
542 | newval = mod; |
||
543 | break; |
||
544 | case mod: |
||
545 | newval = yes; |
||
546 | break; |
||
547 | case yes: |
||
548 | newval = no; |
||
549 | break; |
||
550 | } |
||
551 | if (sym_set_tristate_value(sym, newval)) |
||
552 | break; |
||
553 | } while (oldval != newval); |
||
554 | return newval; |
||
555 | } |
||
556 | |||
557 | bool sym_string_valid(struct symbol *sym, const char *str) |
||
558 | { |
||
559 | signed char ch; |
||
560 | |||
561 | switch (sym->type) { |
||
562 | case S_STRING: |
||
563 | return true; |
||
564 | case S_INT: |
||
565 | ch = *str++; |
||
566 | if (ch == '-') |
||
567 | ch = *str++; |
||
568 | if (!isdigit(ch)) |
||
569 | return false; |
||
570 | if (ch == '0' && *str != 0) |
||
571 | return false; |
||
572 | while ((ch = *str++)) { |
||
573 | if (!isdigit(ch)) |
||
574 | return false; |
||
575 | } |
||
576 | return true; |
||
577 | case S_HEX: |
||
578 | if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) |
||
579 | str += 2; |
||
580 | ch = *str++; |
||
581 | do { |
||
582 | if (!isxdigit(ch)) |
||
583 | return false; |
||
584 | } while ((ch = *str++)); |
||
585 | return true; |
||
586 | case S_BOOLEAN: |
||
587 | case S_TRISTATE: |
||
588 | switch (str[0]) { |
||
589 | case 'y': case 'Y': |
||
590 | case 'm': case 'M': |
||
591 | case 'n': case 'N': |
||
592 | return true; |
||
593 | } |
||
594 | return false; |
||
595 | default: |
||
596 | return false; |
||
597 | } |
||
598 | } |
||
599 | |||
600 | bool sym_string_within_range(struct symbol *sym, const char *str) |
||
601 | { |
||
602 | struct property *prop; |
||
603 | long long val; |
||
604 | |||
605 | switch (sym->type) { |
||
606 | case S_STRING: |
||
607 | return sym_string_valid(sym, str); |
||
608 | case S_INT: |
||
609 | if (!sym_string_valid(sym, str)) |
||
610 | return false; |
||
611 | prop = sym_get_range_prop(sym); |
||
612 | if (!prop) |
||
613 | return true; |
||
614 | val = strtoll(str, NULL, 10); |
||
615 | return val >= sym_get_range_val(prop->expr->left.sym, 10) && |
||
616 | val <= sym_get_range_val(prop->expr->right.sym, 10); |
||
617 | case S_HEX: |
||
618 | if (!sym_string_valid(sym, str)) |
||
619 | return false; |
||
620 | prop = sym_get_range_prop(sym); |
||
621 | if (!prop) |
||
622 | return true; |
||
623 | val = strtoll(str, NULL, 16); |
||
624 | return val >= sym_get_range_val(prop->expr->left.sym, 16) && |
||
625 | val <= sym_get_range_val(prop->expr->right.sym, 16); |
||
626 | case S_BOOLEAN: |
||
627 | case S_TRISTATE: |
||
628 | switch (str[0]) { |
||
629 | case 'y': case 'Y': |
||
630 | return sym_tristate_within_range(sym, yes); |
||
631 | case 'm': case 'M': |
||
632 | return sym_tristate_within_range(sym, mod); |
||
633 | case 'n': case 'N': |
||
634 | return sym_tristate_within_range(sym, no); |
||
635 | } |
||
636 | return false; |
||
637 | default: |
||
638 | return false; |
||
639 | } |
||
640 | } |
||
641 | |||
642 | bool sym_set_string_value(struct symbol *sym, const char *newval) |
||
643 | { |
||
644 | const char *oldval; |
||
645 | char *val; |
||
646 | int size; |
||
647 | |||
648 | switch (sym->type) { |
||
649 | case S_BOOLEAN: |
||
650 | case S_TRISTATE: |
||
651 | switch (newval[0]) { |
||
652 | case 'y': case 'Y': |
||
653 | return sym_set_tristate_value(sym, yes); |
||
654 | case 'm': case 'M': |
||
655 | return sym_set_tristate_value(sym, mod); |
||
656 | case 'n': case 'N': |
||
657 | return sym_set_tristate_value(sym, no); |
||
658 | } |
||
659 | return false; |
||
660 | default: |
||
661 | ; |
||
662 | } |
||
663 | |||
664 | if (!sym_string_within_range(sym, newval)) |
||
665 | return false; |
||
666 | |||
667 | if (!(sym->flags & SYMBOL_DEF_USER)) { |
||
668 | sym->flags |= SYMBOL_DEF_USER; |
||
669 | sym_set_changed(sym); |
||
670 | } |
||
671 | |||
672 | oldval = sym->def[S_DEF_USER].val; |
||
673 | size = strlen(newval) + 1; |
||
674 | if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { |
||
675 | size += 2; |
||
676 | sym->def[S_DEF_USER].val = val = xmalloc(size); |
||
677 | *val++ = '0'; |
||
678 | *val++ = 'x'; |
||
679 | } else if (!oldval || strcmp(oldval, newval)) |
||
680 | sym->def[S_DEF_USER].val = val = xmalloc(size); |
||
681 | else |
||
682 | return true; |
||
683 | |||
684 | strcpy(val, newval); |
||
685 | free((void *)oldval); |
||
686 | sym_clear_all_valid(); |
||
687 | |||
688 | return true; |
||
689 | } |
||
690 | |||
691 | /* |
||
692 | * Find the default value associated to a symbol. |
||
693 | * For tristate symbol handle the modules=n case |
||
694 | * in which case "m" becomes "y". |
||
695 | * If the symbol does not have any default then fallback |
||
696 | * to the fixed default values. |
||
697 | */ |
||
698 | const char *sym_get_string_default(struct symbol *sym) |
||
699 | { |
||
700 | struct property *prop; |
||
701 | struct symbol *ds; |
||
702 | const char *str; |
||
703 | tristate val; |
||
704 | |||
705 | sym_calc_visibility(sym); |
||
706 | sym_calc_value(modules_sym); |
||
707 | val = symbol_no.curr.tri; |
||
708 | str = symbol_empty.curr.val; |
||
709 | |||
710 | /* If symbol has a default value look it up */ |
||
711 | prop = sym_get_default_prop(sym); |
||
712 | if (prop != NULL) { |
||
713 | switch (sym->type) { |
||
714 | case S_BOOLEAN: |
||
715 | case S_TRISTATE: |
||
716 | /* The visibility may limit the value from yes => mod */ |
||
717 | val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); |
||
718 | break; |
||
719 | default: |
||
720 | /* |
||
721 | * The following fails to handle the situation |
||
722 | * where a default value is further limited by |
||
723 | * the valid range. |
||
724 | */ |
||
725 | ds = prop_get_symbol(prop); |
||
726 | if (ds != NULL) { |
||
727 | sym_calc_value(ds); |
||
728 | str = (const char *)ds->curr.val; |
||
729 | } |
||
730 | } |
||
731 | } |
||
732 | |||
733 | /* Handle select statements */ |
||
734 | val = EXPR_OR(val, sym->rev_dep.tri); |
||
735 | |||
736 | /* transpose mod to yes if modules are not enabled */ |
||
737 | if (val == mod) |
||
738 | if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) |
||
739 | val = yes; |
||
740 | |||
741 | /* transpose mod to yes if type is bool */ |
||
742 | if (sym->type == S_BOOLEAN && val == mod) |
||
743 | val = yes; |
||
744 | |||
745 | switch (sym->type) { |
||
746 | case S_BOOLEAN: |
||
747 | case S_TRISTATE: |
||
748 | switch (val) { |
||
749 | case no: return "n"; |
||
750 | case mod: return "m"; |
||
751 | case yes: return "y"; |
||
752 | } |
||
753 | case S_INT: |
||
754 | case S_HEX: |
||
755 | return str; |
||
756 | case S_STRING: |
||
757 | return str; |
||
758 | case S_OTHER: |
||
759 | case S_UNKNOWN: |
||
760 | break; |
||
761 | } |
||
762 | return ""; |
||
763 | } |
||
764 | |||
765 | const char *sym_get_string_value(struct symbol *sym) |
||
766 | { |
||
767 | tristate val; |
||
768 | |||
769 | switch (sym->type) { |
||
770 | case S_BOOLEAN: |
||
771 | case S_TRISTATE: |
||
772 | val = sym_get_tristate_value(sym); |
||
773 | switch (val) { |
||
774 | case no: |
||
775 | return "n"; |
||
776 | case mod: |
||
777 | sym_calc_value(modules_sym); |
||
778 | return (modules_sym->curr.tri == no) ? "n" : "m"; |
||
779 | case yes: |
||
780 | return "y"; |
||
781 | } |
||
782 | break; |
||
783 | default: |
||
784 | ; |
||
785 | } |
||
786 | return (const char *)sym->curr.val; |
||
787 | } |
||
788 | |||
789 | bool sym_is_changable(struct symbol *sym) |
||
790 | { |
||
791 | return sym->visible > sym->rev_dep.tri; |
||
792 | } |
||
793 | |||
794 | static unsigned strhash(const char *s) |
||
795 | { |
||
796 | /* fnv32 hash */ |
||
797 | unsigned hash = 2166136261U; |
||
798 | for (; *s; s++) |
||
799 | hash = (hash ^ *s) * 0x01000193; |
||
800 | return hash; |
||
801 | } |
||
802 | |||
803 | struct symbol *sym_lookup(const char *name, int flags) |
||
804 | { |
||
805 | struct symbol *symbol; |
||
806 | char *new_name; |
||
807 | int hash; |
||
808 | |||
809 | if (name) { |
||
810 | if (name[0] && !name[1]) { |
||
811 | switch (name[0]) { |
||
812 | case 'y': return &symbol_yes; |
||
813 | case 'm': return &symbol_mod; |
||
814 | case 'n': return &symbol_no; |
||
815 | } |
||
816 | } |
||
817 | hash = strhash(name) % SYMBOL_HASHSIZE; |
||
818 | |||
819 | for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { |
||
820 | if (symbol->name && |
||
821 | !strcmp(symbol->name, name) && |
||
822 | (flags ? symbol->flags & flags |
||
823 | : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) |
||
824 | return symbol; |
||
825 | } |
||
826 | new_name = strdup(name); |
||
827 | } else { |
||
828 | new_name = NULL; |
||
829 | hash = 0; |
||
830 | } |
||
831 | |||
832 | symbol = xmalloc(sizeof(*symbol)); |
||
833 | memset(symbol, 0, sizeof(*symbol)); |
||
834 | symbol->name = new_name; |
||
835 | symbol->type = S_UNKNOWN; |
||
836 | symbol->flags |= flags; |
||
837 | |||
838 | symbol->next = symbol_hash[hash]; |
||
839 | symbol_hash[hash] = symbol; |
||
840 | |||
841 | return symbol; |
||
842 | } |
||
843 | |||
844 | struct symbol *sym_find(const char *name) |
||
845 | { |
||
846 | struct symbol *symbol = NULL; |
||
847 | int hash = 0; |
||
848 | |||
849 | if (!name) |
||
850 | return NULL; |
||
851 | |||
852 | if (name[0] && !name[1]) { |
||
853 | switch (name[0]) { |
||
854 | case 'y': return &symbol_yes; |
||
855 | case 'm': return &symbol_mod; |
||
856 | case 'n': return &symbol_no; |
||
857 | } |
||
858 | } |
||
859 | hash = strhash(name) % SYMBOL_HASHSIZE; |
||
860 | |||
861 | for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { |
||
862 | if (symbol->name && |
||
863 | !strcmp(symbol->name, name) && |
||
864 | !(symbol->flags & SYMBOL_CONST)) |
||
865 | break; |
||
866 | } |
||
867 | |||
868 | return symbol; |
||
869 | } |
||
870 | |||
871 | /* |
||
872 | * Expand symbol's names embedded in the string given in argument. Symbols' |
||
873 | * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to |
||
874 | * the empty string. |
||
875 | */ |
||
876 | const char *sym_expand_string_value(const char *in) |
||
877 | { |
||
878 | const char *src; |
||
879 | char *res; |
||
880 | size_t reslen; |
||
881 | |||
882 | reslen = strlen(in) + 1; |
||
883 | res = xmalloc(reslen); |
||
884 | res[0] = '\0'; |
||
885 | |||
886 | while ((src = strchr(in, '$'))) { |
||
887 | char *p, name[SYMBOL_MAXLENGTH]; |
||
888 | const char *symval = ""; |
||
889 | struct symbol *sym; |
||
890 | size_t newlen; |
||
891 | |||
892 | strncat(res, in, src - in); |
||
893 | src++; |
||
894 | |||
895 | p = name; |
||
896 | while (isalnum(*src) || *src == '_') |
||
897 | *p++ = *src++; |
||
898 | *p = '\0'; |
||
899 | |||
900 | sym = sym_find(name); |
||
901 | if (sym != NULL) { |
||
902 | sym_calc_value(sym); |
||
903 | symval = sym_get_string_value(sym); |
||
904 | } |
||
905 | |||
906 | newlen = strlen(res) + strlen(symval) + strlen(src) + 1; |
||
907 | if (newlen > reslen) { |
||
908 | reslen = newlen; |
||
909 | res = realloc(res, reslen); |
||
910 | } |
||
911 | |||
912 | strcat(res, symval); |
||
913 | in = src; |
||
914 | } |
||
915 | strcat(res, in); |
||
916 | |||
917 | return res; |
||
918 | } |
||
919 | |||
920 | const char *sym_escape_string_value(const char *in) |
||
921 | { |
||
922 | const char *p; |
||
923 | size_t reslen; |
||
924 | char *res; |
||
925 | size_t l; |
||
926 | |||
927 | reslen = strlen(in) + strlen("\"\"") + 1; |
||
928 | |||
929 | p = in; |
||
930 | for (;;) { |
||
931 | l = strcspn(p, "\"\\"); |
||
932 | p += l; |
||
933 | |||
934 | if (p[0] == '\0') |
||
935 | break; |
||
936 | |||
937 | reslen++; |
||
938 | p++; |
||
939 | } |
||
940 | |||
941 | res = xmalloc(reslen); |
||
942 | res[0] = '\0'; |
||
943 | |||
944 | strcat(res, "\""); |
||
945 | |||
946 | p = in; |
||
947 | for (;;) { |
||
948 | l = strcspn(p, "\"\\"); |
||
949 | strncat(res, p, l); |
||
950 | p += l; |
||
951 | |||
952 | if (p[0] == '\0') |
||
953 | break; |
||
954 | |||
955 | strcat(res, "\\"); |
||
956 | strncat(res, p++, 1); |
||
957 | } |
||
958 | |||
959 | strcat(res, "\""); |
||
960 | return res; |
||
961 | } |
||
962 | |||
963 | struct sym_match { |
||
964 | struct symbol *sym; |
||
965 | off_t so, eo; |
||
966 | }; |
||
967 | |||
968 | /* Compare matched symbols as thus: |
||
969 | * - first, symbols that match exactly |
||
970 | * - then, alphabetical sort |
||
971 | */ |
||
972 | static int sym_rel_comp(const void *sym1, const void *sym2) |
||
973 | { |
||
974 | const struct sym_match *s1 = sym1; |
||
975 | const struct sym_match *s2 = sym2; |
||
976 | int exact1, exact2; |
||
977 | |||
978 | /* Exact match: |
||
979 | * - if matched length on symbol s1 is the length of that symbol, |
||
980 | * then this symbol should come first; |
||
981 | * - if matched length on symbol s2 is the length of that symbol, |
||
982 | * then this symbol should come first. |
||
983 | * Note: since the search can be a regexp, both symbols may match |
||
984 | * exactly; if this is the case, we can't decide which comes first, |
||
985 | * and we fallback to sorting alphabetically. |
||
986 | */ |
||
987 | exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); |
||
988 | exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); |
||
989 | if (exact1 && !exact2) |
||
990 | return -1; |
||
991 | if (!exact1 && exact2) |
||
992 | return 1; |
||
993 | |||
994 | /* As a fallback, sort symbols alphabetically */ |
||
995 | return strcmp(s1->sym->name, s2->sym->name); |
||
996 | } |
||
997 | |||
998 | struct symbol **sym_re_search(const char *pattern) |
||
999 | { |
||
1000 | struct symbol *sym, **sym_arr = NULL; |
||
1001 | struct sym_match *sym_match_arr = NULL; |
||
1002 | int i, cnt, size; |
||
1003 | regex_t re; |
||
1004 | regmatch_t match[1]; |
||
1005 | |||
1006 | cnt = size = 0; |
||
1007 | /* Skip if empty */ |
||
1008 | if (strlen(pattern) == 0) |
||
1009 | return NULL; |
||
1010 | if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) |
||
1011 | return NULL; |
||
1012 | |||
1013 | for_all_symbols(i, sym) { |
||
1014 | if (sym->flags & SYMBOL_CONST || !sym->name) |
||
1015 | continue; |
||
1016 | if (regexec(&re, sym->name, 1, match, 0)) |
||
1017 | continue; |
||
1018 | if (cnt >= size) { |
||
1019 | void *tmp; |
||
1020 | size += 16; |
||
1021 | tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); |
||
1022 | if (!tmp) |
||
1023 | goto sym_re_search_free; |
||
1024 | sym_match_arr = tmp; |
||
1025 | } |
||
1026 | sym_calc_value(sym); |
||
1027 | /* As regexec returned 0, we know we have a match, so |
||
1028 | * we can use match[0].rm_[se]o without further checks |
||
1029 | */ |
||
1030 | sym_match_arr[cnt].so = match[0].rm_so; |
||
1031 | sym_match_arr[cnt].eo = match[0].rm_eo; |
||
1032 | sym_match_arr[cnt++].sym = sym; |
||
1033 | } |
||
1034 | if (sym_match_arr) { |
||
1035 | qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); |
||
1036 | sym_arr = malloc((cnt+1) * sizeof(struct symbol)); |
||
1037 | if (!sym_arr) |
||
1038 | goto sym_re_search_free; |
||
1039 | for (i = 0; i < cnt; i++) |
||
1040 | sym_arr[i] = sym_match_arr[i].sym; |
||
1041 | sym_arr[cnt] = NULL; |
||
1042 | } |
||
1043 | sym_re_search_free: |
||
1044 | /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ |
||
1045 | free(sym_match_arr); |
||
1046 | regfree(&re); |
||
1047 | |||
1048 | return sym_arr; |
||
1049 | } |
||
1050 | |||
1051 | /* |
||
1052 | * When we check for recursive dependencies we use a stack to save |
||
1053 | * current state so we can print out relevant info to user. |
||
1054 | * The entries are located on the call stack so no need to free memory. |
||
1055 | * Note insert() remove() must always match to properly clear the stack. |
||
1056 | */ |
||
1057 | static struct dep_stack { |
||
1058 | struct dep_stack *prev, *next; |
||
1059 | struct symbol *sym; |
||
1060 | struct property *prop; |
||
1061 | struct expr *expr; |
||
1062 | } *check_top; |
||
1063 | |||
1064 | static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) |
||
1065 | { |
||
1066 | memset(stack, 0, sizeof(*stack)); |
||
1067 | if (check_top) |
||
1068 | check_top->next = stack; |
||
1069 | stack->prev = check_top; |
||
1070 | stack->sym = sym; |
||
1071 | check_top = stack; |
||
1072 | } |
||
1073 | |||
1074 | static void dep_stack_remove(void) |
||
1075 | { |
||
1076 | check_top = check_top->prev; |
||
1077 | if (check_top) |
||
1078 | check_top->next = NULL; |
||
1079 | } |
||
1080 | |||
1081 | /* |
||
1082 | * Called when we have detected a recursive dependency. |
||
1083 | * check_top point to the top of the stact so we use |
||
1084 | * the ->prev pointer to locate the bottom of the stack. |
||
1085 | */ |
||
1086 | static void sym_check_print_recursive(struct symbol *last_sym) |
||
1087 | { |
||
1088 | struct dep_stack *stack; |
||
1089 | struct symbol *sym, *next_sym; |
||
1090 | struct menu *menu = NULL; |
||
1091 | struct property *prop; |
||
1092 | struct dep_stack cv_stack; |
||
1093 | |||
1094 | if (sym_is_choice_value(last_sym)) { |
||
1095 | dep_stack_insert(&cv_stack, last_sym); |
||
1096 | last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); |
||
1097 | } |
||
1098 | |||
1099 | for (stack = check_top; stack != NULL; stack = stack->prev) |
||
1100 | if (stack->sym == last_sym) |
||
1101 | break; |
||
1102 | if (!stack) { |
||
1103 | fprintf(stderr, "unexpected recursive dependency error\n"); |
||
1104 | return; |
||
1105 | } |
||
1106 | |||
1107 | for (; stack; stack = stack->next) { |
||
1108 | sym = stack->sym; |
||
1109 | next_sym = stack->next ? stack->next->sym : last_sym; |
||
1110 | prop = stack->prop; |
||
1111 | if (prop == NULL) |
||
1112 | prop = stack->sym->prop; |
||
1113 | |||
1114 | /* for choice values find the menu entry (used below) */ |
||
1115 | if (sym_is_choice(sym) || sym_is_choice_value(sym)) { |
||
1116 | for (prop = sym->prop; prop; prop = prop->next) { |
||
1117 | menu = prop->menu; |
||
1118 | if (prop->menu) |
||
1119 | break; |
||
1120 | } |
||
1121 | } |
||
1122 | if (stack->sym == last_sym) |
||
1123 | fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", |
||
1124 | prop->file->name, prop->lineno); |
||
1125 | fprintf(stderr, "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n"); |
||
1126 | fprintf(stderr, "subsection \"Kconfig recursive dependency limitations\"\n"); |
||
1127 | if (stack->expr) { |
||
1128 | fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", |
||
1129 | prop->file->name, prop->lineno, |
||
1130 | sym->name ? sym->name : "<choice>", |
||
1131 | prop_get_type_name(prop->type), |
||
1132 | next_sym->name ? next_sym->name : "<choice>"); |
||
1133 | } else if (stack->prop) { |
||
1134 | fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", |
||
1135 | prop->file->name, prop->lineno, |
||
1136 | sym->name ? sym->name : "<choice>", |
||
1137 | next_sym->name ? next_sym->name : "<choice>"); |
||
1138 | } else if (sym_is_choice(sym)) { |
||
1139 | fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", |
||
1140 | menu->file->name, menu->lineno, |
||
1141 | sym->name ? sym->name : "<choice>", |
||
1142 | next_sym->name ? next_sym->name : "<choice>"); |
||
1143 | } else if (sym_is_choice_value(sym)) { |
||
1144 | fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", |
||
1145 | menu->file->name, menu->lineno, |
||
1146 | sym->name ? sym->name : "<choice>", |
||
1147 | next_sym->name ? next_sym->name : "<choice>"); |
||
1148 | } else { |
||
1149 | fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", |
||
1150 | prop->file->name, prop->lineno, |
||
1151 | sym->name ? sym->name : "<choice>", |
||
1152 | next_sym->name ? next_sym->name : "<choice>"); |
||
1153 | } |
||
1154 | } |
||
1155 | |||
1156 | if (check_top == &cv_stack) |
||
1157 | dep_stack_remove(); |
||
1158 | } |
||
1159 | |||
1160 | static struct symbol *sym_check_expr_deps(struct expr *e) |
||
1161 | { |
||
1162 | struct symbol *sym; |
||
1163 | |||
1164 | if (!e) |
||
1165 | return NULL; |
||
1166 | switch (e->type) { |
||
1167 | case E_OR: |
||
1168 | case E_AND: |
||
1169 | sym = sym_check_expr_deps(e->left.expr); |
||
1170 | if (sym) |
||
1171 | return sym; |
||
1172 | return sym_check_expr_deps(e->right.expr); |
||
1173 | case E_NOT: |
||
1174 | return sym_check_expr_deps(e->left.expr); |
||
1175 | case E_EQUAL: |
||
1176 | case E_GEQ: |
||
1177 | case E_GTH: |
||
1178 | case E_LEQ: |
||
1179 | case E_LTH: |
||
1180 | case E_UNEQUAL: |
||
1181 | sym = sym_check_deps(e->left.sym); |
||
1182 | if (sym) |
||
1183 | return sym; |
||
1184 | return sym_check_deps(e->right.sym); |
||
1185 | case E_SYMBOL: |
||
1186 | return sym_check_deps(e->left.sym); |
||
1187 | default: |
||
1188 | break; |
||
1189 | } |
||
1190 | printf("Oops! How to check %d?\n", e->type); |
||
1191 | return NULL; |
||
1192 | } |
||
1193 | |||
1194 | /* return NULL when dependencies are OK */ |
||
1195 | static struct symbol *sym_check_sym_deps(struct symbol *sym) |
||
1196 | { |
||
1197 | struct symbol *sym2; |
||
1198 | struct property *prop; |
||
1199 | struct dep_stack stack; |
||
1200 | |||
1201 | dep_stack_insert(&stack, sym); |
||
1202 | |||
1203 | sym2 = sym_check_expr_deps(sym->rev_dep.expr); |
||
1204 | if (sym2) |
||
1205 | goto out; |
||
1206 | |||
1207 | for (prop = sym->prop; prop; prop = prop->next) { |
||
1208 | if (prop->type == P_CHOICE || prop->type == P_SELECT) |
||
1209 | continue; |
||
1210 | stack.prop = prop; |
||
1211 | sym2 = sym_check_expr_deps(prop->visible.expr); |
||
1212 | if (sym2) |
||
1213 | break; |
||
1214 | if (prop->type != P_DEFAULT || sym_is_choice(sym)) |
||
1215 | continue; |
||
1216 | stack.expr = prop->expr; |
||
1217 | sym2 = sym_check_expr_deps(prop->expr); |
||
1218 | if (sym2) |
||
1219 | break; |
||
1220 | stack.expr = NULL; |
||
1221 | } |
||
1222 | |||
1223 | out: |
||
1224 | dep_stack_remove(); |
||
1225 | |||
1226 | return sym2; |
||
1227 | } |
||
1228 | |||
1229 | static struct symbol *sym_check_choice_deps(struct symbol *choice) |
||
1230 | { |
||
1231 | struct symbol *sym, *sym2; |
||
1232 | struct property *prop; |
||
1233 | struct expr *e; |
||
1234 | struct dep_stack stack; |
||
1235 | |||
1236 | dep_stack_insert(&stack, choice); |
||
1237 | |||
1238 | prop = sym_get_choice_prop(choice); |
||
1239 | expr_list_for_each_sym(prop->expr, e, sym) |
||
1240 | sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
||
1241 | |||
1242 | choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
||
1243 | sym2 = sym_check_sym_deps(choice); |
||
1244 | choice->flags &= ~SYMBOL_CHECK; |
||
1245 | if (sym2) |
||
1246 | goto out; |
||
1247 | |||
1248 | expr_list_for_each_sym(prop->expr, e, sym) { |
||
1249 | sym2 = sym_check_sym_deps(sym); |
||
1250 | if (sym2) |
||
1251 | break; |
||
1252 | } |
||
1253 | out: |
||
1254 | expr_list_for_each_sym(prop->expr, e, sym) |
||
1255 | sym->flags &= ~SYMBOL_CHECK; |
||
1256 | |||
1257 | if (sym2 && sym_is_choice_value(sym2) && |
||
1258 | prop_get_symbol(sym_get_choice_prop(sym2)) == choice) |
||
1259 | sym2 = choice; |
||
1260 | |||
1261 | dep_stack_remove(); |
||
1262 | |||
1263 | return sym2; |
||
1264 | } |
||
1265 | |||
1266 | struct symbol *sym_check_deps(struct symbol *sym) |
||
1267 | { |
||
1268 | struct symbol *sym2; |
||
1269 | struct property *prop; |
||
1270 | |||
1271 | if (sym->flags & SYMBOL_CHECK) { |
||
1272 | sym_check_print_recursive(sym); |
||
1273 | return sym; |
||
1274 | } |
||
1275 | if (sym->flags & SYMBOL_CHECKED) |
||
1276 | return NULL; |
||
1277 | |||
1278 | if (sym_is_choice_value(sym)) { |
||
1279 | struct dep_stack stack; |
||
1280 | |||
1281 | /* for choice groups start the check with main choice symbol */ |
||
1282 | dep_stack_insert(&stack, sym); |
||
1283 | prop = sym_get_choice_prop(sym); |
||
1284 | sym2 = sym_check_deps(prop_get_symbol(prop)); |
||
1285 | dep_stack_remove(); |
||
1286 | } else if (sym_is_choice(sym)) { |
||
1287 | sym2 = sym_check_choice_deps(sym); |
||
1288 | } else { |
||
1289 | sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
||
1290 | sym2 = sym_check_sym_deps(sym); |
||
1291 | sym->flags &= ~SYMBOL_CHECK; |
||
1292 | } |
||
1293 | |||
1294 | if (sym2 && sym2 == sym) |
||
1295 | sym2 = NULL; |
||
1296 | |||
1297 | return sym2; |
||
1298 | } |
||
1299 | |||
1300 | struct property *prop_alloc(enum prop_type type, struct symbol *sym) |
||
1301 | { |
||
1302 | struct property *prop; |
||
1303 | struct property **propp; |
||
1304 | |||
1305 | prop = xmalloc(sizeof(*prop)); |
||
1306 | memset(prop, 0, sizeof(*prop)); |
||
1307 | prop->type = type; |
||
1308 | prop->sym = sym; |
||
1309 | prop->file = current_file; |
||
1310 | prop->lineno = zconf_lineno(); |
||
1311 | |||
1312 | /* append property to the prop list of symbol */ |
||
1313 | if (sym) { |
||
1314 | for (propp = &sym->prop; *propp; propp = &(*propp)->next) |
||
1315 | ; |
||
1316 | *propp = prop; |
||
1317 | } |
||
1318 | |||
1319 | return prop; |
||
1320 | } |
||
1321 | |||
1322 | struct symbol *prop_get_symbol(struct property *prop) |
||
1323 | { |
||
1324 | if (prop->expr && (prop->expr->type == E_SYMBOL || |
||
1325 | prop->expr->type == E_LIST)) |
||
1326 | return prop->expr->left.sym; |
||
1327 | return NULL; |
||
1328 | } |
||
1329 | |||
1330 | const char *prop_get_type_name(enum prop_type type) |
||
1331 | { |
||
1332 | switch (type) { |
||
1333 | case P_PROMPT: |
||
1334 | return "prompt"; |
||
1335 | case P_ENV: |
||
1336 | return "env"; |
||
1337 | case P_COMMENT: |
||
1338 | return "comment"; |
||
1339 | case P_MENU: |
||
1340 | return "menu"; |
||
1341 | case P_DEFAULT: |
||
1342 | return "default"; |
||
1343 | case P_CHOICE: |
||
1344 | return "choice"; |
||
1345 | case P_SELECT: |
||
1346 | return "select"; |
||
1347 | case P_RANGE: |
||
1348 | return "range"; |
||
1349 | case P_SYMBOL: |
||
1350 | return "symbol"; |
||
1351 | case P_RESET: |
||
1352 | return "reset"; |
||
1353 | case P_UNKNOWN: |
||
1354 | break; |
||
1355 | } |
||
1356 | return "unknown"; |
||
1357 | } |
||
1358 | |||
1359 | static void prop_add_env(const char *env) |
||
1360 | { |
||
1361 | struct symbol *sym, *sym2; |
||
1362 | struct property *prop; |
||
1363 | char *p; |
||
1364 | |||
1365 | sym = current_entry->sym; |
||
1366 | sym->flags |= SYMBOL_AUTO; |
||
1367 | for_all_properties(sym, prop, P_ENV) { |
||
1368 | sym2 = prop_get_symbol(prop); |
||
1369 | if (strcmp(sym2->name, env)) |
||
1370 | menu_warn(current_entry, "redefining environment symbol from %s", |
||
1371 | sym2->name); |
||
1372 | return; |
||
1373 | } |
||
1374 | |||
1375 | prop = prop_alloc(P_ENV, sym); |
||
1376 | prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); |
||
1377 | |||
1378 | sym_env_list = expr_alloc_one(E_LIST, sym_env_list); |
||
1379 | sym_env_list->right.sym = sym; |
||
1380 | |||
1381 | p = getenv(env); |
||
1382 | if (p) |
||
1383 | sym_add_default(sym, p); |
||
1384 | else |
||
1385 | menu_warn(current_entry, "environment variable %s undefined", env); |
||
1386 | } |