base/config/kconfig/menu.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 <stdlib.h>
00007 #include <string.h>
00008 
00009 #define LKC_DIRECT_LINK
00010 #include "lkc.h"
00011 
00012 struct menu rootmenu;
00013 struct menu *current_menu, *current_entry;
00014 static struct menu **last_entry_ptr;
00015 
00016 struct file *file_list;
00017 struct file *current_file;
00018 
00019 void menu_init(void)
00020 {
00021     current_entry = current_menu = &rootmenu;
00022     last_entry_ptr = &rootmenu.list;
00023 }
00024 
00025 void menu_add_entry(struct symbol *sym)
00026 {
00027     struct menu *menu;
00028 
00029     menu = malloc(sizeof(*menu));
00030     memset(menu, 0, sizeof(*menu));
00031     menu->sym = sym;
00032     menu->parent = current_menu;
00033     menu->file = current_file;
00034     menu->lineno = zconf_lineno();
00035 
00036     *last_entry_ptr = menu;
00037     last_entry_ptr = &menu->next;
00038     current_entry = menu;
00039 }
00040 
00041 void menu_end_entry(void)
00042 {
00043 }
00044 
00045 void menu_add_menu(void)
00046 {
00047     current_menu = current_entry;
00048     last_entry_ptr = &current_entry->list;
00049 }
00050 
00051 void menu_end_menu(void)
00052 {
00053     last_entry_ptr = &current_menu->next;
00054     current_menu = current_menu->parent;
00055 }
00056 
00057 struct expr *menu_check_dep(struct expr *e)
00058 {
00059     if (!e)
00060         return e;
00061 
00062     switch (e->type) {
00063     case E_NOT:
00064         e->left.expr = menu_check_dep(e->left.expr);
00065         break;
00066     case E_OR:
00067     case E_AND:
00068         e->left.expr = menu_check_dep(e->left.expr);
00069         e->right.expr = menu_check_dep(e->right.expr);
00070         break;
00071     case E_SYMBOL:
00072         /* change 'm' into 'm' && MODULES */
00073         if (e->left.sym == &symbol_mod)
00074             return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
00075         break;
00076     default:
00077         break;
00078     }
00079     return e;
00080 }
00081 
00082 void menu_add_dep(struct expr *dep)
00083 {
00084     current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
00085 }
00086 
00087 void menu_set_type(int type)
00088 {
00089     struct symbol *sym = current_entry->sym;
00090 
00091     if (sym->type == type)
00092         return;
00093     if (sym->type == S_UNKNOWN) {
00094         sym->type = type;
00095         return;
00096     }
00097     fprintf(stderr, "%s:%d:warning: type of '%s' redefined from '%s' to '%s'\n",
00098         current_entry->file->name, current_entry->lineno,
00099         sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type));
00100 }
00101 
00102 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
00103 {
00104     struct property *prop = prop_alloc(type, current_entry->sym);
00105 
00106     prop->menu = current_entry;
00107     prop->text = prompt;
00108     prop->expr = expr;
00109     prop->visible.expr = menu_check_dep(dep);
00110 
00111     if (prompt) {
00112         if (current_entry->prompt)
00113             fprintf(stderr, "%s:%d: prompt redefined\n",
00114                 current_entry->file->name, current_entry->lineno);
00115         current_entry->prompt = prop;
00116     }
00117 
00118     return prop;
00119 }
00120 
00121 void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
00122 {
00123     menu_add_prop(type, prompt, NULL, dep);
00124 }
00125 
00126 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
00127 {
00128     menu_add_prop(type, NULL, expr, dep);
00129 }
00130 
00131 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
00132 {
00133     menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
00134 }
00135 
00136 void menu_finalize(struct menu *parent)
00137 {
00138     struct menu *menu, *last_menu;
00139     struct symbol *sym;
00140     struct property *prop;
00141     struct expr *parentdep, *basedep, *dep, *dep2, **ep;
00142 
00143     sym = parent->sym;
00144     if (parent->list) {
00145         if (sym && sym_is_choice(sym)) {
00146             /* find the first choice value and find out choice type */
00147             for (menu = parent->list; menu; menu = menu->next) {
00148                 if (menu->sym) {
00149                     current_entry = parent;
00150                     menu_set_type(menu->sym->type);
00151                     current_entry = menu;
00152                     menu_set_type(sym->type);
00153                     break;
00154                 }
00155             }
00156             parentdep = expr_alloc_symbol(sym);
00157         } else if (parent->prompt)
00158             parentdep = parent->prompt->visible.expr;
00159         else
00160             parentdep = parent->dep;
00161 
00162         for (menu = parent->list; menu; menu = menu->next) {
00163             basedep = expr_transform(menu->dep);
00164             basedep = expr_alloc_and(expr_copy(parentdep), basedep);
00165             basedep = expr_eliminate_dups(basedep);
00166             menu->dep = basedep;
00167             if (menu->sym)
00168                 prop = menu->sym->prop;
00169             else
00170                 prop = menu->prompt;
00171             for (; prop; prop = prop->next) {
00172                 if (prop->menu != menu)
00173                     continue;
00174                 dep = expr_transform(prop->visible.expr);
00175                 dep = expr_alloc_and(expr_copy(basedep), dep);
00176                 dep = expr_eliminate_dups(dep);
00177                 if (menu->sym && menu->sym->type != S_TRISTATE)
00178                     dep = expr_trans_bool(dep);
00179                 prop->visible.expr = dep;
00180                 if (prop->type == P_SELECT) {
00181                     struct symbol *es = prop_get_symbol(prop);
00182                     es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
00183                             expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
00184                 }
00185             }
00186         }
00187         for (menu = parent->list; menu; menu = menu->next)
00188             menu_finalize(menu);
00189     } else if (sym) {
00190         basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
00191         basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
00192         basedep = expr_eliminate_dups(expr_transform(basedep));
00193         last_menu = NULL;
00194         for (menu = parent->next; menu; menu = menu->next) {
00195             dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
00196             if (!expr_contains_symbol(dep, sym))
00197                 break;
00198             if (expr_depends_symbol(dep, sym))
00199                 goto next;
00200             dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
00201             dep = expr_eliminate_dups(expr_transform(dep));
00202             dep2 = expr_copy(basedep);
00203             expr_eliminate_eq(&dep, &dep2);
00204             expr_free(dep);
00205             if (!expr_is_yes(dep2)) {
00206                 expr_free(dep2);
00207                 break;
00208             }
00209             expr_free(dep2);
00210         next:
00211             menu_finalize(menu);
00212             menu->parent = parent;
00213             last_menu = menu;
00214         }
00215         if (last_menu) {
00216             parent->list = parent->next;
00217             parent->next = last_menu->next;
00218             last_menu->next = NULL;
00219         }
00220     }
00221     for (menu = parent->list; menu; menu = menu->next) {
00222         if (sym && sym_is_choice(sym) && menu->sym) {
00223             menu->sym->flags |= SYMBOL_CHOICEVAL;
00224             if (!menu->prompt)
00225                 fprintf(stderr, "%s:%d:warning: choice value must have a prompt\n",
00226                     menu->file->name, menu->lineno);
00227             for (prop = menu->sym->prop; prop; prop = prop->next) {
00228                 if (prop->type == P_PROMPT && prop->menu != menu) {
00229                     fprintf(stderr, "%s:%d:warning: choice values currently only support a single prompt\n",
00230                         prop->file->name, prop->lineno);
00231                     
00232                 }
00233                 if (prop->type == P_DEFAULT)
00234                     fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n",
00235                         prop->file->name, prop->lineno);
00236             }
00237             current_entry = menu;
00238             menu_set_type(sym->type);
00239             menu_add_symbol(P_CHOICE, sym, NULL);
00240             prop = sym_get_choice_prop(sym);
00241             for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
00242                 ;
00243             *ep = expr_alloc_one(E_CHOICE, NULL);
00244             (*ep)->right.sym = menu->sym;
00245         }
00246         if (menu->list && (!menu->prompt || !menu->prompt->text)) {
00247             for (last_menu = menu->list; ; last_menu = last_menu->next) {
00248                 last_menu->parent = parent;
00249                 if (!last_menu->next)
00250                     break;
00251             }
00252             last_menu->next = menu->next;
00253             menu->next = menu->list;
00254             menu->list = NULL;
00255         }
00256     }
00257 
00258     if (sym && !(sym->flags & SYMBOL_WARNED)) {
00259         struct symbol *sym2;
00260         if (sym->type == S_UNKNOWN)
00261             fprintf(stderr, "%s:%d:warning: config symbol defined without type\n",
00262                 parent->file->name, parent->lineno);
00263 
00264         if (sym_is_choice(sym) && !parent->prompt)
00265             fprintf(stderr, "%s:%d:warning: choice must have a prompt\n",
00266                 parent->file->name, parent->lineno);
00267 
00268         for (prop = sym->prop; prop; prop = prop->next) {
00269             switch (prop->type) {
00270             case P_DEFAULT:
00271                 if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
00272                     prop->expr->type != E_SYMBOL)
00273                     fprintf(stderr, "%s:%d:warning: default must be a single symbol\n",
00274                         prop->file->name, prop->lineno);
00275                 break;
00276             case P_SELECT:
00277                 sym2 = prop_get_symbol(prop);
00278                 if ((sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
00279                     (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE))
00280                     fprintf(stderr, "%s:%d:warning: enable is only allowed with boolean and tristate symbols\n",
00281                         prop->file->name, prop->lineno);
00282                 break;
00283             case P_RANGE:
00284                 if (sym->type != S_INT && sym->type != S_HEX)
00285                     fprintf(stderr, "%s:%d:warning: range is only allowed for int or hex symbols\n",
00286                         prop->file->name, prop->lineno);
00287                 if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
00288                     !sym_string_valid(sym, prop->expr->right.sym->name))
00289                     fprintf(stderr, "%s:%d:warning: range is invalid\n",
00290                         prop->file->name, prop->lineno);
00291                 break;
00292             default:
00293                 ;
00294             }
00295         }
00296         sym->flags |= SYMBOL_WARNED;
00297     }
00298 
00299     if (sym && !sym_is_optional(sym) && parent->prompt) {
00300         sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
00301                 expr_alloc_and(parent->prompt->visible.expr,
00302                     expr_alloc_symbol(&symbol_mod)));
00303     }
00304 }
00305 
00306 bool menu_is_visible(struct menu *menu)
00307 {
00308     struct menu *child;
00309     struct symbol *sym;
00310     tristate visible;
00311 
00312     if (!menu->prompt)
00313         return false;
00314     sym = menu->sym;
00315     if (sym) {
00316         sym_calc_value(sym);
00317         visible = menu->prompt->visible.tri;
00318     } else
00319         visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
00320 
00321     if (visible != no)
00322         return true;
00323     if (!sym || sym_get_tristate_value(menu->sym) == no)
00324         return false;
00325 
00326     for (child = menu->list; child; child = child->next)
00327         if (menu_is_visible(child))
00328             return true;
00329     return false;
00330 }
00331 
00332 const char *menu_get_prompt(struct menu *menu)
00333 {
00334     if (menu->prompt)
00335         return menu->prompt->text;
00336     else if (menu->sym)
00337         return menu->sym->name;
00338     return NULL;
00339 }
00340 
00341 struct menu *menu_get_root_menu(struct menu *menu)
00342 {
00343     return &rootmenu;
00344 }
00345 
00346 struct menu *menu_get_parent_menu(struct menu *menu)
00347 {
00348     enum prop_type type;
00349 
00350     for (; menu != &rootmenu; menu = menu->parent) {
00351         type = menu->prompt ? menu->prompt->type : 0;
00352         if (type == P_MENU)
00353             break;
00354     }
00355     return menu;
00356 }
00357 
00358 struct file *file_lookup(const char *name)
00359 {
00360     struct file *file;
00361 
00362     for (file = file_list; file; file = file->next) {
00363         if (!strcmp(name, file->name))
00364             return file;
00365     }
00366 
00367     file = malloc(sizeof(*file));
00368     memset(file, 0, sizeof(*file));
00369     file->name = strdup(name);
00370     file->next = file_list;
00371     file_list = file;
00372     return file;
00373 }

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