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