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