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
12struct menu rootmenu;
13struct menu *current_menu, *current_entry;
14static struct menu **last_entry_ptr;
15
16struct file *file_list;
17struct file *current_file;
18
19void menu_init(void)
20{
21	current_entry = current_menu = &rootmenu;
22	last_entry_ptr = &rootmenu.list;
23}
24
25void 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
41void menu_end_entry(void)
42{
43}
44
45void menu_add_menu(void)
46{
47	current_menu = current_entry;
48	last_entry_ptr = &current_entry->list;
49}
50
51void menu_end_menu(void)
52{
53	last_entry_ptr = &current_menu->next;
54	current_menu = current_menu->parent;
55}
56
57void menu_add_dep(struct expr *dep)
58{
59	current_entry->dep = expr_alloc_and(current_entry->dep, dep);
60}
61
62void 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
77struct 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
90struct 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
114void menu_add_prompt(int token, char *prompt, struct expr *dep)
115{
116	current_entry->prompt = menu_add_prop(token, prompt, NULL, dep);
117}
118
119void 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
124void 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
229bool 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
243const 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
252struct menu *menu_get_root_menu(struct menu *menu)
253{
254	return &rootmenu;
255}
256
257struct 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
270struct 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
287int 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	fclose(out);
305	rename(".config.tmp", name);
306	return 0;
307}
308
309