3d3b4d19c2361c48cc1240e940f495a6f85b06bf
[people/mcb30/busybox.git] / 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
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 void menu_init(void)
20 {
21         current_entry = current_menu = &rootmenu;
22         last_entry_ptr = &rootmenu.list;
23 }
24
25 void menu_add_entry(struct symbol *sym)
26 {
27         struct menu *menu;
28
29         menu = malloc(sizeof(*menu));
30         memset(menu, 0, sizeof(*menu));
31         menu->sym = sym;
32         menu->parent = current_menu;
33         menu->file = current_file;
34         menu->lineno = zconf_lineno();
35
36         *last_entry_ptr = menu;
37         last_entry_ptr = &menu->next;
38         current_entry = menu;
39 }
40
41 void menu_end_entry(void)
42 {
43 }
44
45 void menu_add_menu(void)
46 {
47         current_menu = current_entry;
48         last_entry_ptr = &current_entry->list;
49 }
50
51 void menu_end_menu(void)
52 {
53         last_entry_ptr = &current_menu->next;
54         current_menu = current_menu->parent;
55 }
56
57 void menu_add_dep(struct expr *dep)
58 {
59         current_entry->dep = expr_alloc_and(current_entry->dep, dep);
60 }
61
62 void menu_set_type(int type)
63 {
64         struct symbol *sym = current_entry->sym;
65
66         if (sym->type == type)
67                 return;
68         if (sym->type == S_UNKNOWN) {
69                 sym->type = type;
70                 return;
71         }
72         fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n",
73                 current_entry->file->name, current_entry->lineno,
74                 sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type));
75 }
76
77 struct property *create_prop(enum prop_type type)
78 {
79         struct property *prop;
80
81         prop = malloc(sizeof(*prop));
82         memset(prop, 0, sizeof(*prop));
83         prop->type = type;
84         prop->file = current_file;
85         prop->lineno = zconf_lineno();
86
87         return prop;
88 }
89
90 struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep)
91 {
92         struct property *prop = create_prop(token);
93         struct property **propp;
94
95         prop->sym = current_entry->sym;
96         prop->menu = current_entry;
97         prop->text = prompt;
98         prop->def = def;
99         E_EXPR(prop->visible) = dep;
100
101         if (prompt)
102                 current_entry->prompt = prop;
103
104         /* append property to the prop list of symbol */
105         if (prop->sym) {
106                 for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
107                         ;
108                 *propp = prop;
109         }
110
111         return prop;
112 }
113
114 void menu_add_prompt(int token, char *prompt, struct expr *dep)
115 {
116         current_entry->prompt = menu_add_prop(token, prompt, NULL, dep);
117 }
118
119 void menu_add_default(int token, struct symbol *def, struct expr *dep)
120 {
121         current_entry->prompt = menu_add_prop(token, NULL, def, dep);
122 }
123
124 void menu_finalize(struct menu *parent)
125 {
126         struct menu *menu, *last_menu;
127         struct symbol *sym;
128         struct property *prop;
129         struct expr *parentdep, *basedep, *dep, *dep2;
130
131         sym = parent->sym;
132         if (parent->list) {
133                 if (sym && sym_is_choice(sym)) {
134                         /* find the first choice value and find out choice type */
135                         for (menu = parent->list; menu; menu = menu->next) {
136                                 if (menu->sym) {
137                                         current_entry = parent;
138                                         menu_set_type(menu->sym->type);
139                                         current_entry = menu;
140                                         menu_set_type(sym->type);
141                                         break;
142                                 }
143                         }
144                         parentdep = expr_alloc_symbol(sym);
145                 } else if (parent->prompt)
146                         parentdep = E_EXPR(parent->prompt->visible);
147                 else
148                         parentdep = parent->dep;
149
150                 for (menu = parent->list; menu; menu = menu->next) {
151                         basedep = expr_transform(menu->dep);
152                         basedep = expr_alloc_and(expr_copy(parentdep), basedep);
153                         basedep = expr_eliminate_dups(basedep);
154                         menu->dep = basedep;
155                         if (menu->sym)
156                                 prop = menu->sym->prop;
157                         else
158                                 prop = menu->prompt;
159                         for (; prop; prop = prop->next) {
160                                 if (prop->menu != menu)
161                                         continue;
162                                 dep = expr_transform(E_EXPR(prop->visible));
163                                 dep = expr_alloc_and(expr_copy(basedep), dep);
164                                 dep = expr_eliminate_dups(dep);
165                                 if (menu->sym && menu->sym->type != S_TRISTATE)
166                                         dep = expr_trans_bool(dep);
167                                 E_EXPR(prop->visible) = dep;
168                         }
169                 }
170                 for (menu = parent->list; menu; menu = menu->next)
171                         menu_finalize(menu);
172         } else if (sym && parent->prompt) {
173                 basedep = E_EXPR(parent->prompt->visible);
174                 basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
175                 basedep = expr_eliminate_dups(expr_transform(basedep));
176                 last_menu = NULL;
177                 for (menu = parent->next; menu; menu = menu->next) {
178                         dep = menu->prompt ? E_EXPR(menu->prompt->visible) : menu->dep;
179                         if (!expr_contains_symbol(dep, sym))
180                                 break;
181                         if (expr_depends_symbol(dep, sym))
182                                 goto next;
183                         dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
184                         dep = expr_eliminate_dups(expr_transform(dep));
185                         dep2 = expr_copy(basedep);
186                         expr_eliminate_eq(&dep, &dep2);
187                         expr_free(dep);
188                         if (!expr_is_yes(dep2)) {
189                                 expr_free(dep2);
190                                 break;
191                         }
192                         expr_free(dep2);
193                 next:
194                         menu_finalize(menu);
195                         menu->parent = parent;
196                         last_menu = menu;
197                 }
198                 if (last_menu) {
199                         parent->list = parent->next;
200                         parent->next = last_menu->next;
201                         last_menu->next = NULL;
202                 }
203         }
204         for (menu = parent->list; menu; menu = menu->next) {
205                 if (sym && sym_is_choice(sym) && menu->sym) {
206                         menu->sym->flags |= SYMBOL_CHOICEVAL;
207                         current_entry = menu;
208                         menu_set_type(sym->type);
209                         menu_add_prop(P_CHOICE, NULL, parent->sym, NULL);
210                         prop = sym_get_choice_prop(parent->sym);
211                         //dep = expr_alloc_one(E_CHOICE, dep);
212                         //dep->right.sym = menu->sym;
213                         prop->dep = expr_alloc_one(E_CHOICE, prop->dep);
214                         prop->dep->right.sym = menu->sym;
215                 }
216                 if (menu->list && (!menu->prompt || !menu->prompt->text)) {
217                         for (last_menu = menu->list; ; last_menu = last_menu->next) {
218                                 last_menu->parent = parent;
219                                 if (!last_menu->next)
220                                         break;
221                         }
222                         last_menu->next = menu->next;
223                         menu->next = menu->list;
224                         menu->list = NULL;
225                 }
226         }
227 }
228
229 bool menu_is_visible(struct menu *menu)
230 {
231         tristate visible;
232
233         if (!menu->prompt)
234                 return false;
235         if (menu->sym) {
236                 sym_calc_value(menu->sym);
237                 visible = E_TRI(menu->prompt->visible);
238         } else
239                 visible = E_CALC(menu->prompt->visible);
240         return visible != no;
241 }
242
243 const char *menu_get_prompt(struct menu *menu)
244 {
245         if (menu->prompt)
246                 return menu->prompt->text;
247         else if (menu->sym)
248                 return menu->sym->name;
249         return NULL;
250 }
251
252 struct menu *menu_get_root_menu(struct menu *menu)
253 {
254         return &rootmenu;
255 }
256
257 struct menu *menu_get_parent_menu(struct menu *menu)
258 {
259         enum prop_type type;
260
261         while (menu != &rootmenu) {
262                 menu = menu->parent;
263                 type = menu->prompt ? menu->prompt->type : 0;
264                 if (type == P_MENU || type == P_ROOTMENU)
265                         break;
266         }
267         return menu;
268 }
269
270 struct file *file_lookup(const char *name)
271 {
272         struct file *file;
273
274         for (file = file_list; file; file = file->next) {
275                 if (!strcmp(name, file->name))
276                         return file;
277         }
278
279         file = malloc(sizeof(*file));
280         memset(file, 0, sizeof(*file));
281         file->name = strdup(name);
282         file->next = file_list;
283         file_list = file;
284         return file;
285 }
286
287 int file_write_dep(const char *name)
288 {
289         struct file *file;
290         FILE *out;
291
292         if (!name)
293                 name = ".config.cmd";
294         out = fopen(".config.tmp", "w");
295         if (!out)
296                 return 1;
297         fprintf(out, "deps_config := \\\n");
298         for (file = file_list; file; file = file->next) {
299                 if (file->next)
300                         fprintf(out, "\t%s \\\n", file->name);
301                 else
302                         fprintf(out, "\t%s\n", file->name);
303         }
304         fprintf(out, "\n.config include/config.h: $(deps_config)\n\n$(deps_config):\n");
305         fclose(out);
306         rename(".config.tmp", name);
307         return 0;
308 }
309