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 Thu Nov 20 11:49:48 2008 for RTAI API by doxygen 1.3.8