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