base/config/kconfig/symbol.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
00003  * Released under the terms of the GNU GPL v2.0.
00004  */
00005 
00006 #include <ctype.h>
00007 #include <stdlib.h>
00008 #include <string.h>
00009 #include <sys/utsname.h>
00010 
00011 #define LKC_DIRECT_LINK
00012 #include "lkc.h"
00013 
00014 struct symbol symbol_yes = {
00015     .name = "y",
00016     .curr = { "y", yes },
00017     .flags = SYMBOL_YES|SYMBOL_VALID,
00018 }, symbol_mod = {
00019     .name = "m",
00020     .curr = { "m", mod },
00021     .flags = SYMBOL_MOD|SYMBOL_VALID,
00022 }, symbol_no = {
00023     .name = "n",
00024     .curr = { "n", no },
00025     .flags = SYMBOL_NO|SYMBOL_VALID,
00026 }, symbol_empty = {
00027     .name = "",
00028     .curr = { "", no },
00029     .flags = SYMBOL_VALID,
00030 };
00031 
00032 int sym_change_count;
00033 struct symbol *modules_sym;
00034 
00035 void sym_add_default(struct symbol *sym, const char *def)
00036 {
00037     struct property *prop = prop_alloc(P_DEFAULT, sym);
00038 
00039     prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
00040 }
00041 
00042 void sym_init(void)
00043 {
00044     struct symbol *sym;
00045     struct utsname uts;
00046     char *p;
00047     static bool inited = false;
00048 
00049     if (inited)
00050         return;
00051     inited = true;
00052 
00053     uname(&uts);
00054 
00055     sym = sym_lookup("ARCH", 0);
00056     sym->type = S_STRING;
00057     sym->flags |= SYMBOL_AUTO;
00058     p = getenv("ARCH");
00059     if (p)
00060         sym_add_default(sym, p);
00061 
00062     sym = sym_lookup("KERNELRELEASE", 0);
00063     sym->type = S_STRING;
00064     sym->flags |= SYMBOL_AUTO;
00065     p = getenv("KERNELRELEASE");
00066     if (p)
00067         sym_add_default(sym, p);
00068 
00069     sym = sym_lookup("UNAME_RELEASE", 0);
00070     sym->type = S_STRING;
00071     sym->flags |= SYMBOL_AUTO;
00072     sym_add_default(sym, uts.release);
00073 }
00074 
00075 enum symbol_type sym_get_type(struct symbol *sym)
00076 {
00077     enum symbol_type type = sym->type;
00078 
00079     if (type == S_TRISTATE) {
00080         if (sym_is_choice_value(sym) && sym->visible == yes)
00081             type = S_BOOLEAN;
00082         else {
00083             sym_calc_value(modules_sym);
00084             if (modules_sym->curr.tri == no)
00085                 type = S_BOOLEAN;
00086         }
00087     }
00088     return type;
00089 }
00090 
00091 const char *sym_type_name(enum symbol_type type)
00092 {
00093     switch (type) {
00094     case S_BOOLEAN:
00095         return "boolean";
00096     case S_TRISTATE:
00097         return "tristate";
00098     case S_INT:
00099         return "integer";
00100     case S_HEX:
00101         return "hex";
00102     case S_STRING:
00103         return "string";
00104     case S_UNKNOWN:
00105         return "unknown";
00106     case S_OTHER:
00107         break;
00108     }
00109     return "???";
00110 }
00111 
00112 struct property *sym_get_choice_prop(struct symbol *sym)
00113 {
00114     struct property *prop;
00115 
00116     for_all_choices(sym, prop)
00117         return prop;
00118     return NULL;
00119 }
00120 
00121 struct property *sym_get_default_prop(struct symbol *sym)
00122 {
00123     struct property *prop;
00124 
00125     for_all_defaults(sym, prop) {
00126         prop->visible.tri = expr_calc_value(prop->visible.expr);
00127         if (prop->visible.tri != no)
00128             return prop;
00129     }
00130     return NULL;
00131 }
00132 
00133 struct property *sym_get_range_prop(struct symbol *sym)
00134 {
00135     struct property *prop;
00136 
00137     for_all_properties(sym, prop, P_RANGE) {
00138         prop->visible.tri = expr_calc_value(prop->visible.expr);
00139         if (prop->visible.tri != no)
00140             return prop;
00141     }
00142     return NULL;
00143 }
00144 
00145 static void sym_calc_visibility(struct symbol *sym)
00146 {
00147     struct property *prop;
00148     tristate tri;
00149 
00150     /* any prompt visible? */
00151     tri = no;
00152     for_all_prompts(sym, prop) {
00153         prop->visible.tri = expr_calc_value(prop->visible.expr);
00154         tri = E_OR(tri, prop->visible.tri);
00155     }
00156     if (sym->visible != tri) {
00157         sym->visible = tri;
00158         sym_set_changed(sym);
00159     }
00160     if (sym_is_choice_value(sym))
00161         return;
00162     tri = no;
00163     if (sym->rev_dep.expr)
00164         tri = expr_calc_value(sym->rev_dep.expr);
00165     if (sym->rev_dep.tri != tri) {
00166         sym->rev_dep.tri = tri;
00167         sym_set_changed(sym);
00168     }
00169 }
00170 
00171 static struct symbol *sym_calc_choice(struct symbol *sym)
00172 {
00173     struct symbol *def_sym;
00174     struct property *prop;
00175     struct expr *e;
00176 
00177     /* is the user choice visible? */
00178     def_sym = sym->user.val;
00179     if (def_sym) {
00180         sym_calc_visibility(def_sym);
00181         if (def_sym->visible != no)
00182             return def_sym;
00183     }
00184 
00185     /* any of the defaults visible? */
00186     for_all_defaults(sym, prop) {
00187         prop->visible.tri = expr_calc_value(prop->visible.expr);
00188         if (prop->visible.tri == no)
00189             continue;
00190         def_sym = prop_get_symbol(prop);
00191         sym_calc_visibility(def_sym);
00192         if (def_sym->visible != no)
00193             return def_sym;
00194     }
00195 
00196     /* just get the first visible value */
00197     prop = sym_get_choice_prop(sym);
00198     for (e = prop->expr; e; e = e->left.expr) {
00199         def_sym = e->right.sym;
00200         sym_calc_visibility(def_sym);
00201         if (def_sym->visible != no)
00202             return def_sym;
00203     }
00204 
00205     /* no choice? reset tristate value */
00206     sym->curr.tri = no;
00207     return NULL;
00208 }
00209 
00210 void sym_calc_value(struct symbol *sym)
00211 {
00212     struct symbol_value newval, oldval;
00213     struct property *prop;
00214     struct expr *e;
00215 
00216     if (!sym)
00217         return;
00218 
00219     if (sym->flags & SYMBOL_VALID)
00220         return;
00221     sym->flags |= SYMBOL_VALID;
00222 
00223     oldval = sym->curr;
00224 
00225     switch (sym->type) {
00226     case S_INT:
00227     case S_HEX:
00228     case S_STRING:
00229         newval = symbol_empty.curr;
00230         break;
00231     case S_BOOLEAN:
00232     case S_TRISTATE:
00233         newval = symbol_no.curr;
00234         break;
00235     default:
00236         sym->curr.val = sym->name;
00237         sym->curr.tri = no;
00238         return;
00239     }
00240     if (!sym_is_choice_value(sym))
00241         sym->flags &= ~SYMBOL_WRITE;
00242 
00243     sym_calc_visibility(sym);
00244 
00245     /* set default if recursively called */
00246     sym->curr = newval;
00247 
00248     switch (sym_get_type(sym)) {
00249     case S_BOOLEAN:
00250     case S_TRISTATE:
00251         if (sym_is_choice_value(sym) && sym->visible == yes) {
00252             prop = sym_get_choice_prop(sym);
00253             newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
00254         } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
00255             sym->flags |= SYMBOL_WRITE;
00256             if (sym_has_value(sym))
00257                 newval.tri = sym->user.tri;
00258             else if (!sym_is_choice(sym)) {
00259                 prop = sym_get_default_prop(sym);
00260                 if (prop)
00261                     newval.tri = expr_calc_value(prop->expr);
00262             }
00263             newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
00264         } else if (!sym_is_choice(sym)) {
00265             prop = sym_get_default_prop(sym);
00266             if (prop) {
00267                 sym->flags |= SYMBOL_WRITE;
00268                 newval.tri = expr_calc_value(prop->expr);
00269             }
00270         }
00271         if (sym_get_type(sym) == S_BOOLEAN) {
00272             if (newval.tri == mod)
00273                 newval.tri = yes;
00274             if (sym->visible == mod)
00275                 sym->visible = yes;
00276             if (sym->rev_dep.tri == mod)
00277                 sym->rev_dep.tri = yes;
00278         }
00279         break;
00280     case S_STRING:
00281     case S_HEX:
00282     case S_INT:
00283         if (sym->visible != no) {
00284             sym->flags |= SYMBOL_WRITE;
00285             if (sym_has_value(sym)) {
00286                 newval.val = sym->user.val;
00287                 break;
00288             }
00289         }
00290         prop = sym_get_default_prop(sym);
00291         if (prop) {
00292             struct symbol *ds = prop_get_symbol(prop);
00293             if (ds) {
00294                 sym->flags |= SYMBOL_WRITE;
00295                 sym_calc_value(ds);
00296                 newval.val = ds->curr.val;
00297             }
00298         }
00299         break;
00300     default:
00301         ;
00302     }
00303 
00304     sym->curr = newval;
00305     if (sym_is_choice(sym) && newval.tri == yes)
00306         sym->curr.val = sym_calc_choice(sym);
00307 
00308     if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
00309         sym_set_changed(sym);
00310 
00311     if (sym_is_choice(sym)) {
00312         int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
00313         prop = sym_get_choice_prop(sym);
00314         for (e = prop->expr; e; e = e->left.expr) {
00315             e->right.sym->flags |= flags;
00316             if (flags & SYMBOL_CHANGED)
00317                 sym_set_changed(e->right.sym);
00318         }
00319     }
00320 }
00321 
00322 void sym_clear_all_valid(void)
00323 {
00324     struct symbol *sym;
00325     int i;
00326 
00327     for_all_symbols(i, sym)
00328         sym->flags &= ~SYMBOL_VALID;
00329     sym_change_count++;
00330 }
00331 
00332 void sym_set_changed(struct symbol *sym)
00333 {
00334     struct property *prop;
00335 
00336     sym->flags |= SYMBOL_CHANGED;
00337     for (prop = sym->prop; prop; prop = prop->next) {
00338         if (prop->menu)
00339             prop->menu->flags |= MENU_CHANGED;
00340     }
00341 }
00342 
00343 void sym_set_all_changed(void)
00344 {
00345     struct symbol *sym;
00346     int i;
00347 
00348     for_all_symbols(i, sym)
00349         sym_set_changed(sym);
00350 }
00351 
00352 bool sym_tristate_within_range(struct symbol *sym, tristate val)
00353 {
00354     int type = sym_get_type(sym);
00355 
00356     if (sym->visible == no)
00357         return false;
00358 
00359     if (type != S_BOOLEAN && type != S_TRISTATE)
00360         return false;
00361 
00362     if (type == S_BOOLEAN && val == mod)
00363         return false;
00364     if (sym->visible <= sym->rev_dep.tri)
00365         return false;
00366     if (sym_is_choice_value(sym) && sym->visible == yes)
00367         return val == yes;
00368     return val >= sym->rev_dep.tri && val <= sym->visible;
00369 }
00370 
00371 bool sym_set_tristate_value(struct symbol *sym, tristate val)
00372 {
00373     tristate oldval = sym_get_tristate_value(sym);
00374 
00375     if (oldval != val && !sym_tristate_within_range(sym, val))
00376         return false;
00377 
00378     if (sym->flags & SYMBOL_NEW) {
00379         sym->flags &= ~SYMBOL_NEW;
00380         sym_set_changed(sym);
00381     }
00382     if (sym_is_choice_value(sym) && val == yes) {
00383         struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
00384 
00385         cs->user.val = sym;
00386         cs->flags &= ~SYMBOL_NEW;
00387     }
00388 
00389     sym->user.tri = val;
00390     if (oldval != val) {
00391         sym_clear_all_valid();
00392         if (sym == modules_sym)
00393             sym_set_all_changed();
00394     }
00395 
00396     return true;
00397 }
00398 
00399 tristate sym_toggle_tristate_value(struct symbol *sym)
00400 {
00401     tristate oldval, newval;
00402 
00403     oldval = newval = sym_get_tristate_value(sym);
00404     do {
00405         switch (newval) {
00406         case no:
00407             newval = mod;
00408             break;
00409         case mod:
00410             newval = yes;
00411             break;
00412         case yes:
00413             newval = no;
00414             break;
00415         }
00416         if (sym_set_tristate_value(sym, newval))
00417             break;
00418     } while (oldval != newval);
00419     return newval;
00420 }
00421 
00422 bool sym_string_valid(struct symbol *sym, const char *str)
00423 {
00424     char ch;
00425 
00426     switch (sym->type) {
00427     case S_STRING:
00428         return true;
00429     case S_INT:
00430         ch = *str++;
00431         if (ch == '-')
00432             ch = *str++;
00433         if (!isdigit(ch))
00434             return false;
00435         if (ch == '0' && *str != 0)
00436             return false;
00437         while ((ch = *str++)) {
00438             if (!isdigit(ch))
00439                 return false;
00440         }
00441         return true;
00442     case S_HEX:
00443         if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
00444             str += 2;
00445         ch = *str++;
00446         do {
00447             if (!isxdigit(ch))
00448                 return false;
00449         } while ((ch = *str++));
00450         return true;
00451     case S_BOOLEAN:
00452     case S_TRISTATE:
00453         switch (str[0]) {
00454         case 'y': case 'Y':
00455         case 'm': case 'M':
00456         case 'n': case 'N':
00457             return true;
00458         }
00459         return false;
00460     default:
00461         return false;
00462     }
00463 }
00464 
00465 bool sym_string_within_range(struct symbol *sym, const char *str)
00466 {
00467     struct property *prop;
00468     int val;
00469 
00470     switch (sym->type) {
00471     case S_STRING:
00472         return sym_string_valid(sym, str);
00473     case S_INT:
00474         if (!sym_string_valid(sym, str))
00475             return false;
00476         prop = sym_get_range_prop(sym);
00477         if (!prop)
00478             return true;
00479         val = strtol(str, NULL, 10);
00480         return val >= strtol(prop->expr->left.sym->name, NULL, 10) &&
00481                val <= strtol(prop->expr->right.sym->name, NULL, 10);
00482     case S_HEX:
00483         if (!sym_string_valid(sym, str))
00484             return false;
00485         prop = sym_get_range_prop(sym);
00486         if (!prop)
00487             return true;
00488         val = strtol(str, NULL, 16);
00489         return val >= strtol(prop->expr->left.sym->name, NULL, 16) &&
00490                val <= strtol(prop->expr->right.sym->name, NULL, 16);
00491     case S_BOOLEAN:
00492     case S_TRISTATE:
00493         switch (str[0]) {
00494         case 'y': case 'Y':
00495             return sym_tristate_within_range(sym, yes);
00496         case 'm': case 'M':
00497             return sym_tristate_within_range(sym, mod);
00498         case 'n': case 'N':
00499             return sym_tristate_within_range(sym, no);
00500         }
00501         return false;
00502     default:
00503         return false;
00504     }
00505 }
00506 
00507 bool sym_set_string_value(struct symbol *sym, const char *newval)
00508 {
00509     const char *oldval;
00510     char *val;
00511     int size;
00512 
00513     switch (sym->type) {
00514     case S_BOOLEAN:
00515     case S_TRISTATE:
00516         switch (newval[0]) {
00517         case 'y': case 'Y':
00518             return sym_set_tristate_value(sym, yes);
00519         case 'm': case 'M':
00520             return sym_set_tristate_value(sym, mod);
00521         case 'n': case 'N':
00522             return sym_set_tristate_value(sym, no);
00523         }
00524         return false;
00525     default:
00526         ;
00527     }
00528 
00529     if (!sym_string_within_range(sym, newval))
00530         return false;
00531 
00532     if (sym->flags & SYMBOL_NEW) {
00533         sym->flags &= ~SYMBOL_NEW;
00534         sym_set_changed(sym);
00535     }
00536 
00537     oldval = sym->user.val;
00538     size = strlen(newval) + 1;
00539     if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
00540         size += 2;
00541         sym->user.val = val = malloc(size);
00542         *val++ = '0';
00543         *val++ = 'x';
00544     } else if (!oldval || strcmp(oldval, newval))
00545         sym->user.val = val = malloc(size);
00546     else
00547         return true;
00548 
00549     strcpy(val, newval);
00550     free((void *)oldval);
00551     sym_clear_all_valid();
00552 
00553     return true;
00554 }
00555 
00556 const char *sym_get_string_value(struct symbol *sym)
00557 {
00558     tristate val;
00559 
00560     switch (sym->type) {
00561     case S_BOOLEAN:
00562     case S_TRISTATE:
00563         val = sym_get_tristate_value(sym);
00564         switch (val) {
00565         case no:
00566             return "n";
00567         case mod:
00568             return "m";
00569         case yes:
00570             return "y";
00571         }
00572         break;
00573     default:
00574         ;
00575     }
00576     return (const char *)sym->curr.val;
00577 }
00578 
00579 bool sym_is_changable(struct symbol *sym)
00580 {
00581     return sym->visible > sym->rev_dep.tri;
00582 }
00583 
00584 struct symbol *sym_lookup(const char *name, int isconst)
00585 {
00586     struct symbol *symbol;
00587     const char *ptr;
00588     char *new_name;
00589     int hash = 0;
00590 
00591     if (name) {
00592         if (name[0] && !name[1]) {
00593             switch (name[0]) {
00594             case 'y': return &symbol_yes;
00595             case 'm': return &symbol_mod;
00596             case 'n': return &symbol_no;
00597             }
00598         }
00599         for (ptr = name; *ptr; ptr++)
00600             hash += *ptr;
00601         hash &= 0xff;
00602 
00603         for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
00604             if (!strcmp(symbol->name, name)) {
00605                 if ((isconst && symbol->flags & SYMBOL_CONST) ||
00606                     (!isconst && !(symbol->flags & SYMBOL_CONST)))
00607                     return symbol;
00608             }
00609         }
00610         new_name = strdup(name);
00611     } else {
00612         new_name = NULL;
00613         hash = 256;
00614     }
00615 
00616     symbol = malloc(sizeof(*symbol));
00617     memset(symbol, 0, sizeof(*symbol));
00618     symbol->name = new_name;
00619     symbol->type = S_UNKNOWN;
00620     symbol->flags = SYMBOL_NEW;
00621     if (isconst)
00622         symbol->flags |= SYMBOL_CONST;
00623 
00624     symbol->next = symbol_hash[hash];
00625     symbol_hash[hash] = symbol;
00626 
00627     return symbol;
00628 }
00629 
00630 struct symbol *sym_find(const char *name)
00631 {
00632     struct symbol *symbol = NULL;
00633     const char *ptr;
00634     int hash = 0;
00635 
00636     if (!name)
00637         return NULL;
00638 
00639     if (name[0] && !name[1]) {
00640         switch (name[0]) {
00641         case 'y': return &symbol_yes;
00642         case 'm': return &symbol_mod;
00643         case 'n': return &symbol_no;
00644         }
00645     }
00646     for (ptr = name; *ptr; ptr++)
00647         hash += *ptr;
00648     hash &= 0xff;
00649 
00650     for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
00651         if (!strcmp(symbol->name, name) &&
00652             !(symbol->flags & SYMBOL_CONST))
00653                 break;
00654     }
00655 
00656     return symbol;
00657 }
00658 
00659 struct symbol *sym_check_deps(struct symbol *sym);
00660 
00661 static struct symbol *sym_check_expr_deps(struct expr *e)
00662 {
00663     struct symbol *sym;
00664 
00665     if (!e)
00666         return NULL;
00667     switch (e->type) {
00668     case E_OR:
00669     case E_AND:
00670         sym = sym_check_expr_deps(e->left.expr);
00671         if (sym)
00672             return sym;
00673         return sym_check_expr_deps(e->right.expr);
00674     case E_NOT:
00675         return sym_check_expr_deps(e->left.expr);
00676     case E_EQUAL:
00677     case E_UNEQUAL:
00678         sym = sym_check_deps(e->left.sym);
00679         if (sym)
00680             return sym;
00681         return sym_check_deps(e->right.sym);
00682     case E_SYMBOL:
00683         return sym_check_deps(e->left.sym);
00684     default:
00685         break;
00686     }
00687     printf("Oops! How to check %d?\n", e->type);
00688     return NULL;
00689 }
00690 
00691 struct symbol *sym_check_deps(struct symbol *sym)
00692 {
00693     struct symbol *sym2;
00694     struct property *prop;
00695 
00696     if (sym->flags & SYMBOL_CHECK_DONE)
00697         return NULL;
00698     if (sym->flags & SYMBOL_CHECK) {
00699         printf("Warning! Found recursive dependency: %s", sym->name);
00700         return sym;
00701     }
00702 
00703     sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
00704     sym2 = sym_check_expr_deps(sym->rev_dep.expr);
00705     if (sym2)
00706         goto out;
00707 
00708     for (prop = sym->prop; prop; prop = prop->next) {
00709         if (prop->type == P_CHOICE)
00710             continue;
00711         sym2 = sym_check_expr_deps(prop->visible.expr);
00712         if (sym2)
00713             goto out;
00714         if (prop->type != P_DEFAULT || sym_is_choice(sym))
00715             continue;
00716         sym2 = sym_check_expr_deps(prop->expr);
00717         if (sym2)
00718             goto out;
00719     }
00720 out:
00721     if (sym2)
00722         printf(" %s", sym->name);
00723     sym->flags &= ~SYMBOL_CHECK;
00724     return sym2;
00725 }
00726 
00727 struct property *prop_alloc(enum prop_type type, struct symbol *sym)
00728 {
00729     struct property *prop;
00730     struct property **propp;
00731 
00732     prop = malloc(sizeof(*prop));
00733     memset(prop, 0, sizeof(*prop));
00734     prop->type = type;
00735     prop->sym = sym;
00736     prop->file = current_file;
00737     prop->lineno = zconf_lineno();
00738 
00739     /* append property to the prop list of symbol */
00740     if (sym) {
00741         for (propp = &sym->prop; *propp; propp = &(*propp)->next)
00742             ;
00743         *propp = prop;
00744     }
00745 
00746     return prop;
00747 }
00748 
00749 struct symbol *prop_get_symbol(struct property *prop)
00750 {
00751     if (prop->expr && (prop->expr->type == E_SYMBOL ||
00752                prop->expr->type == E_CHOICE))
00753         return prop->expr->left.sym;
00754     return NULL;
00755 }
00756 
00757 const char *prop_get_type_name(enum prop_type type)
00758 {
00759     switch (type) {
00760     case P_PROMPT:
00761         return "prompt";
00762     case P_COMMENT:
00763         return "comment";
00764     case P_MENU:
00765         return "menu";
00766     case P_DEFAULT:
00767         return "default";
00768     case P_CHOICE:
00769         return "choice";
00770     case P_SELECT:
00771         return "select";
00772     case P_RANGE:
00773         return "range";
00774     case P_UNKNOWN:
00775         break;
00776     }
00777     return "unknown";
00778 }

Generated on Tue Feb 2 17:46:04 2010 for RTAI API by  doxygen 1.4.7