root/trunk/freewrt/tools/config/symbol.c

Revision 3223, 15.6 kB (checked in by tg, 5 years ago)

implement "select !FOO", everything including cosmetics from me,
except rev_dep_inv+deselected stuff, which is from nbd@openwrt –
thanks

selected symbols are now shown as “-+-” (on) or “_ _” (off)

Line 
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 <stdbool.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/utsname.h>
11
12 #define LKC_DIRECT_LINK
13 #include "lkc.h"
14
15 extern int output_mode;
16
17 struct symbol symbol_yes = {
18         .name = "y",
19         .curr = { "y", yes },
20         .flags = SYMBOL_YES|SYMBOL_VALID,
21 }, symbol_mod = {
22         .name = "m",
23         .curr = { "m", mod },
24         .flags = SYMBOL_MOD|SYMBOL_VALID,
25 }, symbol_no = {
26         .name = "n",
27         .curr = { "n", no },
28         .flags = SYMBOL_NO|SYMBOL_VALID,
29 }, symbol_empty = {
30         .name = "",
31         .curr = { "", no },
32         .flags = SYMBOL_VALID,
33 };
34
35 int sym_change_count;
36 struct symbol *modules_sym;
37 tristate modules_val;
38
39 void 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
46 void sym_init(void)
47 {
48         struct symbol *sym;
49         char *p;
50         static bool inited = false;
51
52         if (inited)
53                 return;
54         inited = true;
55
56         sym = sym_lookup("VERSION", 0);
57         sym->type = S_STRING;
58         sym->flags |= SYMBOL_AUTO;
59         p = getenv("VERSION");
60         if (p)
61                 sym_add_default(sym, p);
62
63         sym = sym_lookup("TARGET_ARCH", 0);
64         sym->type = S_STRING;
65         sym->flags |= SYMBOL_AUTO;
66         p = getenv("TARGET_ARCH");
67         if (p)
68                 sym_add_default(sym, p);
69
70 }
71
72 enum symbol_type sym_get_type(struct symbol *sym)
73 {
74         enum symbol_type type = sym->type;
75
76         if (type == S_TRISTATE) {
77                 if (sym_is_choice_value(sym) && sym->visible == yes)
78                         type = S_BOOLEAN;
79                 else if (modules_val == no)
80                         type = S_BOOLEAN;
81         }
82         return type;
83 }
84
85 const char *sym_type_name(enum symbol_type type)
86 {
87         switch (type) {
88         case S_BOOLEAN:
89                 return "boolean";
90         case S_TRISTATE:
91                 return "tristate";
92         case S_INT:
93                 return "integer";
94         case S_HEX:
95                 return "hex";
96         case S_STRING:
97                 return "string";
98         case S_UNKNOWN:
99                 return "unknown";
100         case S_OTHER:
101                 break;
102         }
103         return "???";
104 }
105
106 struct property *sym_get_choice_prop(struct symbol *sym)
107 {
108         struct property *prop;
109
110         for_all_choices(sym, prop)
111                 return prop;
112         return NULL;
113 }
114
115 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 || output_mode)
122                         return prop;
123         }
124         return NULL;
125 }
126
127 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 void sym_calc_visibility(struct symbol *sym)
140 {
141         struct property *prop;
142         tristate tri;
143         bool deselected = false;
144
145         /* any prompt visible? */
146         tri = no;
147         for_all_prompts(sym, prop) {
148                 prop->visible.tri = expr_calc_value(prop->visible.expr);
149                 tri = E_OR(tri, prop->visible.tri);
150         }
151         if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
152                 tri = yes;
153         if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) {
154                 tri = no;
155                 deselected = true;
156         }
157         if (sym->visible != tri) {
158                 sym->visible = tri;
159                 sym_set_changed(sym);
160         }
161         if (sym_is_choice_value(sym) || deselected)
162                 return;
163         tri = no;
164         if (sym->rev_dep.expr)
165                 tri = expr_calc_value(sym->rev_dep.expr);
166         if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
167                 tri = yes;
168         if (sym->rev_dep.tri != tri) {
169                 sym->rev_dep.tri = tri;
170                 sym_set_changed(sym);
171         }
172 }
173
174 static struct symbol *sym_calc_choice(struct symbol *sym)
175 {
176         struct symbol *def_sym;
177         struct property *prop;
178         struct expr *e;
179
180         /* is the user choice visible? */
181         def_sym = sym->user.val;
182         if (def_sym) {
183                 sym_calc_visibility(def_sym);
184                 if (def_sym->visible != no)
185                         return def_sym;
186         }
187
188         /* any of the defaults visible? */
189         for_all_defaults(sym, prop) {
190                 prop->visible.tri = expr_calc_value(prop->visible.expr);
191                 if (prop->visible.tri == no)
192                         continue;
193                 def_sym = prop_get_symbol(prop);
194                 sym_calc_visibility(def_sym);
195                 if (def_sym->visible != no)
196                         return def_sym;
197         }
198
199         /* just get the first visible value */
200         prop = sym_get_choice_prop(sym);
201         for (e = prop->expr; e; e = e->left.expr) {
202                 def_sym = e->right.sym;
203                 sym_calc_visibility(def_sym);
204                 if (def_sym->visible != no)
205                         return def_sym;
206         }
207
208         /* no choice? reset tristate value */
209         sym->curr.tri = no;
210         return NULL;
211 }
212
213 void sym_calc_value(struct symbol *sym)
214 {
215         struct symbol_value newval, oldval;
216         struct property *prop;
217         struct expr *e;
218
219         if (!sym)
220                 return;
221
222         if (sym->flags & SYMBOL_VALID)
223                 return;
224         sym->flags |= SYMBOL_VALID;
225
226         oldval = sym->curr;
227
228         switch (sym->type) {
229         case S_INT:
230         case S_HEX:
231         case S_STRING:
232                 newval = symbol_empty.curr;
233                 break;
234         case S_BOOLEAN:
235         case S_TRISTATE:
236                 newval = symbol_no.curr;
237                 break;
238         default:
239                 sym->curr.val = sym->name;
240                 sym->curr.tri = no;
241                 return;
242         }
243         if (!sym_is_choice_value(sym))
244                 sym->flags &= ~SYMBOL_WRITE;
245
246         sym_calc_visibility(sym);
247
248         /* set default if recursively called */
249         sym->curr = newval;
250
251         switch (sym_get_type(sym)) {
252         case S_BOOLEAN:
253         case S_TRISTATE:
254                 if (sym_is_choice_value(sym) && sym->visible == yes) {
255                         prop = sym_get_choice_prop(sym);
256                         newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
257                 } else if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) {
258                         newval.tri = no;
259                 } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
260                         sym->flags |= SYMBOL_WRITE;
261                         if (sym_has_value(sym))
262                                 newval.tri = sym->user.tri;
263                         else if (!sym_is_choice(sym)) {
264                                 prop = sym_get_default_prop(sym);
265                                 if (prop)
266                                         newval.tri = expr_calc_value(prop->expr);
267                         }
268                         newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
269                 } else if (!sym_is_choice(sym)) {
270                         prop = sym_get_default_prop(sym);
271                         if (prop) {
272                                 sym->flags |= SYMBOL_WRITE;
273                                 newval.tri = expr_calc_value(prop->expr);
274                         }
275                 }
276                 if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
277                         newval.tri = yes;
278                 break;
279         case S_STRING:
280         case S_HEX:
281         case S_INT:
282                 if (sym->visible != no) {
283                         sym->flags |= SYMBOL_WRITE;
284                         if (sym_has_value(sym)) {
285                                 newval.val = sym->user.val;
286                                 break;
287                         }
288                 }
289                 prop = sym_get_default_prop(sym);
290                 if (prop) {
291                         struct symbol *ds = prop_get_symbol(prop);
292                         if (ds) {
293                                 sym->flags |= SYMBOL_WRITE;
294                                 sym_calc_value(ds);
295                                 newval.val = ds->curr.val;
296                         }
297                 }
298                 break;
299         default:
300                 ;
301         }
302
303         sym->curr = newval;
304         if (sym_is_choice(sym) && newval.tri == yes)
305                 sym->curr.val = sym_calc_choice(sym);
306
307         if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
308                 sym_set_changed(sym);
309         if (modules_sym == sym)
310                 modules_val = modules_sym->curr.tri;
311
312         if (sym_is_choice(sym)) {
313                 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
314                 prop = sym_get_choice_prop(sym);
315                 for (e = prop->expr; e; e = e->left.expr) {
316                         e->right.sym->flags |= flags;
317                         if (flags & SYMBOL_CHANGED)
318                                 sym_set_changed(e->right.sym);
319                 }
320         }
321 }
322
323 void sym_clear_all_valid(void)
324 {
325         struct symbol *sym;
326         int i;
327
328         for_all_symbols(i, sym)
329                 sym->flags &= ~SYMBOL_VALID;
330         sym_change_count++;
331         if (modules_sym)
332                 sym_calc_value(modules_sym);
333 }
334
335 void sym_set_changed(struct symbol *sym)
336 {
337         struct property *prop;
338
339         sym->flags |= SYMBOL_CHANGED;
340         for (prop = sym->prop; prop; prop = prop->next) {
341                 if (prop->menu)
342                         prop->menu->flags |= MENU_CHANGED;
343         }
344 }
345
346 void sym_set_all_changed(void)
347 {
348         struct symbol *sym;
349         int i;
350
351         for_all_symbols(i, sym)
352                 sym_set_changed(sym);
353 }
354
355 bool sym_tristate_within_range(struct symbol *sym, tristate val)
356 {
357         int type = sym_get_type(sym);
358
359         if (sym->visible == no)
360                 return false;
361
362         if (type != S_BOOLEAN && type != S_TRISTATE)
363                 return false;
364
365         if (type == S_BOOLEAN && val == mod)
366                 return false;
367         if (sym->visible <= sym->rev_dep.tri)
368                 return false;
369         if (sym_is_choice_value(sym) && sym->visible == yes)
370                 return val == yes;
371         return val >= sym->rev_dep.tri && val <= sym->visible;
372 }
373
374 bool sym_set_tristate_value(struct symbol *sym, tristate val)
375 {
376         tristate oldval = sym_get_tristate_value(sym);
377
378         if (oldval != val && !sym_tristate_within_range(sym, val))
379                 return false;
380
381         if (sym->flags & SYMBOL_NEW) {
382                 sym->flags &= ~SYMBOL_NEW;
383                 sym_set_changed(sym);
384         }
385         if (sym_is_choice_value(sym) && val == yes) {
386                 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
387
388                 cs->user.val = sym;
389                 cs->flags &= ~SYMBOL_NEW;
390         }
391
392         sym->user.tri = val;
393         if (oldval != val) {
394                 sym_clear_all_valid();
395                 if (sym == modules_sym)
396                         sym_set_all_changed();
397         }
398
399         return true;
400 }
401
402 tristate sym_toggle_tristate_value(struct symbol *sym)
403 {
404         tristate oldval, newval;
405
406         oldval = newval = sym_get_tristate_value(sym);
407         do {
408                 switch (newval) {
409                 case no:
410                         newval = mod;
411                         break;
412                 case mod:
413                         newval = yes;
414                         break;
415                 case yes:
416                         newval = no;
417                         break;
418                 }
419                 if (sym_set_tristate_value(sym, newval))
420                         break;
421         } while (oldval != newval);
422         return newval;
423 }
424
425 bool sym_string_valid(struct symbol *sym, const char *str)
426 {
427         char ch;
428
429         switch (sym->type) {
430         case S_STRING:
431                 return true;
432         case S_INT:
433                 ch = *str++;
434                 if (ch == '-')
435                         ch = *str++;
436                 if (!isdigit(ch))
437                         return false;
438                 if (ch == '0' && *str != 0)
439                         return false;
440                 while ((ch = *str++)) {
441                         if (!isdigit(ch))
442                                 return false;
443                 }
444                 return true;
445         case S_HEX:
446                 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
447                         str += 2;
448                 ch = *str++;
449                 do {
450                         if (!isxdigit(ch))
451                                 return false;
452                 } while ((ch = *str++));
453                 return true;
454         case S_BOOLEAN:
455         case S_TRISTATE:
456                 switch (str[0]) {
457                 case 'y': case 'Y':
458                 case 'm': case 'M':
459                 case 'n': case 'N':
460                         return true;
461                 }
462                 return false;
463         default:
464                 return false;
465         }
466 }
467
468 bool sym_string_within_range(struct symbol *sym, const char *str)
469 {
470         struct property *prop;
471         int val;
472
473         switch (sym->type) {
474         case S_STRING:
475                 return sym_string_valid(sym, str);
476         case S_INT:
477                 if (!sym_string_valid(sym, str))
478                         return false;
479                 prop = sym_get_range_prop(sym);
480                 if (!prop)
481                         return true;
482                 val = strtol(str, NULL, 10);
483                 return val >= strtol(prop->expr->left.sym->name, NULL, 10) &&
484                        val <= strtol(prop->expr->right.sym->name, NULL, 10);
485         case S_HEX:
486                 if (!sym_string_valid(sym, str))
487                         return false;
488                 prop = sym_get_range_prop(sym);
489                 if (!prop)
490                         return true;
491                 val = strtol(str, NULL, 16);
492                 return val >= strtol(prop->expr->left.sym->name, NULL, 16) &&
493                        val <= strtol(prop->expr->right.sym->name, NULL, 16);
494         case S_BOOLEAN:
495         case S_TRISTATE:
496                 switch (str[0]) {
497                 case 'y': case 'Y':
498                         return sym_tristate_within_range(sym, yes);
499                 case 'm': case 'M':
500                         return sym_tristate_within_range(sym, mod);
501                 case 'n': case 'N':
502                         return sym_tristate_within_range(sym, no);
503                 }
504                 return false;
505         default:
506                 return false;
507         }
508 }
509
510 bool sym_set_string_value(struct symbol *sym, const char *newval)
511 {
512         const char *oldval;
513         char *val;
514         int size;
515
516         switch (sym->type) {
517         case S_BOOLEAN:
518         case S_TRISTATE:
519                 switch (newval[0]) {
520                 case 'y': case 'Y':
521                         return sym_set_tristate_value(sym, yes);
522                 case 'm': case 'M':
523                         return sym_set_tristate_value(sym, mod);
524                 case 'n': case 'N':
525                         return sym_set_tristate_value(sym, no);
526                 }
527                 return false;
528         default:
529                 ;
530         }
531
532         if (!sym_string_within_range(sym, newval))
533                 return false;
534
535         if (sym->flags & SYMBOL_NEW) {
536                 sym->flags &= ~SYMBOL_NEW;
537                 sym_set_changed(sym);
538         }
539
540         oldval = sym->user.val;
541         size = strlen(newval) + 1;
542         if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
543                 size += 2;
544                 sym->user.val = val = malloc(size);
545                 *val++ = '0';
546                 *val++ = 'x';
547         } else if (!oldval || strcmp(oldval, newval))
548                 sym->user.val = val = malloc(size);
549         else
550                 return true;
551
552         strcpy(val, newval);
553         free((void *)oldval);
554         sym_clear_all_valid();
555
556         return true;
557 }
558
559 const char *sym_get_string_value(struct symbol *sym)
560 {
561         tristate val;
562
563         switch (sym->type) {
564         case S_BOOLEAN:
565         case S_TRISTATE:
566                 val = sym_get_tristate_value(sym);
567                 switch (val) {
568                 case no:
569                         return "n";
570                 case mod:
571                         return "m";
572                 case yes:
573                         return "y";
574                 }
575                 break;
576         default:
577                 ;
578         }
579         return (const char *)sym->curr.val;
580 }
581
582 bool sym_is_changable(struct symbol *sym)
583 {
584         return sym->visible > sym->rev_dep.tri;
585 }
586
587 struct symbol *sym_lookup(const char *name, int isconst)
588 {
589         struct symbol *symbol;
590         const char *ptr;
591         char *new_name;
592         int hash = 0;
593
594         if (name) {
595                 if (name[0] && !name[1]) {
596                         switch (name[0]) {
597                         case 'y': return &symbol_yes;
598                         case 'm': return &symbol_mod;
599                         case 'n': return &symbol_no;
600                         }
601                 }
602                 for (ptr = name; *ptr; ptr++)
603                         hash += *ptr;
604                 hash &= 0xff;
605
606                 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
607                         if (!strcmp(symbol->name, name)) {
608                                 if ((isconst && symbol->flags & SYMBOL_CONST) ||
609                                     (!isconst && !(symbol->flags & SYMBOL_CONST)))
610                                         return symbol;
611                         }
612                 }
613                 new_name = strdup(name);
614         } else {
615                 new_name = NULL;
616                 hash = 256;
617         }
618
619         symbol = malloc(sizeof(*symbol));
620         memset(symbol, 0, sizeof(*symbol));
621         symbol->name = new_name;
622         symbol->type = S_UNKNOWN;
623         symbol->flags = SYMBOL_NEW;
624         if (isconst)
625                 symbol->flags |= SYMBOL_CONST;
626
627         symbol->next = symbol_hash[hash];
628         symbol_hash[hash] = symbol;
629
630         return symbol;
631 }
632
633 struct symbol *sym_find(const char *name)
634 {
635         struct symbol *symbol = NULL;
636         const char *ptr;
637         int hash = 0;
638
639         if (!name)
640                 return NULL;
641
642         if (name[0] && !name[1]) {
643                 switch (name[0]) {
644                 case 'y': return &symbol_yes;
645                 case 'm': return &symbol_mod;
646                 case 'n': return &symbol_no;
647                 }
648         }
649         for (ptr = name; *ptr; ptr++)
650                 hash += *ptr;
651         hash &= 0xff;
652
653         for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
654                 if (!strcmp(symbol->name, name) &&
655                     !(symbol->flags & SYMBOL_CONST))
656                                 break;
657         }
658
659         return symbol;
660 }
661
662 struct symbol *sym_check_deps(struct symbol *sym);
663
664 static struct symbol *sym_check_expr_deps(struct expr *e)
665 {
666         struct symbol *sym;
667
668         if (!e)
669                 return NULL;
670         switch (e->type) {
671         case E_OR:
672         case E_AND:
673                 sym = sym_check_expr_deps(e->left.expr);
674                 if (sym)
675                         return sym;
676                 return sym_check_expr_deps(e->right.expr);
677         case E_NOT:
678                 return sym_check_expr_deps(e->left.expr);
679         case E_EQUAL:
680         case E_UNEQUAL:
681                 sym = sym_check_deps(e->left.sym);
682                 if (sym)
683                         return sym;
684                 return sym_check_deps(e->right.sym);
685         case E_SYMBOL:
686                 return sym_check_deps(e->left.sym);
687         default:
688                 break;
689         }
690         printf("Oops! How to check %d?\n", e->type);
691         return NULL;
692 }
693
694 struct symbol *sym_check_deps(struct symbol *sym)
695 {
696         struct symbol *sym2;
697         struct property *prop;
698
699         if (sym->flags & SYMBOL_CHECK_DONE)
700                 return NULL;
701         if (sym->flags & SYMBOL_CHECK) {
702                 printf("Warning! Found recursive dependency: %s", sym->name);
703                 return sym;
704         }
705
706         sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
707         sym2 = sym_check_expr_deps(sym->rev_dep.expr);
708         if (sym2)
709                 goto out;
710
711         for (prop = sym->prop; prop; prop = prop->next) {
712                 if (prop->type == P_CHOICE || prop->type == P_SELECT || prop->type == P_SELECTNOT)
713                         continue;
714                 sym2 = sym_check_expr_deps(prop->visible.expr);
715                 if (sym2)
716                         goto out;
717                 if (prop->type != P_DEFAULT || sym_is_choice(sym))
718                         continue;
719                 sym2 = sym_check_expr_deps(prop->expr);
720                 if (sym2)
721                         goto out;
722         }
723 out:
724         if (sym2)
725                 printf(" %s", sym->name);
726         sym->flags &= ~SYMBOL_CHECK;
727         return sym2;
728 }
729
730 struct property *prop_alloc(enum prop_type type, struct symbol *sym)
731 {
732         struct property *prop;
733         struct property **propp;
734
735         prop = malloc(sizeof(*prop));
736         memset(prop, 0, sizeof(*prop));
737         prop->type = type;
738         prop->sym = sym;
739         prop->file = current_file;
740         prop->lineno = zconf_lineno();
741
742         /* append property to the prop list of symbol */
743         if (sym) {
744                 for (propp = &sym->prop; *propp; propp = &(*propp)->next)
745                         ;
746                 *propp = prop;
747         }
748
749         return prop;
750 }
751
752 struct symbol *prop_get_symbol(struct property *prop)
753 {
754         if (prop->expr && (prop->expr->type == E_SYMBOL ||
755                            prop->expr->type == E_CHOICE))
756                 return prop->expr->left.sym;
757         return NULL;
758 }
759
760 const char *prop_get_type_name(enum prop_type type)
761 {
762         switch (type) {
763         case P_PROMPT:
764                 return "prompt";
765         case P_COMMENT:
766                 return "comment";
767         case P_MENU:
768                 return "menu";
769         case P_DEFAULT:
770                 return "default";
771         case P_CHOICE:
772                 return "choice";
773         case P_SELECT:
774         case P_SELECTNOT:
775                 return "select";
776         case P_RANGE:
777                 return "range";
778         case P_UNKNOWN:
779                 break;
780         }
781         return "unknown";
782 }
Note: See TracBrowser for help on using the browser.