source: debwrt/trunk/config/mconf/menu.c @ 1

Last change on this file since 1 was 1, checked in by amain, 13 years ago

Initial import of the build environment for DebWrt

File size: 10.1 KB
Line 
1/*
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;
13static struct menu **last_entry_ptr;
14
15struct file *file_list;
16struct file *current_file;
17
18static 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
38void 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
64struct menu *menu_add_menu(void)
65{
66        menu_end_entry();
67        last_entry_ptr = &current_entry->list;
68        return current_menu = current_entry;
69}
70
71void menu_end_menu(void)
72{
73        last_entry_ptr = &current_menu->next;
74        current_menu = current_menu->parent;
75}
76
77void menu_add_dep(struct expr *dep)
78{
79        current_entry->dep = expr_alloc_and(current_entry->dep, dep);
80}
81
82void menu_set_type(int type)
83{
84        struct symbol *sym = current_entry->sym;
85
86        if (sym->type == type)
87                return;
88        if (sym->type == S_UNKNOWN) {
89                sym->type = type;
90                return;
91        }
92        menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n",
93            sym->name ? sym->name : "<choice>",
94            sym_type_name(sym->type), sym_type_name(type));
95}
96
97struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
98{
99        struct property *prop = prop_alloc(type, current_entry->sym);
100
101        prop->menu = current_entry;
102        prop->text = prompt;
103        prop->expr = expr;
104        prop->visible.expr = dep;
105
106        if (prompt) {
107                if (current_entry->prompt)
108                        menu_warn(current_entry, "prompt redefined\n");
109                current_entry->prompt = prop;
110        }
111
112        return prop;
113}
114
115struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
116{
117        return menu_add_prop(type, prompt, NULL, dep);
118}
119
120void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
121{
122        menu_add_prop(type, NULL, expr, dep);
123}
124
125void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
126{
127        menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
128}
129
130static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
131{
132        return sym2->type == S_INT || sym2->type == S_HEX ||
133               (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
134}
135
136void sym_check_prop(struct symbol *sym)
137{
138        struct property *prop;
139        struct symbol *sym2;
140        for (prop = sym->prop; prop; prop = prop->next) {
141                switch (prop->type) {
142                case P_DEFAULT:
143                        if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
144                            prop->expr->type != E_SYMBOL)
145                                prop_warn(prop,
146                                    "default for config symbol '%'"
147                                    " must be a single symbol", sym->name);
148                        break;
149                case P_SELECT:
150                        sym2 = prop_get_symbol(prop);
151                        if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
152                                prop_warn(prop,
153                                    "config symbol '%s' uses select, but is "
154                                    "not boolean or tristate", sym->name);
155                        else if (sym2->type == S_UNKNOWN)
156                                prop_warn(prop,
157                                    "'select' used by config symbol '%s' "
158                                    "refer to undefined symbol '%s'",
159                                    sym->name, sym2->name);
160                        else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
161                                prop_warn(prop,
162                                    "'%s' has wrong type. 'select' only "
163                                    "accept arguments of boolean and "
164                                    "tristate type", sym2->name);
165                        break;
166                case P_DESELECT:
167                        sym2 = prop_get_symbol(prop);
168                        if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
169                                prop_warn(prop,
170                                    "config symbol '%s' uses deselect, but is "
171                                    "not boolean or tristate", sym->name);
172                        else if (sym2->type == S_UNKNOWN)
173                                prop_warn(prop,
174                                    "'deselect' used by config symbol '%s' "
175                                    "refer to undefined symbol '%s'",
176                                    sym->name, sym2->name);
177                        else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
178                                prop_warn(prop,
179                                    "'%s' has wrong type. 'deselect' only "
180                                    "accept arguments of boolean and "
181                                    "tristate type", sym2->name);
182                        break;
183                case P_RANGE:
184                        if (sym->type != S_INT && sym->type != S_HEX)
185                                prop_warn(prop, "range is only allowed "
186                                                "for int or hex symbols");
187                        if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
188                            !menu_range_valid_sym(sym, prop->expr->right.sym))
189                                prop_warn(prop, "range is invalid");
190                        break;
191                default:
192                        ;
193                }
194        }
195}
196
197void menu_finalize(struct menu *parent)
198{
199        struct menu *menu, *last_menu;
200        struct symbol *sym;
201        struct property *prop;
202        struct expr *parentdep, *basedep, *dep, *dep2, **ep;
203
204        sym = parent->sym;
205        if (parent->list) {
206                if (sym && sym_is_choice(sym)) {
207                        /* find the first choice value and find out choice type */
208                        for (menu = parent->list; menu; menu = menu->next) {
209                                if (menu->sym) {
210                                        current_entry = parent;
211                                        menu_set_type(menu->sym->type);
212                                        current_entry = menu;
213                                        menu_set_type(sym->type);
214                                        break;
215                                }
216                        }
217                        parentdep = expr_alloc_symbol(sym);
218                } else if (parent->prompt)
219                        parentdep = parent->prompt->visible.expr;
220                else
221                        parentdep = parent->dep;
222
223                for (menu = parent->list; menu; menu = menu->next) {
224                        basedep = expr_transform(menu->dep);
225                        basedep = expr_alloc_and(expr_copy(parentdep), basedep);
226                        basedep = expr_eliminate_dups(basedep);
227                        menu->dep = basedep;
228                        if (menu->sym)
229                                prop = menu->sym->prop;
230                        else
231                                prop = menu->prompt;
232
233                        for (; prop; prop = prop->next) {
234                                if (prop->menu != menu)
235                                        continue;
236                                dep = expr_transform(prop->visible.expr);
237                                dep = expr_alloc_and(expr_copy(menu->dep), dep);
238                                dep = expr_eliminate_dups(dep);
239                                if (menu->sym && menu->sym->type != S_TRISTATE)
240                                        dep = expr_trans_bool(dep);
241                                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                                }
247                                if (prop->type == P_DESELECT) {
248                                        struct symbol *es = prop_get_symbol(prop);
249                                        es->rev_dep_inv.expr = expr_alloc_or(es->rev_dep_inv.expr,
250                                                        expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
251                                }
252                        }
253                }
254                for (menu = parent->list; menu; menu = menu->next)
255                        menu_finalize(menu);
256        } else if (sym) {
257                basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
258                basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
259                basedep = expr_eliminate_dups(expr_transform(basedep));
260                last_menu = NULL;
261                for (menu = parent->next; menu; menu = menu->next) {
262                        dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
263                        if (!expr_contains_symbol(dep, sym))
264                                break;
265                        if (expr_depends_symbol(dep, sym))
266                                goto next;
267                        dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
268                        dep = expr_eliminate_dups(expr_transform(dep));
269                        dep2 = expr_copy(basedep);
270                        expr_eliminate_eq(&dep, &dep2);
271                        expr_free(dep);
272                        if (!expr_is_yes(dep2)) {
273                                expr_free(dep2);
274                                break;
275                        }
276                        expr_free(dep2);
277                next:
278                        menu_finalize(menu);
279                        menu->parent = parent;
280                        last_menu = menu;
281                }
282                if (last_menu) {
283                        parent->list = parent->next;
284                        parent->next = last_menu->next;
285                        last_menu->next = NULL;
286                }
287        }
288        for (menu = parent->list; menu; menu = menu->next) {
289                if (sym && sym_is_choice(sym) && menu->sym) {
290                        menu->sym->flags |= SYMBOL_CHOICEVAL;
291                        if (!menu->prompt)
292                                menu_warn(menu, "choice value must have a prompt");
293                        for (prop = menu->sym->prop; prop; prop = prop->next) {
294                                if (prop->type == P_PROMPT && prop->menu != menu) {
295                                        prop_warn(prop, "choice values "
296                                            "currently only support a "
297                                            "single prompt");
298                                }
299                        }
300                        current_entry = menu;
301                        menu_set_type(sym->type);
302                        menu_add_symbol(P_CHOICE, sym, NULL);
303                        prop = sym_get_choice_prop(sym);
304                        for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
305                                ;
306                        *ep = expr_alloc_one(E_CHOICE, NULL);
307                        (*ep)->right.sym = menu->sym;
308                }
309                if (menu->list && (!menu->prompt || !menu->prompt->text)) {
310                        for (last_menu = menu->list; ; last_menu = last_menu->next) {
311                                last_menu->parent = parent;
312                                if (!last_menu->next)
313                                        break;
314                        }
315                        last_menu->next = menu->next;
316                        menu->next = menu->list;
317                        menu->list = NULL;
318                }
319        }
320
321        if (sym && !(sym->flags & SYMBOL_WARNED)) {
322                if (sym->type == S_UNKNOWN)
323                        menu_warn(parent, "config symbol defined "
324                            "without type\n");
325
326                if (sym_is_choice(sym) && !parent->prompt)
327                        menu_warn(parent, "choice must have a prompt\n");
328
329                /* Check properties connected to this symbol */
330                sym_check_prop(sym);
331                sym->flags |= SYMBOL_WARNED;
332        }
333
334        if (sym && !sym_is_optional(sym) && parent->prompt) {
335                sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
336                                expr_alloc_and(parent->prompt->visible.expr,
337                                        expr_alloc_symbol(&symbol_mod)));
338        }
339}
340
341bool menu_is_visible(struct menu *menu)
342{
343        struct menu *child;
344        struct symbol *sym;
345        tristate visible;
346
347        if (!menu->prompt)
348                return false;
349        sym = menu->sym;
350        if (sym) {
351                sym_calc_value(sym);
352                visible = menu->prompt->visible.tri;
353        } else
354                visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
355
356        if (visible != no)
357                return true;
358        if (!sym || sym_get_tristate_value(menu->sym) == no)
359                return false;
360
361        for (child = menu->list; child; child = child->next)
362                if (menu_is_visible(child))
363                        return true;
364        return false;
365}
366
367const char *menu_get_prompt(struct menu *menu)
368{
369        if (menu->prompt)
370                return _(menu->prompt->text);
371        else if (menu->sym)
372                return _(menu->sym->name);
373        return NULL;
374}
375
376struct menu *menu_get_root_menu(struct menu *menu)
377{
378        return &rootmenu;
379}
380
381struct menu *menu_get_parent_menu(struct menu *menu)
382{
383        enum prop_type type;
384
385        for (; menu != &rootmenu; menu = menu->parent) {
386                type = menu->prompt ? menu->prompt->type : 0;
387                if (type == P_MENU)
388                        break;
389        }
390        return menu;
391}
392
Note: See TracBrowser for help on using the repository browser.