00001
00002
00003
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 = ¤t_entry->list;
00049 }
00050
00051 void menu_end_menu(void)
00052 {
00053 last_entry_ptr = ¤t_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
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
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 }