source: branches/stable/mindi-busybox/scripts/config/menu.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 9.6 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
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
76struct 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
101void menu_add_dep(struct expr *dep)
102{
103    current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
104}
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    }
116    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));
119}
120
121struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
122{
123    struct property *prop = prop_alloc(type, current_entry->sym);
124
125    prop->menu = current_entry;
126    prop->text = prompt;
127    prop->expr = expr;
128    prop->visible.expr = menu_check_dep(dep);
129
130    if (prompt) {
131        if (current_entry->prompt)
132            menu_warn(current_entry, "prompt redefined\n");
133        current_entry->prompt = prop;
134    }
135
136    return prop;
137}
138
139void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
140{
141    menu_add_prop(type, prompt, NULL, dep);
142}
143
144void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
145{
146    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);
152}
153
154void 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
198void menu_finalize(struct menu *parent)
199{
200    struct menu *menu, *last_menu;
201    struct symbol *sym;
202    struct property *prop;
203    struct expr *parentdep, *basedep, *dep, *dep2, **ep;
204
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)
220            parentdep = parent->prompt->visible.expr;
221        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;
236                dep = expr_transform(prop->visible.expr);
237                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);
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            }
248        }
249        for (menu = parent->list; menu; menu = menu->next)
250            menu_finalize(menu);
251    } else if (sym) {
252        basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
253        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) {
257            dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
258            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;
286            if (!menu->prompt)
287                menu_warn(menu, "choice value must have a prompt");
288            for (prop = menu->sym->prop; prop; prop = prop->next) {
289                if (prop->type == P_PROMPT && prop->menu != menu) {
290                    prop_warn(prop, "choice values "
291                        "currently only support a "
292                        "single prompt");
293                }
294                if (prop->type == P_DEFAULT)
295                    prop_warn(prop, "defaults for choice "
296                        "values not supported");
297            }
298            current_entry = menu;
299            menu_set_type(sym->type);
300            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;
306        }
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    }
318
319    if (sym && !(sym->flags & SYMBOL_WARNED)) {
320        if (sym->type == S_UNKNOWN)
321            menu_warn(parent, "config symbol defined "
322                "without type\n");
323
324        if (sym_is_choice(sym) && !parent->prompt)
325            menu_warn(parent, "choice must have a prompt\n");
326
327        /* Check properties connected to this symbol */
328        sym_check_prop(sym);
329        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    }
337}
338
339bool menu_is_visible(struct menu *menu)
340{
341    struct menu *child;
342    struct symbol *sym;
343    tristate visible;
344
345    if (!menu->prompt)
346        return false;
347    sym = menu->sym;
348    if (sym) {
349        sym_calc_value(sym);
350        visible = menu->prompt->visible.tri;
351    } else
352        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;
363}
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
383    for (; menu != &rootmenu; menu = menu->parent) {
384        type = menu->prompt ? menu->prompt->type : 0;
385        if (type == P_MENU)
386            break;
387    }
388    return menu;
389}
390
Note: See TracBrowser for help on using the repository browser.