blob: 0c13156f33441fc8fc787b92ab038b752c87a563 [file] [log] [blame]
Eric Andersenc9f20d92002-12-05 08:41:41 +00001/*
2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
4 */
5
6#include <stdlib.h>
7#include <string.h>
8
9#define LKC_DIRECT_LINK
10#include "lkc.h"
11
12struct menu rootmenu;
Eric Andersenc9f20d92002-12-05 08:41:41 +000013static struct menu **last_entry_ptr;
14
15struct file *file_list;
16struct file *current_file;
17
Eric Andersen837f0582004-07-15 06:01:05 +000018static void menu_warn(struct menu *menu, const char *fmt, ...)
19{
20 va_list ap;
21 va_start(ap, fmt);
22 fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
23 vfprintf(stderr, fmt, ap);
24 fprintf(stderr, "\n");
25 va_end(ap);
26}
27
28static void prop_warn(struct property *prop, const char *fmt, ...)
29{
30 va_list ap;
31 va_start(ap, fmt);
32 fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
33 vfprintf(stderr, fmt, ap);
34 fprintf(stderr, "\n");
35 va_end(ap);
36}
37
Eric Andersenc9f20d92002-12-05 08:41:41 +000038void menu_init(void)
39{
40 current_entry = current_menu = &rootmenu;
41 last_entry_ptr = &rootmenu.list;
42}
43
44void menu_add_entry(struct symbol *sym)
45{
46 struct menu *menu;
47
48 menu = malloc(sizeof(*menu));
49 memset(menu, 0, sizeof(*menu));
50 menu->sym = sym;
51 menu->parent = current_menu;
52 menu->file = current_file;
53 menu->lineno = zconf_lineno();
54
55 *last_entry_ptr = menu;
56 last_entry_ptr = &menu->next;
57 current_entry = menu;
58}
59
60void menu_end_entry(void)
61{
62}
63
64void menu_add_menu(void)
65{
66 current_menu = current_entry;
67 last_entry_ptr = &current_entry->list;
68}
69
70void menu_end_menu(void)
71{
72 last_entry_ptr = &current_menu->next;
73 current_menu = current_menu->parent;
74}
75
Eric Andersen72d8e442003-08-05 02:18:25 +000076struct expr *menu_check_dep(struct expr *e)
77{
78 if (!e)
79 return e;
80
81 switch (e->type) {
82 case E_NOT:
83 e->left.expr = menu_check_dep(e->left.expr);
84 break;
85 case E_OR:
86 case E_AND:
87 e->left.expr = menu_check_dep(e->left.expr);
88 e->right.expr = menu_check_dep(e->right.expr);
89 break;
90 case E_SYMBOL:
91 /* change 'm' into 'm' && MODULES */
92 if (e->left.sym == &symbol_mod)
93 return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
94 break;
95 default:
96 break;
97 }
98 return e;
99}
100
Eric Andersenc9f20d92002-12-05 08:41:41 +0000101void menu_add_dep(struct expr *dep)
102{
Eric Andersen72d8e442003-08-05 02:18:25 +0000103 current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
Eric Andersenc9f20d92002-12-05 08:41:41 +0000104}
105
106void menu_set_type(int type)
107{
108 struct symbol *sym = current_entry->sym;
109
110 if (sym->type == type)
111 return;
112 if (sym->type == S_UNKNOWN) {
113 sym->type = type;
114 return;
115 }
Eric Andersen837f0582004-07-15 06:01:05 +0000116 menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n",
117 sym->name ? sym->name : "<choice>",
118 sym_type_name(sym->type), sym_type_name(type));
Eric Andersenc9f20d92002-12-05 08:41:41 +0000119}
120
Eric Andersen72d8e442003-08-05 02:18:25 +0000121struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000122{
Eric Andersen72d8e442003-08-05 02:18:25 +0000123 struct property *prop = prop_alloc(type, current_entry->sym);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000124
Eric Andersenc9f20d92002-12-05 08:41:41 +0000125 prop->menu = current_entry;
126 prop->text = prompt;
Eric Andersen72d8e442003-08-05 02:18:25 +0000127 prop->expr = expr;
128 prop->visible.expr = menu_check_dep(dep);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000129
Eric Andersen72d8e442003-08-05 02:18:25 +0000130 if (prompt) {
131 if (current_entry->prompt)
Eric Andersen837f0582004-07-15 06:01:05 +0000132 menu_warn(current_entry, "prompt redefined\n");
Eric Andersenc9f20d92002-12-05 08:41:41 +0000133 current_entry->prompt = prop;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000134 }
135
136 return prop;
137}
138
Eric Andersen72d8e442003-08-05 02:18:25 +0000139void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000140{
Eric Andersen72d8e442003-08-05 02:18:25 +0000141 menu_add_prop(type, prompt, NULL, dep);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000142}
143
Eric Andersen72d8e442003-08-05 02:18:25 +0000144void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000145{
Eric Andersen72d8e442003-08-05 02:18:25 +0000146 menu_add_prop(type, NULL, expr, dep);
147}
148
149void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
150{
151 menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000152}
153
Eric Andersen837f0582004-07-15 06:01:05 +0000154void sym_check_prop(struct symbol *sym)
155{
156 struct property *prop;
157 struct symbol *sym2;
158 for (prop = sym->prop; prop; prop = prop->next) {
159 switch (prop->type) {
160 case P_DEFAULT:
161 if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
162 prop->expr->type != E_SYMBOL)
163 prop_warn(prop,
164 "default for config symbol '%'"
165 " must be a single symbol", sym->name);
166 break;
167 case P_SELECT:
168 sym2 = prop_get_symbol(prop);
169 if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
170 prop_warn(prop,
171 "config symbol '%s' uses select, but is "
172 "not boolean or tristate", sym->name);
173 else if (sym2->type == S_UNKNOWN)
174 prop_warn(prop,
175 "'select' used by config symbol '%s' "
176 "refer to undefined symbol '%s'",
177 sym->name, sym2->name);
178 else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
179 prop_warn(prop,
180 "'%s' has wrong type. 'select' only "
181 "accept arguments of boolean and "
182 "tristate type", sym2->name);
183 break;
184 case P_RANGE:
185 if (sym->type != S_INT && sym->type != S_HEX)
186 prop_warn(prop, "range is only allowed "
187 "for int or hex symbols");
188 if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
189 !sym_string_valid(sym, prop->expr->right.sym->name))
190 prop_warn(prop, "range is invalid");
191 break;
192 default:
193 ;
194 }
195 }
196}
197
Eric Andersenc9f20d92002-12-05 08:41:41 +0000198void menu_finalize(struct menu *parent)
199{
200 struct menu *menu, *last_menu;
201 struct symbol *sym;
202 struct property *prop;
Eric Andersen72d8e442003-08-05 02:18:25 +0000203 struct expr *parentdep, *basedep, *dep, *dep2, **ep;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000204
205 sym = parent->sym;
206 if (parent->list) {
207 if (sym && sym_is_choice(sym)) {
208 /* find the first choice value and find out choice type */
209 for (menu = parent->list; menu; menu = menu->next) {
210 if (menu->sym) {
211 current_entry = parent;
212 menu_set_type(menu->sym->type);
213 current_entry = menu;
214 menu_set_type(sym->type);
215 break;
216 }
217 }
218 parentdep = expr_alloc_symbol(sym);
219 } else if (parent->prompt)
Eric Andersen72d8e442003-08-05 02:18:25 +0000220 parentdep = parent->prompt->visible.expr;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000221 else
222 parentdep = parent->dep;
223
224 for (menu = parent->list; menu; menu = menu->next) {
225 basedep = expr_transform(menu->dep);
226 basedep = expr_alloc_and(expr_copy(parentdep), basedep);
227 basedep = expr_eliminate_dups(basedep);
228 menu->dep = basedep;
229 if (menu->sym)
230 prop = menu->sym->prop;
231 else
232 prop = menu->prompt;
233 for (; prop; prop = prop->next) {
234 if (prop->menu != menu)
235 continue;
Eric Andersen72d8e442003-08-05 02:18:25 +0000236 dep = expr_transform(prop->visible.expr);
Eric Andersenc9f20d92002-12-05 08:41:41 +0000237 dep = expr_alloc_and(expr_copy(basedep), dep);
238 dep = expr_eliminate_dups(dep);
239 if (menu->sym && menu->sym->type != S_TRISTATE)
240 dep = expr_trans_bool(dep);
Eric Andersen72d8e442003-08-05 02:18:25 +0000241 prop->visible.expr = dep;
242 if (prop->type == P_SELECT) {
243 struct symbol *es = prop_get_symbol(prop);
244 es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
245 expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
246 }
Eric Andersenc9f20d92002-12-05 08:41:41 +0000247 }
248 }
249 for (menu = parent->list; menu; menu = menu->next)
250 menu_finalize(menu);
Eric Andersen72d8e442003-08-05 02:18:25 +0000251 } else if (sym) {
252 basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000253 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
254 basedep = expr_eliminate_dups(expr_transform(basedep));
255 last_menu = NULL;
256 for (menu = parent->next; menu; menu = menu->next) {
Eric Andersen72d8e442003-08-05 02:18:25 +0000257 dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000258 if (!expr_contains_symbol(dep, sym))
259 break;
260 if (expr_depends_symbol(dep, sym))
261 goto next;
262 dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
263 dep = expr_eliminate_dups(expr_transform(dep));
264 dep2 = expr_copy(basedep);
265 expr_eliminate_eq(&dep, &dep2);
266 expr_free(dep);
267 if (!expr_is_yes(dep2)) {
268 expr_free(dep2);
269 break;
270 }
271 expr_free(dep2);
272 next:
273 menu_finalize(menu);
274 menu->parent = parent;
275 last_menu = menu;
276 }
277 if (last_menu) {
278 parent->list = parent->next;
279 parent->next = last_menu->next;
280 last_menu->next = NULL;
281 }
282 }
283 for (menu = parent->list; menu; menu = menu->next) {
284 if (sym && sym_is_choice(sym) && menu->sym) {
285 menu->sym->flags |= SYMBOL_CHOICEVAL;
Eric Andersen72d8e442003-08-05 02:18:25 +0000286 if (!menu->prompt)
Eric Andersen837f0582004-07-15 06:01:05 +0000287 menu_warn(menu, "choice value must have a prompt");
Eric Andersen72d8e442003-08-05 02:18:25 +0000288 for (prop = menu->sym->prop; prop; prop = prop->next) {
289 if (prop->type == P_PROMPT && prop->menu != menu) {
Eric Andersen837f0582004-07-15 06:01:05 +0000290 prop_warn(prop, "choice values "
291 "currently only support a "
292 "single prompt");
Eric Andersen72d8e442003-08-05 02:18:25 +0000293 }
294 if (prop->type == P_DEFAULT)
Eric Andersen837f0582004-07-15 06:01:05 +0000295 prop_warn(prop, "defaults for choice "
296 "values not supported");
Eric Andersen72d8e442003-08-05 02:18:25 +0000297 }
Eric Andersenc9f20d92002-12-05 08:41:41 +0000298 current_entry = menu;
299 menu_set_type(sym->type);
Eric Andersen72d8e442003-08-05 02:18:25 +0000300 menu_add_symbol(P_CHOICE, sym, NULL);
301 prop = sym_get_choice_prop(sym);
302 for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
303 ;
304 *ep = expr_alloc_one(E_CHOICE, NULL);
305 (*ep)->right.sym = menu->sym;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000306 }
307 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
308 for (last_menu = menu->list; ; last_menu = last_menu->next) {
309 last_menu->parent = parent;
310 if (!last_menu->next)
311 break;
312 }
313 last_menu->next = menu->next;
314 menu->next = menu->list;
315 menu->list = NULL;
316 }
317 }
Eric Andersen72d8e442003-08-05 02:18:25 +0000318
319 if (sym && !(sym->flags & SYMBOL_WARNED)) {
Eric Andersen72d8e442003-08-05 02:18:25 +0000320 if (sym->type == S_UNKNOWN)
Eric Andersen837f0582004-07-15 06:01:05 +0000321 menu_warn(parent, "config symbol defined "
322 "without type\n");
Eric Andersen72d8e442003-08-05 02:18:25 +0000323
324 if (sym_is_choice(sym) && !parent->prompt)
Eric Andersen837f0582004-07-15 06:01:05 +0000325 menu_warn(parent, "choice must have a prompt\n");
Eric Andersen72d8e442003-08-05 02:18:25 +0000326
Eric Andersen837f0582004-07-15 06:01:05 +0000327 /* Check properties connected to this symbol */
328 sym_check_prop(sym);
Eric Andersen72d8e442003-08-05 02:18:25 +0000329 sym->flags |= SYMBOL_WARNED;
330 }
331
332 if (sym && !sym_is_optional(sym) && parent->prompt) {
333 sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
334 expr_alloc_and(parent->prompt->visible.expr,
335 expr_alloc_symbol(&symbol_mod)));
336 }
Eric Andersenc9f20d92002-12-05 08:41:41 +0000337}
338
339bool menu_is_visible(struct menu *menu)
340{
Eric Andersen72d8e442003-08-05 02:18:25 +0000341 struct menu *child;
342 struct symbol *sym;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000343 tristate visible;
344
345 if (!menu->prompt)
346 return false;
Eric Andersen72d8e442003-08-05 02:18:25 +0000347 sym = menu->sym;
348 if (sym) {
349 sym_calc_value(sym);
350 visible = menu->prompt->visible.tri;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000351 } else
Eric Andersen72d8e442003-08-05 02:18:25 +0000352 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
353
354 if (visible != no)
355 return true;
356 if (!sym || sym_get_tristate_value(menu->sym) == no)
357 return false;
358
359 for (child = menu->list; child; child = child->next)
360 if (menu_is_visible(child))
361 return true;
362 return false;
Eric Andersenc9f20d92002-12-05 08:41:41 +0000363}
364
365const char *menu_get_prompt(struct menu *menu)
366{
367 if (menu->prompt)
368 return menu->prompt->text;
369 else if (menu->sym)
370 return menu->sym->name;
371 return NULL;
372}
373
374struct menu *menu_get_root_menu(struct menu *menu)
375{
376 return &rootmenu;
377}
378
379struct menu *menu_get_parent_menu(struct menu *menu)
380{
381 enum prop_type type;
382
Eric Andersen72d8e442003-08-05 02:18:25 +0000383 for (; menu != &rootmenu; menu = menu->parent) {
Eric Andersenc9f20d92002-12-05 08:41:41 +0000384 type = menu->prompt ? menu->prompt->type : 0;
Eric Andersen72d8e442003-08-05 02:18:25 +0000385 if (type == P_MENU)
Eric Andersenc9f20d92002-12-05 08:41:41 +0000386 break;
387 }
388 return menu;
389}
390