source: MondoRescue/branches/stable/mindi-busybox/scripts/config/symbol.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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