Root/scripts/config/menu.c

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
393

Archive Download this file



interactive