Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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