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.


imported SEABIOS source tree
[palacios.git] / bios / seabios / tools / 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 static const char nohelp_text[] = N_(
13         "There is no help available for this option.\n");
14
15 struct menu rootmenu;
16 static struct menu **last_entry_ptr;
17
18 struct file *file_list;
19 struct file *current_file;
20
21 void menu_warn(struct menu *menu, const char *fmt, ...)
22 {
23         va_list ap;
24         va_start(ap, fmt);
25         fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
26         vfprintf(stderr, fmt, ap);
27         fprintf(stderr, "\n");
28         va_end(ap);
29 }
30
31 static void prop_warn(struct property *prop, const char *fmt, ...)
32 {
33         va_list ap;
34         va_start(ap, fmt);
35         fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
36         vfprintf(stderr, fmt, ap);
37         fprintf(stderr, "\n");
38         va_end(ap);
39 }
40
41 void _menu_init(void)
42 {
43         current_entry = current_menu = &rootmenu;
44         last_entry_ptr = &rootmenu.list;
45 }
46
47 void menu_add_entry(struct symbol *sym)
48 {
49         struct menu *menu;
50
51         menu = malloc(sizeof(*menu));
52         memset(menu, 0, sizeof(*menu));
53         menu->sym = sym;
54         menu->parent = current_menu;
55         menu->file = current_file;
56         menu->lineno = zconf_lineno();
57
58         *last_entry_ptr = menu;
59         last_entry_ptr = &menu->next;
60         current_entry = menu;
61         if (sym)
62                 menu_add_symbol(P_SYMBOL, sym, NULL);
63 }
64
65 void menu_end_entry(void)
66 {
67 }
68
69 struct menu *menu_add_menu(void)
70 {
71         menu_end_entry();
72         last_entry_ptr = &current_entry->list;
73         return current_menu = current_entry;
74 }
75
76 void menu_end_menu(void)
77 {
78         last_entry_ptr = &current_menu->next;
79         current_menu = current_menu->parent;
80 }
81
82 static struct expr *menu_check_dep(struct expr *e)
83 {
84         if (!e)
85                 return e;
86
87         switch (e->type) {
88         case E_NOT:
89                 e->left.expr = menu_check_dep(e->left.expr);
90                 break;
91         case E_OR:
92         case E_AND:
93                 e->left.expr = menu_check_dep(e->left.expr);
94                 e->right.expr = menu_check_dep(e->right.expr);
95                 break;
96         case E_SYMBOL:
97                 /* change 'm' into 'm' && MODULES */
98                 if (e->left.sym == &symbol_mod)
99                         return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
100                 break;
101         default:
102                 break;
103         }
104         return e;
105 }
106
107 void menu_add_dep(struct expr *dep)
108 {
109         current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
110 }
111
112 void menu_set_type(int type)
113 {
114         struct symbol *sym = current_entry->sym;
115
116         if (sym->type == type)
117                 return;
118         if (sym->type == S_UNKNOWN) {
119                 sym->type = type;
120                 return;
121         }
122         menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
123             sym->name ? sym->name : "<choice>",
124             sym_type_name(sym->type), sym_type_name(type));
125 }
126
127 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
128 {
129         struct property *prop = prop_alloc(type, current_entry->sym);
130
131         prop->menu = current_entry;
132         prop->expr = expr;
133         prop->visible.expr = menu_check_dep(dep);
134
135         if (prompt) {
136                 if (isspace(*prompt)) {
137                         prop_warn(prop, "leading whitespace ignored");
138                         while (isspace(*prompt))
139                                 prompt++;
140                 }
141                 if (current_entry->prompt && current_entry != &rootmenu)
142                         prop_warn(prop, "prompt redefined");
143
144                 /* Apply all upper menus' visibilities to actual prompts. */
145                 if(type == P_PROMPT) {
146                         struct menu *menu = current_entry;
147
148                         while ((menu = menu->parent) != NULL) {
149                                 if (!menu->visibility)
150                                         continue;
151                                 prop->visible.expr
152                                         = expr_alloc_and(prop->visible.expr,
153                                                          menu->visibility);
154                         }
155                 }
156
157                 current_entry->prompt = prop;
158         }
159         prop->text = prompt;
160
161         return prop;
162 }
163
164 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
165 {
166         return menu_add_prop(type, prompt, NULL, dep);
167 }
168
169 void menu_add_visibility(struct expr *expr)
170 {
171         current_entry->visibility = expr_alloc_and(current_entry->visibility,
172             expr);
173 }
174
175 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
176 {
177         menu_add_prop(type, NULL, expr, dep);
178 }
179
180 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
181 {
182         menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
183 }
184
185 void menu_add_option(int token, char *arg)
186 {
187         struct property *prop;
188
189         switch (token) {
190         case T_OPT_MODULES:
191                 prop = prop_alloc(P_DEFAULT, modules_sym);
192                 prop->expr = expr_alloc_symbol(current_entry->sym);
193                 break;
194         case T_OPT_DEFCONFIG_LIST:
195                 if (!sym_defconfig_list)
196                         sym_defconfig_list = current_entry->sym;
197                 else if (sym_defconfig_list != current_entry->sym)
198                         zconf_error("trying to redefine defconfig symbol");
199                 break;
200         case T_OPT_ENV:
201                 prop_add_env(arg);
202                 break;
203         }
204 }
205
206 static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
207 {
208         return sym2->type == S_INT || sym2->type == S_HEX ||
209                (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
210 }
211
212 static void sym_check_prop(struct symbol *sym)
213 {
214         struct property *prop;
215         struct symbol *sym2;
216         for (prop = sym->prop; prop; prop = prop->next) {
217                 switch (prop->type) {
218                 case P_DEFAULT:
219                         if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
220                             prop->expr->type != E_SYMBOL)
221                                 prop_warn(prop,
222                                     "default for config symbol '%s'"
223                                     " must be a single symbol", sym->name);
224                         if (prop->expr->type != E_SYMBOL)
225                                 break;
226                         sym2 = prop_get_symbol(prop);
227                         if (sym->type == S_HEX || sym->type == S_INT) {
228                                 if (!menu_validate_number(sym, sym2))
229                                         prop_warn(prop,
230                                             "'%s': number is invalid",
231                                             sym->name);
232                         }
233                         break;
234                 case P_SELECT:
235                         sym2 = prop_get_symbol(prop);
236                         if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
237                                 prop_warn(prop,
238                                     "config symbol '%s' uses select, but is "
239                                     "not boolean or tristate", sym->name);
240                         else if (sym2->type != S_UNKNOWN &&
241                                  sym2->type != S_BOOLEAN &&
242                                  sym2->type != S_TRISTATE)
243                                 prop_warn(prop,
244                                     "'%s' has wrong type. 'select' only "
245                                     "accept arguments of boolean and "
246                                     "tristate type", sym2->name);
247                         break;
248                 case P_RANGE:
249                         if (sym->type != S_INT && sym->type != S_HEX)
250                                 prop_warn(prop, "range is only allowed "
251                                                 "for int or hex symbols");
252                         if (!menu_validate_number(sym, prop->expr->left.sym) ||
253                             !menu_validate_number(sym, prop->expr->right.sym))
254                                 prop_warn(prop, "range is invalid");
255                         break;
256                 default:
257                         ;
258                 }
259         }
260 }
261
262 void menu_finalize(struct menu *parent)
263 {
264         struct menu *menu, *last_menu;
265         struct symbol *sym;
266         struct property *prop;
267         struct expr *parentdep, *basedep, *dep, *dep2, **ep;
268
269         sym = parent->sym;
270         if (parent->list) {
271                 if (sym && sym_is_choice(sym)) {
272                         if (sym->type == S_UNKNOWN) {
273                                 /* find the first choice value to find out choice type */
274                                 current_entry = parent;
275                                 for (menu = parent->list; menu; menu = menu->next) {
276                                         if (menu->sym && menu->sym->type != S_UNKNOWN) {
277                                                 menu_set_type(menu->sym->type);
278                                                 break;
279                                         }
280                                 }
281                         }
282                         /* set the type of the remaining choice values */
283                         for (menu = parent->list; menu; menu = menu->next) {
284                                 current_entry = menu;
285                                 if (menu->sym && menu->sym->type == S_UNKNOWN)
286                                         menu_set_type(sym->type);
287                         }
288                         parentdep = expr_alloc_symbol(sym);
289                 } else if (parent->prompt)
290                         parentdep = parent->prompt->visible.expr;
291                 else
292                         parentdep = parent->dep;
293
294                 for (menu = parent->list; menu; menu = menu->next) {
295                         basedep = expr_transform(menu->dep);
296                         basedep = expr_alloc_and(expr_copy(parentdep), basedep);
297                         basedep = expr_eliminate_dups(basedep);
298                         menu->dep = basedep;
299                         if (menu->sym)
300                                 prop = menu->sym->prop;
301                         else
302                                 prop = menu->prompt;
303                         for (; prop; prop = prop->next) {
304                                 if (prop->menu != menu)
305                                         continue;
306                                 dep = expr_transform(prop->visible.expr);
307                                 dep = expr_alloc_and(expr_copy(basedep), dep);
308                                 dep = expr_eliminate_dups(dep);
309                                 if (menu->sym && menu->sym->type != S_TRISTATE)
310                                         dep = expr_trans_bool(dep);
311                                 prop->visible.expr = dep;
312                                 if (prop->type == P_SELECT) {
313                                         struct symbol *es = prop_get_symbol(prop);
314                                         es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
315                                                         expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
316                                 }
317                         }
318                 }
319                 for (menu = parent->list; menu; menu = menu->next)
320                         menu_finalize(menu);
321         } else if (sym) {
322                 basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
323                 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
324                 basedep = expr_eliminate_dups(expr_transform(basedep));
325                 last_menu = NULL;
326                 for (menu = parent->next; menu; menu = menu->next) {
327                         dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
328                         if (!expr_contains_symbol(dep, sym))
329                                 break;
330                         if (expr_depends_symbol(dep, sym))
331                                 goto next;
332                         dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
333                         dep = expr_eliminate_dups(expr_transform(dep));
334                         dep2 = expr_copy(basedep);
335                         expr_eliminate_eq(&dep, &dep2);
336                         expr_free(dep);
337                         if (!expr_is_yes(dep2)) {
338                                 expr_free(dep2);
339                                 break;
340                         }
341                         expr_free(dep2);
342                 next:
343                         menu_finalize(menu);
344                         menu->parent = parent;
345                         last_menu = menu;
346                 }
347                 if (last_menu) {
348                         parent->list = parent->next;
349                         parent->next = last_menu->next;
350                         last_menu->next = NULL;
351                 }
352
353                 sym->dir_dep.expr = parent->dep;
354         }
355         for (menu = parent->list; menu; menu = menu->next) {
356                 if (sym && sym_is_choice(sym) &&
357                     menu->sym && !sym_is_choice_value(menu->sym)) {
358                         current_entry = menu;
359                         menu->sym->flags |= SYMBOL_CHOICEVAL;
360                         if (!menu->prompt)
361                                 menu_warn(menu, "choice value must have a prompt");
362                         for (prop = menu->sym->prop; prop; prop = prop->next) {
363                                 if (prop->type == P_DEFAULT)
364                                         prop_warn(prop, "defaults for choice "
365                                                   "values not supported");
366                                 if (prop->menu == menu)
367                                         continue;
368                                 if (prop->type == P_PROMPT &&
369                                     prop->menu->parent->sym != sym)
370                                         prop_warn(prop, "choice value used outside its choice group");
371                         }
372                         /* Non-tristate choice values of tristate choices must
373                          * depend on the choice being set to Y. The choice
374                          * values' dependencies were propagated to their
375                          * properties above, so the change here must be re-
376                          * propagated.
377                          */
378                         if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
379                                 basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
380                                 menu->dep = expr_alloc_and(basedep, menu->dep);
381                                 for (prop = menu->sym->prop; prop; prop = prop->next) {
382                                         if (prop->menu != menu)
383                                                 continue;
384                                         prop->visible.expr = expr_alloc_and(expr_copy(basedep),
385                                                                             prop->visible.expr);
386                                 }
387                         }
388                         menu_add_symbol(P_CHOICE, sym, NULL);
389                         prop = sym_get_choice_prop(sym);
390                         for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
391                                 ;
392                         *ep = expr_alloc_one(E_LIST, NULL);
393                         (*ep)->right.sym = menu->sym;
394                 }
395                 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
396                         for (last_menu = menu->list; ; last_menu = last_menu->next) {
397                                 last_menu->parent = parent;
398                                 if (!last_menu->next)
399                                         break;
400                         }
401                         last_menu->next = menu->next;
402                         menu->next = menu->list;
403                         menu->list = NULL;
404                 }
405         }
406
407         if (sym && !(sym->flags & SYMBOL_WARNED)) {
408                 if (sym->type == S_UNKNOWN)
409                         menu_warn(parent, "config symbol defined without type");
410
411                 if (sym_is_choice(sym) && !parent->prompt)
412                         menu_warn(parent, "choice must have a prompt");
413
414                 /* Check properties connected to this symbol */
415                 sym_check_prop(sym);
416                 sym->flags |= SYMBOL_WARNED;
417         }
418
419         if (sym && !sym_is_optional(sym) && parent->prompt) {
420                 sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
421                                 expr_alloc_and(parent->prompt->visible.expr,
422                                         expr_alloc_symbol(&symbol_mod)));
423         }
424 }
425
426 bool menu_has_prompt(struct menu *menu)
427 {
428         if (!menu->prompt)
429                 return false;
430         return true;
431 }
432
433 bool menu_is_visible(struct menu *menu)
434 {
435         struct menu *child;
436         struct symbol *sym;
437         tristate visible;
438
439         if (!menu->prompt)
440                 return false;
441
442         if (menu->visibility) {
443                 if (expr_calc_value(menu->visibility) == no)
444                         return no;
445         }
446
447         sym = menu->sym;
448         if (sym) {
449                 sym_calc_value(sym);
450                 visible = menu->prompt->visible.tri;
451         } else
452                 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
453
454         if (visible != no)
455                 return true;
456
457         if (!sym || sym_get_tristate_value(menu->sym) == no)
458                 return false;
459
460         for (child = menu->list; child; child = child->next) {
461                 if (menu_is_visible(child)) {
462                         if (sym)
463                                 sym->flags |= SYMBOL_DEF_USER;
464                         return true;
465                 }
466         }
467
468         return false;
469 }
470
471 const char *menu_get_prompt(struct menu *menu)
472 {
473         if (menu->prompt)
474                 return menu->prompt->text;
475         else if (menu->sym)
476                 return menu->sym->name;
477         return NULL;
478 }
479
480 struct menu *menu_get_root_menu(struct menu *menu)
481 {
482         return &rootmenu;
483 }
484
485 struct menu *menu_get_parent_menu(struct menu *menu)
486 {
487         enum prop_type type;
488
489         for (; menu != &rootmenu; menu = menu->parent) {
490                 type = menu->prompt ? menu->prompt->type : 0;
491                 if (type == P_MENU)
492                         break;
493         }
494         return menu;
495 }
496
497 bool menu_has_help(struct menu *menu)
498 {
499         return menu->help != NULL;
500 }
501
502 const char *menu_get_help(struct menu *menu)
503 {
504         if (menu->help)
505                 return menu->help;
506         else
507                 return "";
508 }
509
510 static void get_prompt_str(struct gstr *r, struct property *prop)
511 {
512         int i, j;
513         struct menu *submenu[8], *menu;
514
515         str_printf(r, _("Prompt: %s\n"), _(prop->text));
516         str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
517                 prop->menu->lineno);
518         if (!expr_is_yes(prop->visible.expr)) {
519                 str_append(r, _("  Depends on: "));
520                 expr_gstr_print(prop->visible.expr, r);
521                 str_append(r, "\n");
522         }
523         menu = prop->menu->parent;
524         for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
525                 submenu[i++] = menu;
526         if (i > 0) {
527                 str_printf(r, _("  Location:\n"));
528                 for (j = 4; --i >= 0; j += 2) {
529                         menu = submenu[i];
530                         str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
531                         if (menu->sym) {
532                                 str_printf(r, " (%s [=%s])", menu->sym->name ?
533                                         menu->sym->name : _("<choice>"),
534                                         sym_get_string_value(menu->sym));
535                         }
536                         str_append(r, "\n");
537                 }
538         }
539 }
540
541 void get_symbol_str(struct gstr *r, struct symbol *sym)
542 {
543         bool hit;
544         struct property *prop;
545
546         if (sym && sym->name) {
547                 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
548                            sym_get_string_value(sym));
549                 str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
550                 if (sym->type == S_INT || sym->type == S_HEX) {
551                         prop = sym_get_range_prop(sym);
552                         if (prop) {
553                                 str_printf(r, "Range : ");
554                                 expr_gstr_print(prop->expr, r);
555                                 str_append(r, "\n");
556                         }
557                 }
558         }
559         for_all_prompts(sym, prop)
560                 get_prompt_str(r, prop);
561         hit = false;
562         for_all_properties(sym, prop, P_SELECT) {
563                 if (!hit) {
564                         str_append(r, "  Selects: ");
565                         hit = true;
566                 } else
567                         str_printf(r, " && ");
568                 expr_gstr_print(prop->expr, r);
569         }
570         if (hit)
571                 str_append(r, "\n");
572         if (sym->rev_dep.expr) {
573                 str_append(r, _("  Selected by: "));
574                 expr_gstr_print(sym->rev_dep.expr, r);
575                 str_append(r, "\n");
576         }
577         str_append(r, "\n\n");
578 }
579
580 struct gstr get_relations_str(struct symbol **sym_arr)
581 {
582         struct symbol *sym;
583         struct gstr res = str_new();
584         int i;
585
586         for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
587                 get_symbol_str(&res, sym);
588         if (!i)
589                 str_append(&res, _("No matches found.\n"));
590         return res;
591 }
592
593
594 void menu_get_ext_help(struct menu *menu, struct gstr *help)
595 {
596         struct symbol *sym = menu->sym;
597
598         if (menu_has_help(menu)) {
599                 if (sym->name) {
600                         str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
601                         str_append(help, _(menu_get_help(menu)));
602                         str_append(help, "\n");
603                 }
604         } else {
605                 str_append(help, nohelp_text);
606         }
607         if (sym)
608                 get_symbol_str(help, sym);
609 }