summaryrefslogtreecommitdiff
path: root/scripts/kconfig/symbol.c
Unidiff
Diffstat (limited to 'scripts/kconfig/symbol.c') (more/less context) (ignore whitespace changes)
-rw-r--r--scripts/kconfig/symbol.c618
1 files changed, 618 insertions, 0 deletions
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
new file mode 100644
index 0000000..59c88d2
--- a/dev/null
+++ b/scripts/kconfig/symbol.c
@@ -0,0 +1,618 @@
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 <sys/utsname.h>
10
11#define LKC_DIRECT_LINK
12#include "lkc.h"
13
14struct symbol symbol_yes = {
15 name: "y",
16 curr: { "y", yes },
17 flags: SYMBOL_YES|SYMBOL_VALID,
18}, symbol_mod = {
19 name: "m",
20 curr: { "m", mod },
21 flags: SYMBOL_MOD|SYMBOL_VALID,
22}, symbol_no = {
23 name: "n",
24 curr: { "n", no },
25 flags: SYMBOL_NO|SYMBOL_VALID,
26}, symbol_empty = {
27 name: "",
28 curr: { "", no },
29 flags: SYMBOL_VALID,
30};
31
32int sym_change_count;
33struct symbol *modules_sym;
34
35void sym_add_default(struct symbol *sym, const char *def)
36{
37 struct property *prop = create_prop(P_DEFAULT);
38 struct property **propp;
39
40 prop->sym = sym;
41 prop->def = sym_lookup(def, 1);
42
43 /* append property to the prop list of symbol */
44 if (prop->sym) {
45 for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
46 ;
47 *propp = prop;
48 }
49}
50
51void sym_init(void)
52{
53 struct symbol *sym;
54 struct utsname uts;
55 char *p;
56 static bool inited = false;
57
58 if (inited)
59 return;
60 inited = true;
61
62 uname(&uts);
63
64 sym = sym_lookup("ARCH", 0);
65 sym->type = S_STRING;
66 sym->flags |= SYMBOL_AUTO;
67 p = getenv("ARCH");
68 if (p)
69 sym_add_default(sym, p);
70
71 sym = sym_lookup("KERNELRELEASE", 0);
72 sym->type = S_STRING;
73 sym->flags |= SYMBOL_AUTO;
74 p = getenv("KERNELRELEASE");
75 if (p)
76 sym_add_default(sym, p);
77
78 sym = sym_lookup("UNAME_RELEASE", 0);
79 sym->type = S_STRING;
80 sym->flags |= SYMBOL_AUTO;
81 sym_add_default(sym, uts.release);
82}
83
84int sym_get_type(struct symbol *sym)
85{
86 int type = sym->type;
87 if (type == S_TRISTATE) {
88 if (sym_is_choice_value(sym) && sym->visible == yes)
89 type = S_BOOLEAN;
90 else {
91 sym_calc_value(modules_sym);
92 if (S_TRI(modules_sym->curr) == no)
93 type = S_BOOLEAN;
94 }
95 }
96 return type;
97}
98
99const char *sym_type_name(int type)
100{
101 switch (type) {
102 case S_BOOLEAN:
103 return "boolean";
104 case S_TRISTATE:
105 return "tristate";
106 case S_INT:
107 return "integer";
108 case S_HEX:
109 return "hex";
110 case S_STRING:
111 return "string";
112 case S_UNKNOWN:
113 return "unknown";
114 }
115 return "???";
116}
117
118struct property *sym_get_choice_prop(struct symbol *sym)
119{
120 struct property *prop;
121
122 for_all_choices(sym, prop)
123 return prop;
124 return NULL;
125}
126
127struct property *sym_get_default_prop(struct symbol *sym)
128{
129 struct property *prop;
130 tristate visible;
131
132 for_all_defaults(sym, prop) {
133 visible = E_CALC(prop->visible);
134 if (visible != no)
135 return prop;
136 }
137 return NULL;
138}
139
140void sym_calc_visibility(struct symbol *sym)
141{
142 struct property *prop;
143 tristate visible, oldvisible;
144
145 /* any prompt visible? */
146 oldvisible = sym->visible;
147 visible = no;
148 for_all_prompts(sym, prop)
149 visible = E_OR(visible, E_CALC(prop->visible));
150 if (oldvisible != visible) {
151 sym->visible = visible;
152 sym->flags |= SYMBOL_CHANGED;
153 }
154}
155
156void sym_calc_value(struct symbol *sym)
157{
158 struct symbol_value newval, oldval;
159 struct property *prop, *def_prop;
160 struct symbol *def_sym;
161 struct expr *e;
162
163 if (sym->flags & SYMBOL_VALID)
164 return;
165
166 oldval = sym->curr;
167
168 switch (sym->type) {
169 case S_INT:
170 case S_HEX:
171 case S_STRING:
172 newval = symbol_empty.curr;
173 break;
174 case S_BOOLEAN:
175 case S_TRISTATE:
176 newval = symbol_no.curr;
177 break;
178 default:
179 S_VAL(newval) = sym->name;
180 S_TRI(newval) = no;
181 if (sym->flags & SYMBOL_CONST) {
182 goto out;
183 }
184 //newval = symbol_empty.curr;
185 // generate warning somewhere here later
186 //S_TRI(newval) = yes;
187 goto out;
188 }
189 sym->flags |= SYMBOL_VALID;
190 if (!sym_is_choice_value(sym))
191 sym->flags &= ~SYMBOL_WRITE;
192
193 sym_calc_visibility(sym);
194
195 /* set default if recursively called */
196 sym->curr = newval;
197
198 if (sym->visible != no) {
199 sym->flags |= SYMBOL_WRITE;
200 if (!sym_has_value(sym)) {
201 if (!sym_is_choice(sym)) {
202 prop = sym_get_default_prop(sym);
203 if (prop) {
204 sym_calc_value(prop->def);
205 newval = prop->def->curr;
206 }
207 }
208 } else
209 newval = sym->def;
210
211 S_TRI(newval) = E_AND(S_TRI(newval), sym->visible);
212 /* if the symbol is visible and not optionial,
213 * possibly ignore old user choice. */
214 if (!sym_is_optional(sym) && S_TRI(newval) == no)
215 S_TRI(newval) = sym->visible;
216 if (sym_is_choice_value(sym) && sym->visible == yes) {
217 prop = sym_get_choice_prop(sym);
218 S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no;
219 }
220 } else {
221 prop = sym_get_default_prop(sym);
222 if (prop) {
223 sym->flags |= SYMBOL_WRITE;
224 sym_calc_value(prop->def);
225 newval = prop->def->curr;
226 }
227 }
228
229 switch (sym_get_type(sym)) {
230 case S_TRISTATE:
231 if (S_TRI(newval) != mod)
232 break;
233 sym_calc_value(modules_sym);
234 if (S_TRI(modules_sym->curr) == no)
235 S_TRI(newval) = yes;
236 break;
237 case S_BOOLEAN:
238 if (S_TRI(newval) == mod)
239 S_TRI(newval) = yes;
240 }
241
242out:
243 sym->curr = newval;
244
245 if (sym_is_choice(sym) && S_TRI(newval) == yes) {
246 def_sym = S_VAL(sym->def);
247 if (def_sym) {
248 sym_calc_visibility(def_sym);
249 if (def_sym->visible == no)
250 def_sym = NULL;
251 }
252 if (!def_sym) {
253 for_all_defaults(sym, def_prop) {
254 if (E_CALC(def_prop->visible) == no)
255 continue;
256 sym_calc_visibility(def_prop->def);
257 if (def_prop->def->visible != no) {
258 def_sym = def_prop->def;
259 break;
260 }
261 }
262 }
263
264 if (!def_sym) {
265 prop = sym_get_choice_prop(sym);
266 for (e = prop->dep; e; e = e->left.expr) {
267 sym_calc_visibility(e->right.sym);
268 if (e->right.sym->visible != no) {
269 def_sym = e->right.sym;
270 break;
271 }
272 }
273 }
274
275 S_VAL(newval) = def_sym;
276 }
277
278 if (memcmp(&oldval, &newval, sizeof(newval)))
279 sym->flags |= SYMBOL_CHANGED;
280 sym->curr = newval;
281
282 if (sym_is_choice(sym)) {
283 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
284 prop = sym_get_choice_prop(sym);
285 for (e = prop->dep; e; e = e->left.expr)
286 e->right.sym->flags |= flags;
287 }
288}
289
290void sym_clear_all_valid(void)
291{
292 struct symbol *sym;
293 int i;
294
295 for_all_symbols(i, sym)
296 sym->flags &= ~SYMBOL_VALID;
297 sym_change_count++;
298}
299
300void sym_set_all_changed(void)
301{
302 struct symbol *sym;
303 int i;
304
305 for_all_symbols(i, sym)
306 sym->flags |= SYMBOL_CHANGED;
307}
308
309bool sym_tristate_within_range(struct symbol *sym, tristate val)
310{
311 int type = sym_get_type(sym);
312
313 if (sym->visible == no)
314 return false;
315
316 if (type != S_BOOLEAN && type != S_TRISTATE)
317 return false;
318
319 switch (val) {
320 case no:
321 if (sym_is_choice_value(sym) && sym->visible == yes)
322 return false;
323 return sym_is_optional(sym);
324 case mod:
325 if (sym_is_choice_value(sym) && sym->visible == yes)
326 return false;
327 return type == S_TRISTATE;
328 case yes:
329 return type == S_BOOLEAN || sym->visible == yes;
330 }
331 return false;
332}
333
334bool sym_set_tristate_value(struct symbol *sym, tristate val)
335{
336 tristate oldval = sym_get_tristate_value(sym);
337
338 if (oldval != val && !sym_tristate_within_range(sym, val))
339 return false;
340
341 if (sym->flags & SYMBOL_NEW) {
342 sym->flags &= ~SYMBOL_NEW;
343 sym->flags |= SYMBOL_CHANGED;
344 }
345 if (sym_is_choice_value(sym) && val == yes) {
346 struct property *prop = sym_get_choice_prop(sym);
347
348 S_VAL(prop->def->def) = sym;
349 prop->def->flags &= ~SYMBOL_NEW;
350 }
351
352 S_TRI(sym->def) = val;
353 if (oldval != val) {
354 sym_clear_all_valid();
355 if (sym == modules_sym)
356 sym_set_all_changed();
357 }
358
359 return true;
360}
361
362tristate sym_toggle_tristate_value(struct symbol *sym)
363{
364 tristate oldval, newval;
365
366 oldval = newval = sym_get_tristate_value(sym);
367 do {
368 switch (newval) {
369 case no:
370 newval = mod;
371 break;
372 case mod:
373 newval = yes;
374 break;
375 case yes:
376 newval = no;
377 break;
378 }
379 if (sym_set_tristate_value(sym, newval))
380 break;
381 } while (oldval != newval);
382 return newval;
383}
384
385bool sym_string_valid(struct symbol *sym, const char *str)
386{
387 char ch;
388
389 switch (sym->type) {
390 case S_STRING:
391 return true;
392 case S_INT:
393 ch = *str++;
394 if (ch == '-')
395 ch = *str++;
396 if (!isdigit(ch))
397 return false;
398 if (ch == '0' && *str != 0)
399 return false;
400 while ((ch = *str++)) {
401 if (!isdigit(ch))
402 return false;
403 }
404 return true;
405 case S_HEX:
406 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
407 str += 2;
408 ch = *str++;
409 do {
410 if (!isxdigit(ch))
411 return false;
412 } while ((ch = *str++));
413 return true;
414 case S_BOOLEAN:
415 case S_TRISTATE:
416 switch (str[0]) {
417 case 'y':
418 case 'Y':
419 return sym_tristate_within_range(sym, yes);
420 case 'm':
421 case 'M':
422 return sym_tristate_within_range(sym, mod);
423 case 'n':
424 case 'N':
425 return sym_tristate_within_range(sym, no);
426 }
427 return false;
428 default:
429 return false;
430 }
431}
432
433bool sym_set_string_value(struct symbol *sym, const char *newval)
434{
435 const char *oldval;
436 char *val;
437 int size;
438
439 switch (sym->type) {
440 case S_BOOLEAN:
441 case S_TRISTATE:
442 switch (newval[0]) {
443 case 'y':
444 case 'Y':
445 return sym_set_tristate_value(sym, yes);
446 case 'm':
447 case 'M':
448 return sym_set_tristate_value(sym, mod);
449 case 'n':
450 case 'N':
451 return sym_set_tristate_value(sym, no);
452 }
453 return false;
454 default:
455 ;
456 }
457
458 if (!sym_string_valid(sym, newval))
459 return false;
460
461 if (sym->flags & SYMBOL_NEW) {
462 sym->flags &= ~SYMBOL_NEW;
463 sym->flags |= SYMBOL_CHANGED;
464 }
465
466 oldval = S_VAL(sym->def);
467 size = strlen(newval) + 1;
468 if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
469 size += 2;
470 S_VAL(sym->def) = val = malloc(size);
471 *val++ = '0';
472 *val++ = 'x';
473 } else if (!oldval || strcmp(oldval, newval))
474 S_VAL(sym->def) = val = malloc(size);
475 else
476 return true;
477
478 strcpy(val, newval);
479 free((void *)oldval);
480 sym_clear_all_valid();
481
482 return true;
483}
484
485const char *sym_get_string_value(struct symbol *sym)
486{
487 tristate val;
488
489 switch (sym->type) {
490 case S_BOOLEAN:
491 case S_TRISTATE:
492 val = sym_get_tristate_value(sym);
493 switch (val) {
494 case no:
495 return "n";
496 case mod:
497 return "m";
498 case yes:
499 return "y";
500 }
501 break;
502 default:
503 ;
504 }
505 return (const char *)S_VAL(sym->curr);
506}
507
508bool sym_is_changable(struct symbol *sym)
509{
510 if (sym->visible == no)
511 return false;
512 /* at least 'n' and 'y'/'m' is selectable */
513 if (sym_is_optional(sym))
514 return true;
515 /* no 'n', so 'y' and 'm' must be selectable */
516 if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes)
517 return true;
518 return false;
519}
520
521struct symbol *sym_lookup(const char *name, int isconst)
522{
523 struct symbol *symbol;
524 const char *ptr;
525 char *new_name;
526 int hash = 0;
527
528 //printf("lookup: %s -> ", name);
529 if (name) {
530 if (name[0] && !name[1]) {
531 switch (name[0]) {
532 case 'y': return &symbol_yes;
533 case 'm': return &symbol_mod;
534 case 'n': return &symbol_no;
535 }
536 }
537 for (ptr = name; *ptr; ptr++)
538 hash += *ptr;
539 hash &= 0xff;
540
541 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
542 if (!strcmp(symbol->name, name)) {
543 if ((isconst && symbol->flags & SYMBOL_CONST) ||
544 (!isconst && !(symbol->flags & SYMBOL_CONST))) {
545 //printf("h:%p\n", symbol);
546 return symbol;
547 }
548 }
549 }
550 new_name = strdup(name);
551 } else {
552 new_name = NULL;
553 hash = 256;
554 }
555
556 symbol = malloc(sizeof(*symbol));
557 memset(symbol, 0, sizeof(*symbol));
558 symbol->name = new_name;
559 symbol->type = S_UNKNOWN;
560 symbol->flags = SYMBOL_NEW;
561 if (isconst)
562 symbol->flags |= SYMBOL_CONST;
563
564 symbol->next = symbol_hash[hash];
565 symbol_hash[hash] = symbol;
566
567 //printf("n:%p\n", symbol);
568 return symbol;
569}
570
571struct symbol *sym_find(const char *name)
572{
573 struct symbol *symbol = NULL;
574 const char *ptr;
575 int hash = 0;
576
577 if (!name)
578 return NULL;
579
580 if (name[0] && !name[1]) {
581 switch (name[0]) {
582 case 'y': return &symbol_yes;
583 case 'm': return &symbol_mod;
584 case 'n': return &symbol_no;
585 }
586 }
587 for (ptr = name; *ptr; ptr++)
588 hash += *ptr;
589 hash &= 0xff;
590
591 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
592 if (!strcmp(symbol->name, name) &&
593 !(symbol->flags & SYMBOL_CONST))
594 break;
595 }
596
597 return symbol;
598}
599
600const char *prop_get_type_name(enum prop_type type)
601{
602 switch (type) {
603 case P_PROMPT:
604 return "prompt";
605 case P_COMMENT:
606 return "comment";
607 case P_MENU:
608 return "menu";
609 case P_ROOTMENU:
610 return "rootmenu";
611 case P_DEFAULT:
612 return "default";
613 case P_CHOICE:
614 return "choice";
615 default:
616 return "unknown";
617 }
618}