root/trunk/freewrt/tools/config/menu.c

Revision 3223, 10.7 kB (checked in by tg, 5 years ago)

implement "select !FOO", everything including cosmetics from me,
except rev_dep_inv+deselected stuff, which is from nbd@openwrt –
thanks

selected symbols are now shown as “-+-” (on) or “_ _” (off)

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
12 struct menu rootmenu;
13 struct menu *current_menu, *current_entry;
14 static struct menu **last_entry_ptr;
15
16 struct file *file_list;
17 struct file *current_file;
18
19 static void menu_warn(struct menu *menu, const char *fmt, ...)
20 {
21         va_list ap;
22         va_start(ap, fmt);
23         fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
24         vfprintf(stderr, fmt, ap);
25         fprintf(stderr, "\n");
26         va_end(ap);
27 }
28
29 static void prop_warn(struct property *prop, const char *fmt, ...)
30 {
31         va_list ap;
32         va_start(ap, fmt);
33         fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
34         vfprintf(stderr, fmt, ap);
35         fprintf(stderr, "\n");
36         va_end(ap);
37 }
38
39 void menu_init(void)
40 {
41         current_entry = current_menu = &rootmenu;
42         last_entry_ptr = &rootmenu.list;
43 }
44
45 void menu_add_entry(struct symbol *sym)
46 {
47         struct menu *menu;
48
49         menu = malloc(sizeof(*menu));
50         memset(menu, 0, sizeof(*menu));
51         menu->sym = sym;
52         menu->parent = current_menu;
53         menu->file = current_file;
54         menu->lineno = zconf_lineno();
55
56         *last_entry_ptr = menu;
57         last_entry_ptr = &menu->next;
58         current_entry = menu;
59 }
60
61 void menu_end_entry(void)
62 {
63 }
64
65 void menu_add_menu(void)
66 {
67         current_menu = current_entry;
68         last_entry_ptr = &current_entry->list;
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 void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
141 {
142         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 void sym_check_prop(struct symbol *sym)
156 {
157         struct property *prop;
158         struct symbol *sym2;
159         for (prop = sym->prop; prop; prop = prop->next) {
160                 switch (prop->type) {
161                 case P_DEFAULT:
162                         if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
163                             prop->expr->type != E_SYMBOL)
164                                 prop_warn(prop,
165                                     "default for config symbol '%'"
166                                     " must be a single symbol", sym->name);
167                         break;
168                 case P_SELECT:
169                 case P_SELECTNOT:
170                         sym2 = prop_get_symbol(prop);
171                         if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
172                                 prop_warn(prop,
173                                     "config symbol '%s' uses select, but is "
174                                     "not boolean or tristate", sym->name);
175                         else if (sym2->type == S_UNKNOWN)
176                                 prop_warn(prop,
177                                     "'select' used by config symbol '%s' "
178                                     "refer to undefined symbol '%s'",
179                                     sym->name, sym2->name);
180                         else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
181                                 prop_warn(prop,
182                                     "'%s' has wrong type. 'select' only "
183                                     "accept arguments of boolean and "
184                                     "tristate type", sym2->name);
185                         break;
186                 case P_RANGE:
187                         if (sym->type != S_INT && sym->type != S_HEX)
188                                 prop_warn(prop, "range is only allowed "
189                                                 "for int or hex symbols");
190                         if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
191                             !sym_string_valid(sym, prop->expr->right.sym->name))
192                                 prop_warn(prop, "range is invalid");
193                         break;
194                 default:
195                         ;
196                 }
197         }
198 }
199
200 void menu_finalize(struct menu *parent)
201 {
202         struct menu *menu, *last_menu;
203         struct symbol *sym;
204         struct property *prop;
205         struct expr *parentdep, *basedep, *dep, *dep2, **ep;
206
207         sym = parent->sym;
208         if (parent->list) {
209                 if (sym && sym_is_choice(sym)) {
210                         /* find the first choice value and find out choice type */
211                         for (menu = parent->list; menu; menu = menu->next) {
212                                 if (menu->sym) {
213                                         current_entry = parent;
214                                         menu_set_type(menu->sym->type);
215                                         current_entry = menu;
216                                         menu_set_type(sym->type);
217                                         break;
218                                 }
219                         }
220                         parentdep = expr_alloc_symbol(sym);
221                 } else if (parent->prompt)
222                         parentdep = parent->prompt->visible.expr;
223                 else
224                         parentdep = parent->dep;
225
226                 for (menu = parent->list; menu; menu = menu->next) {
227                         basedep = expr_transform(menu->dep);
228                         basedep = expr_alloc_and(expr_copy(parentdep), basedep);
229                         basedep = expr_eliminate_dups(basedep);
230                         menu->dep = basedep;
231                         if (menu->sym)
232                                 prop = menu->sym->prop;
233                         else
234                                 prop = menu->prompt;
235                         for (; prop; prop = prop->next) {
236                                 if (prop->menu != menu)
237                                         continue;
238                                 dep = expr_transform(prop->visible.expr);
239                                 dep = expr_alloc_and(expr_copy(basedep), dep);
240                                 dep = expr_eliminate_dups(dep);
241                                 if (menu->sym && menu->sym->type != S_TRISTATE)
242                                         dep = expr_trans_bool(dep);
243                                 prop->visible.expr = dep;
244                                 if (prop->type == P_SELECT) {
245                                         struct symbol *es = prop_get_symbol(prop);
246                                         es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
247                                                         expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
248                                 } else if (prop->type == P_SELECTNOT) {
249                                         struct symbol *es = prop_get_symbol(prop);
250                                         es->rev_dep_inv.expr = expr_alloc_or(es->rev_dep_inv.expr,
251                                                         expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
252                                 }
253                         }
254                 }
255                 for (menu = parent->list; menu; menu = menu->next)
256                         menu_finalize(menu);
257         } else if (sym) {
258                 basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
259                 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
260                 basedep = expr_eliminate_dups(expr_transform(basedep));
261                 last_menu = NULL;
262                 for (menu = parent->next; menu; menu = menu->next) {
263                         dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
264                         if (!expr_contains_symbol(dep, sym))
265                                 break;
266                         if (expr_depends_symbol(dep, sym))
267                                 goto next;
268                         dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
269                         dep = expr_eliminate_dups(expr_transform(dep));
270                         dep2 = expr_copy(basedep);
271                         expr_eliminate_eq(&dep, &dep2);
272                         expr_free(dep);
273                         if (!expr_is_yes(dep2)) {
274                                 expr_free(dep2);
275                                 break;
276                         }
277                         expr_free(dep2);
278                 next:
279                         menu_finalize(menu);
280                         menu->parent = parent;
281                         last_menu = menu;
282                 }
283                 if (last_menu) {
284                         parent->list = parent->next;
285                         parent->next = last_menu->next;
286                         last_menu->next = NULL;
287                 }
288         }
289         for (menu = parent->list; menu; menu = menu->next) {
290                 if (sym && sym_is_choice(sym) && menu->sym) {
291                         menu->sym->flags |= SYMBOL_CHOICEVAL;
292                         if (!menu->prompt)
293                                 menu_warn(menu, "choice value must have a prompt");
294                         for (prop = menu->sym->prop; prop; prop = prop->next) {
295                                 if (prop->type == P_PROMPT && prop->menu != menu) {
296                                         prop_warn(prop, "choice values "
297                                             "currently only support a "
298                                             "single prompt");
299                                 }
300                                 if (prop->type == P_DEFAULT)
301                                         prop_warn(prop, "defaults for choice "
302                                             "values not supported");
303                         }
304                         current_entry = menu;
305                         menu_set_type(sym->type);
306                         menu_add_symbol(P_CHOICE, sym, NULL);
307                         prop = sym_get_choice_prop(sym);
308                         for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
309                                 ;
310                         *ep = expr_alloc_one(E_CHOICE, NULL);
311                         (*ep)->right.sym = menu->sym;
312                 }
313                 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
314                         for (last_menu = menu->list; ; last_menu = last_menu->next) {
315                                 last_menu->parent = parent;
316                                 if (!last_menu->next)
317                                         break;
318                         }
319                         last_menu->next = menu->next;
320                         menu->next = menu->list;
321                         menu->list = NULL;
322                 }
323         }
324
325         if (sym && !(sym->flags & SYMBOL_WARNED)) {
326                 if (sym->type == S_UNKNOWN)
327                         menu_warn(parent, "config symbol defined "
328                             "without type\n");
329
330                 if (sym_is_choice(sym) && !parent->prompt)
331                         menu_warn(parent, "choice must have a prompt\n");
332
333                 /* Check properties connected to this symbol */
334                 sym_check_prop(sym);
335                 sym->flags |= SYMBOL_WARNED;
336         }
337
338         if (sym && !sym_is_optional(sym) && parent->prompt) {
339                 sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
340                                 expr_alloc_and(parent->prompt->visible.expr,
341                                         expr_alloc_symbol(&symbol_mod)));
342         }
343 }
344
345 bool menu_is_visible(struct menu *menu)
346 {
347         struct menu *child;
348         struct symbol *sym;
349         tristate visible;
350
351         if (!menu->prompt)
352                 return false;
353         sym = menu->sym;
354         if (sym) {
355                 sym_calc_value(sym);
356                 visible = menu->prompt->visible.tri;
357         } else
358                 visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
359
360         if (visible != no)
361                 return true;
362         if (!sym || sym_get_tristate_value(menu->sym) == no)
363                 return false;
364
365         for (child = menu->list; child; child = child->next)
366                 if (menu_is_visible(child))
367                         return true;
368         return false;
369 }
370
371 const char *menu_get_prompt(struct menu *menu)
372 {
373         if (menu->prompt)
374                 return menu->prompt->text;
375         else if (menu->sym)
376                 return menu->sym->name;
377         return NULL;
378 }
379
380 struct menu *menu_get_root_menu(struct menu *menu)
381 {
382         return &rootmenu;
383 }
384
385 struct menu *menu_get_parent_menu(struct menu *menu)
386 {
387         enum prop_type type;
388
389         for (; menu != &rootmenu; menu = menu->parent) {
390                 type = menu->prompt ? menu->prompt->type : 0;
391                 if (type == P_MENU)
392                         break;
393         }
394         return menu;
395 }
396
397 struct file *file_lookup(const char *name)
398 {
399         struct file *file;
400
401         for (file = file_list; file; file = file->next) {
402                 if (!strcmp(name, file->name))
403                         return file;
404         }
405
406         file = malloc(sizeof(*file));
407         memset(file, 0, sizeof(*file));
408         file->name = strdup(name);
409         file->next = file_list;
410         file_list = file;
411         return file;
412 }
413
414 int file_write_dep(const char *name)
415 {
416         struct file *file;
417         FILE *out;
418
419         if (!name)
420                 name = ".config.cmd";
421         out = fopen(".config.tmp", "w");
422         if (!out)
423                 return 1;
424         fprintf(out, "deps_config := \\\n");
425         for (file = file_list; file; file = file->next) {
426                 if (file->next)
427                         fprintf(out, "\t%s \\\n", file->name);
428                 else
429                         fprintf(out, "\t%s\n", file->name);
430         }
431         fprintf(out, "\n.config include/config.h: $(deps_config)\n\n$(deps_config):\n");
432         fclose(out);
433         rename(".config.tmp", name);
434         return 0;
435 }
436
Note: See TracBrowser for help on using the browser.