usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / config / symbol.c
blob94dc59ff9a8ba714a6e43062e8c8ac317a662af4
1 /*
2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
4 */
6 #include <ctype.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/utsname.h>
11 #define LKC_DIRECT_LINK
12 #include "lkc.h"
14 struct 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,
32 int sym_change_count;
33 struct symbol *modules_sym;
35 void sym_add_default(struct symbol *sym, const char *def)
37 struct property *prop = create_prop(P_DEFAULT);
38 struct property **propp;
40 prop->sym = sym;
41 prop->def = sym_lookup(def, 1);
43 /* append property to the prop list of symbol */
44 if (prop->sym) {
45 for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
47 *propp = prop;
51 void sym_init(void)
53 struct symbol *sym;
54 struct utsname uts;
55 char *p;
56 static bool inited = false;
58 if (inited)
59 return;
60 inited = true;
62 uname(&uts);
65 sym = sym_lookup("VERSION", 0);
66 sym->type = S_STRING;
67 sym->flags |= SYMBOL_AUTO;
68 p = getenv("VERSION");
69 if (p)
70 sym_add_default(sym, p);
73 sym = sym_lookup("TARGET_ARCH", 0);
74 sym->type = S_STRING;
75 sym->flags |= SYMBOL_AUTO;
76 p = getenv("TARGET_ARCH");
77 if (p)
78 sym_add_default(sym, p);
81 int sym_get_type(struct symbol *sym)
83 int type = sym->type;
84 if (type == S_TRISTATE) {
85 if (sym_is_choice_value(sym) && sym->visible == yes)
86 type = S_BOOLEAN;
87 else {
88 sym_calc_value(modules_sym);
89 if (S_TRI(modules_sym->curr) == no)
90 type = S_BOOLEAN;
93 return type;
96 const char *sym_type_name(int type)
98 switch (type) {
99 case S_BOOLEAN:
100 return "boolean";
101 case S_TRISTATE:
102 return "tristate";
103 case S_INT:
104 return "integer";
105 case S_HEX:
106 return "hex";
107 case S_STRING:
108 return "string";
109 case S_UNKNOWN:
110 return "unknown";
112 return "???";
115 struct property *sym_get_choice_prop(struct symbol *sym)
117 struct property *prop;
119 for_all_choices(sym, prop)
120 return prop;
121 return NULL;
124 struct property *sym_get_default_prop(struct symbol *sym)
126 struct property *prop;
127 tristate visible;
129 for_all_defaults(sym, prop) {
130 visible = E_CALC(prop->visible);
131 if (visible != no)
132 return prop;
134 return NULL;
137 void sym_calc_visibility(struct symbol *sym)
139 struct property *prop;
140 tristate visible, oldvisible;
142 /* any prompt visible? */
143 oldvisible = sym->visible;
144 visible = no;
145 for_all_prompts(sym, prop)
146 visible = E_OR(visible, E_CALC(prop->visible));
147 if (oldvisible != visible) {
148 sym->visible = visible;
149 sym->flags |= SYMBOL_CHANGED;
153 void sym_calc_value(struct symbol *sym)
155 struct symbol_value newval, oldval;
156 struct property *prop, *def_prop;
157 struct symbol *def_sym;
158 struct expr *e;
160 if (sym->flags & SYMBOL_VALID)
161 return;
163 oldval = sym->curr;
165 switch (sym->type) {
166 case S_INT:
167 case S_HEX:
168 case S_STRING:
169 newval = symbol_empty.curr;
170 break;
171 case S_BOOLEAN:
172 case S_TRISTATE:
173 newval = symbol_no.curr;
174 break;
175 default:
176 S_VAL(newval) = sym->name;
177 S_TRI(newval) = no;
178 if (sym->flags & SYMBOL_CONST) {
179 goto out;
181 //newval = symbol_empty.curr;
182 // generate warning somewhere here later
183 //S_TRI(newval) = yes;
184 goto out;
186 sym->flags |= SYMBOL_VALID;
187 if (!sym_is_choice_value(sym))
188 sym->flags &= ~SYMBOL_WRITE;
190 sym_calc_visibility(sym);
192 /* set default if recursively called */
193 sym->curr = newval;
195 if (sym->visible != no) {
196 sym->flags |= SYMBOL_WRITE;
197 if (!sym_has_value(sym)) {
198 if (!sym_is_choice(sym)) {
199 prop = sym_get_default_prop(sym);
200 if (prop) {
201 sym_calc_value(prop->def);
202 newval = prop->def->curr;
205 } else
206 newval = sym->def;
208 S_TRI(newval) = E_AND(S_TRI(newval), sym->visible);
209 /* if the symbol is visible and not optionial,
210 * possibly ignore old user choice. */
211 if (!sym_is_optional(sym) && S_TRI(newval) == no)
212 S_TRI(newval) = sym->visible;
213 if (sym_is_choice_value(sym) && sym->visible == yes) {
214 prop = sym_get_choice_prop(sym);
215 S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no;
217 } else {
218 prop = sym_get_default_prop(sym);
219 if (prop) {
220 sym->flags |= SYMBOL_WRITE;
221 sym_calc_value(prop->def);
222 newval = prop->def->curr;
226 switch (sym_get_type(sym)) {
227 case S_TRISTATE:
228 if (S_TRI(newval) != mod)
229 break;
230 sym_calc_value(modules_sym);
231 if (S_TRI(modules_sym->curr) == no)
232 S_TRI(newval) = yes;
233 break;
234 case S_BOOLEAN:
235 if (S_TRI(newval) == mod)
236 S_TRI(newval) = yes;
239 out:
240 sym->curr = newval;
242 if (sym_is_choice(sym) && S_TRI(newval) == yes) {
243 def_sym = S_VAL(sym->def);
244 if (def_sym) {
245 sym_calc_visibility(def_sym);
246 if (def_sym->visible == no)
247 def_sym = NULL;
249 if (!def_sym) {
250 for_all_defaults(sym, def_prop) {
251 if (E_CALC(def_prop->visible) == no)
252 continue;
253 sym_calc_visibility(def_prop->def);
254 if (def_prop->def->visible != no) {
255 def_sym = def_prop->def;
256 break;
261 if (!def_sym) {
262 prop = sym_get_choice_prop(sym);
263 for (e = prop->dep; e; e = e->left.expr) {
264 sym_calc_visibility(e->right.sym);
265 if (e->right.sym->visible != no) {
266 def_sym = e->right.sym;
267 break;
272 S_VAL(newval) = def_sym;
275 if (memcmp(&oldval, &newval, sizeof(newval)))
276 sym->flags |= SYMBOL_CHANGED;
277 sym->curr = newval;
279 if (sym_is_choice(sym)) {
280 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
281 prop = sym_get_choice_prop(sym);
282 for (e = prop->dep; e; e = e->left.expr)
283 e->right.sym->flags |= flags;
287 void sym_clear_all_valid(void)
289 struct symbol *sym;
290 int i;
292 for_all_symbols(i, sym)
293 sym->flags &= ~SYMBOL_VALID;
294 sym_change_count++;
297 void sym_set_all_changed(void)
299 struct symbol *sym;
300 int i;
302 for_all_symbols(i, sym)
303 sym->flags |= SYMBOL_CHANGED;
306 bool sym_tristate_within_range(struct symbol *sym, tristate val)
308 int type = sym_get_type(sym);
310 if (sym->visible == no)
311 return false;
313 if (type != S_BOOLEAN && type != S_TRISTATE)
314 return false;
316 switch (val) {
317 case no:
318 if (sym_is_choice_value(sym) && sym->visible == yes)
319 return false;
320 return sym_is_optional(sym);
321 case mod:
322 if (sym_is_choice_value(sym) && sym->visible == yes)
323 return false;
324 return type == S_TRISTATE;
325 case yes:
326 return type == S_BOOLEAN || sym->visible == yes;
328 return false;
331 bool sym_set_tristate_value(struct symbol *sym, tristate val)
333 tristate oldval = sym_get_tristate_value(sym);
335 if (oldval != val && !sym_tristate_within_range(sym, val))
336 return false;
338 if (sym->flags & SYMBOL_NEW) {
339 sym->flags &= ~SYMBOL_NEW;
340 sym->flags |= SYMBOL_CHANGED;
342 if (sym_is_choice_value(sym) && val == yes) {
343 struct property *prop = sym_get_choice_prop(sym);
345 S_VAL(prop->def->def) = sym;
346 prop->def->flags &= ~SYMBOL_NEW;
349 S_TRI(sym->def) = val;
350 if (oldval != val) {
351 sym_clear_all_valid();
352 if (sym == modules_sym)
353 sym_set_all_changed();
356 return true;
359 tristate sym_toggle_tristate_value(struct symbol *sym)
361 tristate oldval, newval;
363 oldval = newval = sym_get_tristate_value(sym);
364 do {
365 switch (newval) {
366 case no:
367 newval = mod;
368 break;
369 case mod:
370 newval = yes;
371 break;
372 case yes:
373 newval = no;
374 break;
376 if (sym_set_tristate_value(sym, newval))
377 break;
378 } while (oldval != newval);
379 return newval;
382 bool sym_string_valid(struct symbol *sym, const char *str)
384 char ch;
386 switch (sym->type) {
387 case S_STRING:
388 return true;
389 case S_INT:
390 ch = *str++;
391 if (ch == '-')
392 ch = *str++;
393 if (!isdigit((int)ch))
394 return false;
395 if (ch == '0' && *str != 0)
396 return false;
397 while ((ch = *str++)) {
398 if (!isdigit((int)ch))
399 return false;
401 return true;
402 case S_HEX:
403 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
404 str += 2;
405 ch = *str++;
406 do {
407 if (!isxdigit((int)ch))
408 return false;
409 } while ((ch = *str++));
410 return true;
411 case S_BOOLEAN:
412 case S_TRISTATE:
413 switch (str[0]) {
414 case 'y':
415 case 'Y':
416 return sym_tristate_within_range(sym, yes);
417 case 'm':
418 case 'M':
419 return sym_tristate_within_range(sym, mod);
420 case 'n':
421 case 'N':
422 return sym_tristate_within_range(sym, no);
424 return false;
425 default:
426 return false;
430 bool sym_set_string_value(struct symbol *sym, const char *newval)
432 const char *oldval;
433 char *val;
434 int size;
436 switch (sym->type) {
437 case S_BOOLEAN:
438 case S_TRISTATE:
439 switch (newval[0]) {
440 case 'y':
441 case 'Y':
442 return sym_set_tristate_value(sym, yes);
443 case 'm':
444 case 'M':
445 return sym_set_tristate_value(sym, mod);
446 case 'n':
447 case 'N':
448 return sym_set_tristate_value(sym, no);
450 return false;
451 default:
455 if (!sym_string_valid(sym, newval))
456 return false;
458 if (sym->flags & SYMBOL_NEW) {
459 sym->flags &= ~SYMBOL_NEW;
460 sym->flags |= SYMBOL_CHANGED;
463 oldval = S_VAL(sym->def);
464 size = strlen(newval) + 1;
465 if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
466 size += 2;
467 S_VAL(sym->def) = val = malloc(size);
468 *val++ = '0';
469 *val++ = 'x';
470 } else if (!oldval || strcmp(oldval, newval))
471 S_VAL(sym->def) = val = malloc(size);
472 else
473 return true;
475 strcpy(val, newval);
476 free((void *)oldval);
477 sym_clear_all_valid();
479 return true;
482 const char *sym_get_string_value(struct symbol *sym)
484 tristate val;
486 switch (sym->type) {
487 case S_BOOLEAN:
488 case S_TRISTATE:
489 val = sym_get_tristate_value(sym);
490 switch (val) {
491 case no:
492 return "n";
493 case mod:
494 return "m";
495 case yes:
496 return "y";
498 break;
499 default:
502 return (const char *)S_VAL(sym->curr);
505 bool sym_is_changable(struct symbol *sym)
507 if (sym->visible == no)
508 return false;
509 /* at least 'n' and 'y'/'m' is selectable */
510 if (sym_is_optional(sym))
511 return true;
512 /* no 'n', so 'y' and 'm' must be selectable */
513 if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes)
514 return true;
515 return false;
518 struct symbol *sym_lookup(const char *name, int isconst)
520 struct symbol *symbol;
521 const char *ptr;
522 char *new_name;
523 int hash = 0;
525 //printf("lookup: %s -> ", name);
526 if (name) {
527 if (name[0] && !name[1]) {
528 switch (name[0]) {
529 case 'y': return &symbol_yes;
530 case 'm': return &symbol_mod;
531 case 'n': return &symbol_no;
534 for (ptr = name; *ptr; ptr++)
535 hash += *ptr;
536 hash &= 0xff;
538 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
539 if (!strcmp(symbol->name, name)) {
540 if ((isconst && symbol->flags & SYMBOL_CONST) ||
541 (!isconst && !(symbol->flags & SYMBOL_CONST))) {
542 //printf("h:%p\n", symbol);
543 return symbol;
547 new_name = strdup(name);
548 } else {
549 new_name = NULL;
550 hash = 256;
553 symbol = malloc(sizeof(*symbol));
554 memset(symbol, 0, sizeof(*symbol));
555 symbol->name = new_name;
556 symbol->type = S_UNKNOWN;
557 symbol->flags = SYMBOL_NEW;
558 if (isconst)
559 symbol->flags |= SYMBOL_CONST;
561 symbol->next = symbol_hash[hash];
562 symbol_hash[hash] = symbol;
564 //printf("n:%p\n", symbol);
565 return symbol;
568 struct symbol *sym_find(const char *name)
570 struct symbol *symbol = NULL;
571 const char *ptr;
572 int hash = 0;
574 if (!name)
575 return NULL;
577 if (name[0] && !name[1]) {
578 switch (name[0]) {
579 case 'y': return &symbol_yes;
580 case 'm': return &symbol_mod;
581 case 'n': return &symbol_no;
584 for (ptr = name; *ptr; ptr++)
585 hash += *ptr;
586 hash &= 0xff;
588 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
589 if (!strcmp(symbol->name, name) &&
590 !(symbol->flags & SYMBOL_CONST))
591 break;
594 return symbol;
597 const char *prop_get_type_name(enum prop_type type)
599 switch (type) {
600 case P_PROMPT:
601 return "prompt";
602 case P_COMMENT:
603 return "comment";
604 case P_MENU:
605 return "menu";
606 case P_ROOTMENU:
607 return "rootmenu";
608 case P_DEFAULT:
609 return "default";
610 case P_CHOICE:
611 return "choice";
612 default:
613 return "unknown";