www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / kernel / linux / 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
14 /* CONFIG_MIPS_BRCM Begin Broadcom changed code. */
15 /* These variables must be moved higher to zconf.tab.c_shipped to make
16  * GCC4.0 happy.  See CRDDB00016084.
17 struct menu *current_menu, *current_entry;
18 */
19 /* CONFIG_MIPS_BRCM end Broadcom changed code. */
20
21 static struct menu **last_entry_ptr;
22
23 struct file *file_list;
24 struct file *current_file;
25
26 static void menu_warn(struct menu *menu, const char *fmt, ...)
27 {
28         va_list ap;
29         va_start(ap, fmt);
30         fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
31         vfprintf(stderr, fmt, ap);
32         fprintf(stderr, "\n");
33         va_end(ap);
34 }
35
36 static void prop_warn(struct property *prop, const char *fmt, ...)
37 {
38         va_list ap;
39         va_start(ap, fmt);
40         fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
41         vfprintf(stderr, fmt, ap);
42         fprintf(stderr, "\n");
43         va_end(ap);
44 }
45
46 void menu_init(void)
47 {
48         current_entry = current_menu = &rootmenu;
49         last_entry_ptr = &rootmenu.list;
50 }
51
52 void menu_add_entry(struct symbol *sym)
53 {
54         struct menu *menu;
55
56         menu = malloc(sizeof(*menu));
57         memset(menu, 0, sizeof(*menu));
58         menu->sym = sym;
59         menu->parent = current_menu;
60         menu->file = current_file;
61         menu->lineno = zconf_lineno();
62
63         *last_entry_ptr = menu;
64         last_entry_ptr = &menu->next;
65         current_entry = menu;
66 }
67
68 void menu_end_entry(void)
69 {
70 }
71
72 void menu_add_menu(void)
73 {
74         current_menu = current_entry;
75         last_entry_ptr = &current_entry->list;
76 }
77
78 void menu_end_menu(void)
79 {
80         last_entry_ptr = &current_menu->next;
81         current_menu = current_menu->parent;
82 }
83
84 struct expr *menu_check_dep(struct expr *e)
85 {
86         if (!e)
87                 return e;
88
89         switch (e->type) {
90         case E_NOT:
91                 e->left.expr = menu_check_dep(e->left.expr);
92                 break;
93         case E_OR:
94         case E_AND:
95                 e->left.expr = menu_check_dep(e->left.expr);
96                 e->right.expr = menu_check_dep(e->right.expr);
97                 break;
98         case E_SYMBOL:
99                 /* change 'm' into 'm' && MODULES */
100                 if (e->left.sym == &symbol_mod)
101                         return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
102                 break;
103         default:
104                 break;
105         }
106         return e;
107 }
108
109 void menu_add_dep(struct expr *dep)
110 {
111         current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
112 }
113
114 void menu_set_type(int type)
115 {
116         struct symbol *sym = current_entry->sym;
117
118         if (sym->type == type)
119                 return;
120         if (sym->type == S_UNKNOWN) {
121                 sym->type = type;
122                 return;
123         }
124         menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n",
125             sym->name ? sym->name : "<choice>",
126             sym_type_name(sym->type), sym_type_name(type));
127 }
128
129 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
130 {
131         struct property *prop = prop_alloc(type, current_entry->sym);
132
133         prop->menu = current_entry;
134         prop->text = prompt;
135         prop->expr = expr;
136         prop->visible.expr = menu_check_dep(dep);
137
138         if (prompt) {
139                 if (current_entry->prompt)
140                         menu_warn(current_entry, "prompt redefined\n");
141                 current_entry->prompt = prop;
142         }
143
144         return prop;
145 }
146
147 void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
148 {
149         menu_add_prop(type, prompt, NULL, dep);
150 }
151
152 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
153 {
154         menu_add_prop(type, NULL, expr, dep);
155 }
156
157 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
158 {
159         menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
160 }
161
162 void sym_check_prop(struct symbol *sym)
163 {
164         struct property *prop;
165         struct symbol *sym2;
166         for (prop = sym->prop; prop; prop = prop->next) {
167                 switch (prop->type) {
168                 case P_DEFAULT:
169                         if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
170                             prop->expr->type != E_SYMBOL)
171                                 prop_warn(prop,
172                                     "default for config symbol '%'"
173                                     " must be a single symbol", sym->name);
174                         break;
175                 case P_SELECT:
176                         sym2 = prop_get_symbol(prop);
177                         if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
178                                 prop_warn(prop,
179                                     "config symbol '%s' uses select, but is "
180                                     "not boolean or tristate", sym->name);
181                         else if (sym2->type == S_UNKNOWN)
182                                 prop_warn(prop,
183                                     "'select' used by config symbol '%s' "
184                                     "refer to undefined symbol '%s'",
185                                     sym->name, sym2->name);
186                         else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
187                                 prop_warn(prop,
188                                     "'%s' has wrong type. 'select' only "
189                                     "accept arguments of boolean and "
190                                     "tristate type", sym2->name);
191                         break;
192                 case P_RANGE:
193                         if (sym->type != S_INT && sym->type != S_HEX)
194                                 prop_warn(prop, "range is only allowed "
195                                                 "for int or hex symbols");
196                         if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
197                             !sym_string_valid(sym, prop->expr->right.sym->name))
198                                 prop_warn(prop, "range is invalid");
199                         break;
200                 default:
201                         ;
202                 }
203         }
204 }
205
206 void menu_finalize(struct menu *parent)
207 {
208         struct menu *menu, *last_menu;
209         struct symbol *sym;
210         struct property *prop;
211         struct expr *parentdep, *basedep, *dep, *dep2, **ep;
212
213         sym = parent->sym;
214         if (parent->list) {
215                 if (sym && sym_is_choice(sym)) {
216                         /* find the first choice value and find out choice type */
217                         for (menu = parent->list; menu; menu = menu->next) {
218                                 if (menu->sym) {
219                                         current_entry = parent;
220                                         menu_set_type(menu->sym->type);
221                                         current_entry = menu;
222                                         menu_set_type(sym->type);
223                                         break;
224                                 }
225                         }
226                         parentdep = expr_alloc_symbol(sym);
227                 } else if (parent->prompt)
228                         parentdep = parent->prompt->visible.expr;
229                 else
230                         parentdep = parent->dep;
231
232                 for (menu = parent->list; menu; menu = menu->next) {
233                         basedep = expr_transform(menu->dep);
234                         basedep = expr_alloc_and(expr_copy(parentdep), basedep);
235                         basedep = expr_eliminate_dups(basedep);
236                         menu->dep = basedep;
237                         if (menu->sym)
238                                 prop = menu->sym->prop;
239                         else
240                                 prop = menu->prompt;
241                         for (; prop; prop = prop->next) {
242                                 if (prop->menu != menu)
243                                         continue;
244                                 dep = expr_transform(prop->visible.expr);
245                                 dep = expr_alloc_and(expr_copy(basedep), dep);
246                                 dep = expr_eliminate_dups(dep);
247                                 if (menu->sym && menu->sym->type != S_TRISTATE)
248                                         dep = expr_trans_bool(dep);
249                                 prop->visible.expr = dep;
250                                 if (prop->type == P_SELECT) {
251                                         struct symbol *es = prop_get_symbol(prop);
252                                         es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
253                                                         expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
254                                 }
255                         }
256                 }
257                 for (menu = parent->list; menu; menu = menu->next)
258                         menu_finalize(menu);
259         } else if (sym) {
260                 basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
261                 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
262                 basedep = expr_eliminate_dups(expr_transform(basedep));
263                 last_menu = NULL;
264                 for (menu = parent->next; menu; menu = menu->next) {
265                         dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
266                         if (!expr_contains_symbol(dep, sym))
267                                 break;
268                         if (expr_depends_symbol(dep, sym))
269                                 goto next;
270                         dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
271                         dep = expr_eliminate_dups(expr_transform(dep));
272                         dep2 = expr_copy(basedep);
273                         expr_eliminate_eq(&dep, &dep2);
274                         expr_free(dep);
275                         if (!expr_is_yes(dep2)) {
276                                 expr_free(dep2);
277                                 break;
278                         }
279                         expr_free(dep2);
280                 next:
281                         menu_finalize(menu);
282                         menu->parent = parent;
283                         last_menu = menu;
284                 }
285                 if (last_menu) {
286                         parent->list = parent->next;
287                         parent->next = last_menu->next;
288                         last_menu->next = NULL;
289                 }
290         }
291         for (menu = parent->list; menu; menu = menu->next) {
292                 if (sym && sym_is_choice(sym) && menu->sym) {
293                         menu->sym->flags |= SYMBOL_CHOICEVAL;
294                         if (!menu->prompt)
295                                 menu_warn(menu, "choice value must have a prompt");
296                         for (prop = menu->sym->prop; prop; prop = prop->next) {
297                                 if (prop->type == P_PROMPT && prop->menu != menu) {
298                                         prop_warn(prop, "choice values "
299                                             "currently only support a "
300                                             "single prompt");
301                                 }
302                                 if (prop->type == P_DEFAULT)
303                                         prop_warn(prop, "defaults for choice "
304                                             "values not supported");
305                         }
306                         current_entry = menu;
307                         menu_set_type(sym->type);
308                         menu_add_symbol(P_CHOICE, sym, NULL);
309                         prop = sym_get_choice_prop(sym);
310                         for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
311                                 ;
312                         *ep = expr_alloc_one(E_CHOICE, NULL);
313                         (*ep)->right.sym = menu->sym;
314                 }
315                 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
316                         for (last_menu = menu->list; ; last_menu = last_menu->next) {
317                                 last_menu->parent = parent;
318                                 if (!last_menu->next)
319                                         break;
320                         }
321                         last_menu->next = menu->next;
322                         menu->next = menu->list;
323                         menu->list = NULL;
324                 }
325         }
326
327         if (sym && !(sym->flags & SYMBOL_WARNED)) {
328                 if (sym->type == S_UNKNOWN)
329                         menu_warn(parent, "config symbol defined "
330                             "without type\n");
331
332                 if (sym_is_choice(sym) && !parent->prompt)
333                         menu_warn(parent, "choice must have a prompt\n");
334
335                 /* Check properties connected to this symbol */
336                 sym_check_prop(sym);
337                 sym->flags |= SYMBOL_WARNED;
338         }
339
340         if (sym && !sym_is_optional(sym) && parent->prompt) {
341                 sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
342                                 expr_alloc_and(parent->prompt->visible.expr,
343                                         expr_alloc_symbol(&symbol_mod)));
344         }
345 }
346
347 bool menu_is_visible(struct menu *menu)
348 {
349         struct menu *child;
350         struct symbol *sym;
351         tristate visible;
352
353         if (!menu->prompt)
354                 return false;
355         sym = menu->sym;
356         if (sym) {
357                 sym_calc_value(sym);
358                 visible = menu->prompt->visible.tri;
359         } else
360                 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
361
362         if (visible != no)
363                 return true;
364         if (!sym || sym_get_tristate_value(menu->sym) == no)
365                 return false;
366
367         for (child = menu->list; child; child = child->next)
368                 if (menu_is_visible(child))
369                         return true;
370         return false;
371 }
372
373 const char *menu_get_prompt(struct menu *menu)
374 {
375         if (menu->prompt)
376                 return menu->prompt->text;
377         else if (menu->sym)
378                 return menu->sym->name;
379         return NULL;
380 }
381
382 struct menu *menu_get_root_menu(struct menu *menu)
383 {
384         return &rootmenu;
385 }
386
387 struct menu *menu_get_parent_menu(struct menu *menu)
388 {
389         enum prop_type type;
390
391         for (; menu != &rootmenu; menu = menu->parent) {
392                 type = menu->prompt ? menu->prompt->type : 0;
393                 if (type == P_MENU)
394                         break;
395         }
396         return menu;
397 }
398
399 struct file *file_lookup(const char *name)
400 {
401         struct file *file;
402
403         for (file = file_list; file; file = file->next) {
404                 if (!strcmp(name, file->name))
405                         return file;
406         }
407
408         file = malloc(sizeof(*file));
409         memset(file, 0, sizeof(*file));
410         file->name = strdup(name);
411         file->next = file_list;
412         file_list = file;
413         return file;
414 }
415
416 int file_write_dep(const char *name)
417 {
418         struct file *file;
419         FILE *out;
420
421         if (!name)
422                 name = ".config.cmd";
423         out = fopen("..config.tmp", "w");
424         if (!out)
425                 return 1;
426         fprintf(out, "deps_config := \\\n");
427         for (file = file_list; file; file = file->next) {
428                 if (file->next)
429                         fprintf(out, "\t%s \\\n", file->name);
430                 else
431                         fprintf(out, "\t%s\n", file->name);
432         }
433         fprintf(out, "\n.config include/linux/autoconf.h: $(deps_config)\n\n$(deps_config):\n");
434         fclose(out);
435         rename("..config.tmp", name);
436         return 0;
437 }
438