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 = &
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
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 }