1*10465441SEvalZero /*
2*10465441SEvalZero * Copyright (C) 2002 Roman Zippel <[email protected]>
3*10465441SEvalZero * Released under the terms of the GNU GPL v2.0.
4*10465441SEvalZero */
5*10465441SEvalZero
6*10465441SEvalZero #include <ctype.h>
7*10465441SEvalZero #include <stdarg.h>
8*10465441SEvalZero #include <stdlib.h>
9*10465441SEvalZero #include <string.h>
10*10465441SEvalZero
11*10465441SEvalZero #include "lkc.h"
12*10465441SEvalZero
13*10465441SEvalZero static const char nohelp_text[] = "There is no help available for this option.";
14*10465441SEvalZero
15*10465441SEvalZero struct menu rootmenu;
16*10465441SEvalZero static struct menu **last_entry_ptr;
17*10465441SEvalZero
18*10465441SEvalZero struct file *file_list;
19*10465441SEvalZero struct file *current_file;
20*10465441SEvalZero
menu_warn(struct menu * menu,const char * fmt,...)21*10465441SEvalZero void menu_warn(struct menu *menu, const char *fmt, ...)
22*10465441SEvalZero {
23*10465441SEvalZero va_list ap;
24*10465441SEvalZero va_start(ap, fmt);
25*10465441SEvalZero fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
26*10465441SEvalZero vfprintf(stderr, fmt, ap);
27*10465441SEvalZero fprintf(stderr, "\n");
28*10465441SEvalZero va_end(ap);
29*10465441SEvalZero }
30*10465441SEvalZero
prop_warn(struct property * prop,const char * fmt,...)31*10465441SEvalZero static void prop_warn(struct property *prop, const char *fmt, ...)
32*10465441SEvalZero {
33*10465441SEvalZero va_list ap;
34*10465441SEvalZero va_start(ap, fmt);
35*10465441SEvalZero fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
36*10465441SEvalZero vfprintf(stderr, fmt, ap);
37*10465441SEvalZero fprintf(stderr, "\n");
38*10465441SEvalZero va_end(ap);
39*10465441SEvalZero }
40*10465441SEvalZero
_menu_init(void)41*10465441SEvalZero void _menu_init(void)
42*10465441SEvalZero {
43*10465441SEvalZero current_entry = current_menu = &rootmenu;
44*10465441SEvalZero last_entry_ptr = &rootmenu.list;
45*10465441SEvalZero }
46*10465441SEvalZero
menu_add_entry(struct symbol * sym)47*10465441SEvalZero void menu_add_entry(struct symbol *sym)
48*10465441SEvalZero {
49*10465441SEvalZero struct menu *menu;
50*10465441SEvalZero
51*10465441SEvalZero menu = xmalloc(sizeof(*menu));
52*10465441SEvalZero memset(menu, 0, sizeof(*menu));
53*10465441SEvalZero menu->sym = sym;
54*10465441SEvalZero menu->parent = current_menu;
55*10465441SEvalZero menu->file = current_file;
56*10465441SEvalZero menu->lineno = zconf_lineno();
57*10465441SEvalZero
58*10465441SEvalZero *last_entry_ptr = menu;
59*10465441SEvalZero last_entry_ptr = &menu->next;
60*10465441SEvalZero current_entry = menu;
61*10465441SEvalZero if (sym)
62*10465441SEvalZero menu_add_symbol(P_SYMBOL, sym, NULL);
63*10465441SEvalZero }
64*10465441SEvalZero
menu_end_entry(void)65*10465441SEvalZero void menu_end_entry(void)
66*10465441SEvalZero {
67*10465441SEvalZero }
68*10465441SEvalZero
menu_add_menu(void)69*10465441SEvalZero struct menu *menu_add_menu(void)
70*10465441SEvalZero {
71*10465441SEvalZero menu_end_entry();
72*10465441SEvalZero last_entry_ptr = ¤t_entry->list;
73*10465441SEvalZero return current_menu = current_entry;
74*10465441SEvalZero }
75*10465441SEvalZero
menu_end_menu(void)76*10465441SEvalZero void menu_end_menu(void)
77*10465441SEvalZero {
78*10465441SEvalZero last_entry_ptr = ¤t_menu->next;
79*10465441SEvalZero current_menu = current_menu->parent;
80*10465441SEvalZero }
81*10465441SEvalZero
menu_check_dep(struct expr * e)82*10465441SEvalZero static struct expr *menu_check_dep(struct expr *e)
83*10465441SEvalZero {
84*10465441SEvalZero if (!e)
85*10465441SEvalZero return e;
86*10465441SEvalZero
87*10465441SEvalZero switch (e->type) {
88*10465441SEvalZero case E_NOT:
89*10465441SEvalZero e->left.expr = menu_check_dep(e->left.expr);
90*10465441SEvalZero break;
91*10465441SEvalZero case E_OR:
92*10465441SEvalZero case E_AND:
93*10465441SEvalZero e->left.expr = menu_check_dep(e->left.expr);
94*10465441SEvalZero e->right.expr = menu_check_dep(e->right.expr);
95*10465441SEvalZero break;
96*10465441SEvalZero case E_SYMBOL:
97*10465441SEvalZero /* change 'm' into 'm' && MODULES */
98*10465441SEvalZero if (e->left.sym == &symbol_mod)
99*10465441SEvalZero return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
100*10465441SEvalZero break;
101*10465441SEvalZero default:
102*10465441SEvalZero break;
103*10465441SEvalZero }
104*10465441SEvalZero return e;
105*10465441SEvalZero }
106*10465441SEvalZero
menu_add_dep(struct expr * dep)107*10465441SEvalZero void menu_add_dep(struct expr *dep)
108*10465441SEvalZero {
109*10465441SEvalZero current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
110*10465441SEvalZero }
111*10465441SEvalZero
menu_set_type(int type)112*10465441SEvalZero void menu_set_type(int type)
113*10465441SEvalZero {
114*10465441SEvalZero struct symbol *sym = current_entry->sym;
115*10465441SEvalZero
116*10465441SEvalZero if (sym->type == type)
117*10465441SEvalZero return;
118*10465441SEvalZero if (sym->type == S_UNKNOWN) {
119*10465441SEvalZero sym->type = type;
120*10465441SEvalZero return;
121*10465441SEvalZero }
122*10465441SEvalZero menu_warn(current_entry,
123*10465441SEvalZero "ignoring type redefinition of '%s' from '%s' to '%s'",
124*10465441SEvalZero sym->name ? sym->name : "<choice>",
125*10465441SEvalZero sym_type_name(sym->type), sym_type_name(type));
126*10465441SEvalZero }
127*10465441SEvalZero
menu_add_prop(enum prop_type type,char * prompt,struct expr * expr,struct expr * dep)128*10465441SEvalZero static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
129*10465441SEvalZero {
130*10465441SEvalZero struct property *prop = prop_alloc(type, current_entry->sym);
131*10465441SEvalZero
132*10465441SEvalZero prop->menu = current_entry;
133*10465441SEvalZero prop->expr = expr;
134*10465441SEvalZero prop->visible.expr = menu_check_dep(dep);
135*10465441SEvalZero
136*10465441SEvalZero if (prompt) {
137*10465441SEvalZero if (isspace(*prompt)) {
138*10465441SEvalZero prop_warn(prop, "leading whitespace ignored");
139*10465441SEvalZero while (isspace(*prompt))
140*10465441SEvalZero prompt++;
141*10465441SEvalZero }
142*10465441SEvalZero if (current_entry->prompt && current_entry != &rootmenu)
143*10465441SEvalZero prop_warn(prop, "prompt redefined");
144*10465441SEvalZero
145*10465441SEvalZero /* Apply all upper menus' visibilities to actual prompts. */
146*10465441SEvalZero if(type == P_PROMPT) {
147*10465441SEvalZero struct menu *menu = current_entry;
148*10465441SEvalZero
149*10465441SEvalZero while ((menu = menu->parent) != NULL) {
150*10465441SEvalZero struct expr *dup_expr;
151*10465441SEvalZero
152*10465441SEvalZero if (!menu->visibility)
153*10465441SEvalZero continue;
154*10465441SEvalZero /*
155*10465441SEvalZero * Do not add a reference to the
156*10465441SEvalZero * menu's visibility expression but
157*10465441SEvalZero * use a copy of it. Otherwise the
158*10465441SEvalZero * expression reduction functions
159*10465441SEvalZero * will modify expressions that have
160*10465441SEvalZero * multiple references which can
161*10465441SEvalZero * cause unwanted side effects.
162*10465441SEvalZero */
163*10465441SEvalZero dup_expr = expr_copy(menu->visibility);
164*10465441SEvalZero
165*10465441SEvalZero prop->visible.expr
166*10465441SEvalZero = expr_alloc_and(prop->visible.expr,
167*10465441SEvalZero dup_expr);
168*10465441SEvalZero }
169*10465441SEvalZero }
170*10465441SEvalZero
171*10465441SEvalZero current_entry->prompt = prop;
172*10465441SEvalZero }
173*10465441SEvalZero prop->text = prompt;
174*10465441SEvalZero
175*10465441SEvalZero return prop;
176*10465441SEvalZero }
177*10465441SEvalZero
menu_add_prompt(enum prop_type type,char * prompt,struct expr * dep)178*10465441SEvalZero struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
179*10465441SEvalZero {
180*10465441SEvalZero return menu_add_prop(type, prompt, NULL, dep);
181*10465441SEvalZero }
182*10465441SEvalZero
menu_add_visibility(struct expr * expr)183*10465441SEvalZero void menu_add_visibility(struct expr *expr)
184*10465441SEvalZero {
185*10465441SEvalZero current_entry->visibility = expr_alloc_and(current_entry->visibility,
186*10465441SEvalZero expr);
187*10465441SEvalZero }
188*10465441SEvalZero
menu_add_expr(enum prop_type type,struct expr * expr,struct expr * dep)189*10465441SEvalZero void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
190*10465441SEvalZero {
191*10465441SEvalZero menu_add_prop(type, NULL, expr, dep);
192*10465441SEvalZero }
193*10465441SEvalZero
menu_add_symbol(enum prop_type type,struct symbol * sym,struct expr * dep)194*10465441SEvalZero void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
195*10465441SEvalZero {
196*10465441SEvalZero menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
197*10465441SEvalZero }
198*10465441SEvalZero
menu_add_option(int token,char * arg)199*10465441SEvalZero void menu_add_option(int token, char *arg)
200*10465441SEvalZero {
201*10465441SEvalZero switch (token) {
202*10465441SEvalZero case T_OPT_MODULES:
203*10465441SEvalZero if (modules_sym)
204*10465441SEvalZero zconf_error("symbol '%s' redefines option 'modules'"
205*10465441SEvalZero " already defined by symbol '%s'",
206*10465441SEvalZero current_entry->sym->name,
207*10465441SEvalZero modules_sym->name
208*10465441SEvalZero );
209*10465441SEvalZero modules_sym = current_entry->sym;
210*10465441SEvalZero break;
211*10465441SEvalZero case T_OPT_DEFCONFIG_LIST:
212*10465441SEvalZero if (!sym_defconfig_list)
213*10465441SEvalZero sym_defconfig_list = current_entry->sym;
214*10465441SEvalZero else if (sym_defconfig_list != current_entry->sym)
215*10465441SEvalZero zconf_error("trying to redefine defconfig symbol");
216*10465441SEvalZero break;
217*10465441SEvalZero case T_OPT_ENV:
218*10465441SEvalZero prop_add_env(arg);
219*10465441SEvalZero break;
220*10465441SEvalZero case T_OPT_ALLNOCONFIG_Y:
221*10465441SEvalZero current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
222*10465441SEvalZero break;
223*10465441SEvalZero }
224*10465441SEvalZero }
225*10465441SEvalZero
menu_validate_number(struct symbol * sym,struct symbol * sym2)226*10465441SEvalZero static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
227*10465441SEvalZero {
228*10465441SEvalZero return sym2->type == S_INT || sym2->type == S_HEX ||
229*10465441SEvalZero (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
230*10465441SEvalZero }
231*10465441SEvalZero
sym_check_prop(struct symbol * sym)232*10465441SEvalZero static void sym_check_prop(struct symbol *sym)
233*10465441SEvalZero {
234*10465441SEvalZero struct property *prop;
235*10465441SEvalZero struct symbol *sym2;
236*10465441SEvalZero char *use;
237*10465441SEvalZero
238*10465441SEvalZero for (prop = sym->prop; prop; prop = prop->next) {
239*10465441SEvalZero switch (prop->type) {
240*10465441SEvalZero case P_DEFAULT:
241*10465441SEvalZero if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
242*10465441SEvalZero prop->expr->type != E_SYMBOL)
243*10465441SEvalZero prop_warn(prop,
244*10465441SEvalZero "default for config symbol '%s'"
245*10465441SEvalZero " must be a single symbol", sym->name);
246*10465441SEvalZero if (prop->expr->type != E_SYMBOL)
247*10465441SEvalZero break;
248*10465441SEvalZero sym2 = prop_get_symbol(prop);
249*10465441SEvalZero if (sym->type == S_HEX || sym->type == S_INT) {
250*10465441SEvalZero if (!menu_validate_number(sym, sym2))
251*10465441SEvalZero prop_warn(prop,
252*10465441SEvalZero "'%s': number is invalid",
253*10465441SEvalZero sym->name);
254*10465441SEvalZero }
255*10465441SEvalZero break;
256*10465441SEvalZero case P_SELECT:
257*10465441SEvalZero case P_IMPLY:
258*10465441SEvalZero use = prop->type == P_SELECT ? "select" : "imply";
259*10465441SEvalZero sym2 = prop_get_symbol(prop);
260*10465441SEvalZero if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
261*10465441SEvalZero prop_warn(prop,
262*10465441SEvalZero "config symbol '%s' uses %s, but is "
263*10465441SEvalZero "not boolean or tristate", sym->name, use);
264*10465441SEvalZero else if (sym2->type != S_UNKNOWN &&
265*10465441SEvalZero sym2->type != S_BOOLEAN &&
266*10465441SEvalZero sym2->type != S_TRISTATE)
267*10465441SEvalZero prop_warn(prop,
268*10465441SEvalZero "'%s' has wrong type. '%s' only "
269*10465441SEvalZero "accept arguments of boolean and "
270*10465441SEvalZero "tristate type", sym2->name, use);
271*10465441SEvalZero break;
272*10465441SEvalZero case P_RANGE:
273*10465441SEvalZero if (sym->type != S_INT && sym->type != S_HEX)
274*10465441SEvalZero prop_warn(prop, "range is only allowed "
275*10465441SEvalZero "for int or hex symbols");
276*10465441SEvalZero if (!menu_validate_number(sym, prop->expr->left.sym) ||
277*10465441SEvalZero !menu_validate_number(sym, prop->expr->right.sym))
278*10465441SEvalZero prop_warn(prop, "range is invalid");
279*10465441SEvalZero break;
280*10465441SEvalZero default:
281*10465441SEvalZero ;
282*10465441SEvalZero }
283*10465441SEvalZero }
284*10465441SEvalZero }
285*10465441SEvalZero
menu_finalize(struct menu * parent)286*10465441SEvalZero void menu_finalize(struct menu *parent)
287*10465441SEvalZero {
288*10465441SEvalZero struct menu *menu, *last_menu;
289*10465441SEvalZero struct symbol *sym;
290*10465441SEvalZero struct property *prop;
291*10465441SEvalZero struct expr *parentdep, *basedep, *dep, *dep2, **ep;
292*10465441SEvalZero
293*10465441SEvalZero sym = parent->sym;
294*10465441SEvalZero if (parent->list) {
295*10465441SEvalZero if (sym && sym_is_choice(sym)) {
296*10465441SEvalZero if (sym->type == S_UNKNOWN) {
297*10465441SEvalZero /* find the first choice value to find out choice type */
298*10465441SEvalZero current_entry = parent;
299*10465441SEvalZero for (menu = parent->list; menu; menu = menu->next) {
300*10465441SEvalZero if (menu->sym && menu->sym->type != S_UNKNOWN) {
301*10465441SEvalZero menu_set_type(menu->sym->type);
302*10465441SEvalZero break;
303*10465441SEvalZero }
304*10465441SEvalZero }
305*10465441SEvalZero }
306*10465441SEvalZero /* set the type of the remaining choice values */
307*10465441SEvalZero for (menu = parent->list; menu; menu = menu->next) {
308*10465441SEvalZero current_entry = menu;
309*10465441SEvalZero if (menu->sym && menu->sym->type == S_UNKNOWN)
310*10465441SEvalZero menu_set_type(sym->type);
311*10465441SEvalZero }
312*10465441SEvalZero parentdep = expr_alloc_symbol(sym);
313*10465441SEvalZero } else if (parent->prompt)
314*10465441SEvalZero parentdep = parent->prompt->visible.expr;
315*10465441SEvalZero else
316*10465441SEvalZero parentdep = parent->dep;
317*10465441SEvalZero
318*10465441SEvalZero for (menu = parent->list; menu; menu = menu->next) {
319*10465441SEvalZero basedep = expr_transform(menu->dep);
320*10465441SEvalZero basedep = expr_alloc_and(expr_copy(parentdep), basedep);
321*10465441SEvalZero basedep = expr_eliminate_dups(basedep);
322*10465441SEvalZero menu->dep = basedep;
323*10465441SEvalZero if (menu->sym)
324*10465441SEvalZero prop = menu->sym->prop;
325*10465441SEvalZero else
326*10465441SEvalZero prop = menu->prompt;
327*10465441SEvalZero for (; prop; prop = prop->next) {
328*10465441SEvalZero if (prop->menu != menu)
329*10465441SEvalZero continue;
330*10465441SEvalZero dep = expr_transform(prop->visible.expr);
331*10465441SEvalZero dep = expr_alloc_and(expr_copy(basedep), dep);
332*10465441SEvalZero dep = expr_eliminate_dups(dep);
333*10465441SEvalZero if (menu->sym && menu->sym->type != S_TRISTATE)
334*10465441SEvalZero dep = expr_trans_bool(dep);
335*10465441SEvalZero prop->visible.expr = dep;
336*10465441SEvalZero if (prop->type == P_SELECT) {
337*10465441SEvalZero struct symbol *es = prop_get_symbol(prop);
338*10465441SEvalZero es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
339*10465441SEvalZero expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
340*10465441SEvalZero } else if (prop->type == P_IMPLY) {
341*10465441SEvalZero struct symbol *es = prop_get_symbol(prop);
342*10465441SEvalZero es->implied.expr = expr_alloc_or(es->implied.expr,
343*10465441SEvalZero expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
344*10465441SEvalZero }
345*10465441SEvalZero }
346*10465441SEvalZero }
347*10465441SEvalZero for (menu = parent->list; menu; menu = menu->next)
348*10465441SEvalZero menu_finalize(menu);
349*10465441SEvalZero } else if (sym) {
350*10465441SEvalZero basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
351*10465441SEvalZero basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
352*10465441SEvalZero basedep = expr_eliminate_dups(expr_transform(basedep));
353*10465441SEvalZero last_menu = NULL;
354*10465441SEvalZero for (menu = parent->next; menu; menu = menu->next) {
355*10465441SEvalZero dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
356*10465441SEvalZero if (!expr_contains_symbol(dep, sym))
357*10465441SEvalZero break;
358*10465441SEvalZero if (expr_depends_symbol(dep, sym))
359*10465441SEvalZero goto next;
360*10465441SEvalZero dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
361*10465441SEvalZero dep = expr_eliminate_dups(expr_transform(dep));
362*10465441SEvalZero dep2 = expr_copy(basedep);
363*10465441SEvalZero expr_eliminate_eq(&dep, &dep2);
364*10465441SEvalZero expr_free(dep);
365*10465441SEvalZero if (!expr_is_yes(dep2)) {
366*10465441SEvalZero expr_free(dep2);
367*10465441SEvalZero break;
368*10465441SEvalZero }
369*10465441SEvalZero expr_free(dep2);
370*10465441SEvalZero next:
371*10465441SEvalZero menu_finalize(menu);
372*10465441SEvalZero menu->parent = parent;
373*10465441SEvalZero last_menu = menu;
374*10465441SEvalZero }
375*10465441SEvalZero if (last_menu) {
376*10465441SEvalZero parent->list = parent->next;
377*10465441SEvalZero parent->next = last_menu->next;
378*10465441SEvalZero last_menu->next = NULL;
379*10465441SEvalZero }
380*10465441SEvalZero
381*10465441SEvalZero sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
382*10465441SEvalZero }
383*10465441SEvalZero for (menu = parent->list; menu; menu = menu->next) {
384*10465441SEvalZero if (sym && sym_is_choice(sym) &&
385*10465441SEvalZero menu->sym && !sym_is_choice_value(menu->sym)) {
386*10465441SEvalZero current_entry = menu;
387*10465441SEvalZero menu->sym->flags |= SYMBOL_CHOICEVAL;
388*10465441SEvalZero if (!menu->prompt)
389*10465441SEvalZero menu_warn(menu, "choice value must have a prompt");
390*10465441SEvalZero for (prop = menu->sym->prop; prop; prop = prop->next) {
391*10465441SEvalZero if (prop->type == P_DEFAULT)
392*10465441SEvalZero prop_warn(prop, "defaults for choice "
393*10465441SEvalZero "values not supported");
394*10465441SEvalZero if (prop->menu == menu)
395*10465441SEvalZero continue;
396*10465441SEvalZero if (prop->type == P_PROMPT &&
397*10465441SEvalZero prop->menu->parent->sym != sym)
398*10465441SEvalZero prop_warn(prop, "choice value used outside its choice group");
399*10465441SEvalZero }
400*10465441SEvalZero /* Non-tristate choice values of tristate choices must
401*10465441SEvalZero * depend on the choice being set to Y. The choice
402*10465441SEvalZero * values' dependencies were propagated to their
403*10465441SEvalZero * properties above, so the change here must be re-
404*10465441SEvalZero * propagated.
405*10465441SEvalZero */
406*10465441SEvalZero if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
407*10465441SEvalZero basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
408*10465441SEvalZero menu->dep = expr_alloc_and(basedep, menu->dep);
409*10465441SEvalZero for (prop = menu->sym->prop; prop; prop = prop->next) {
410*10465441SEvalZero if (prop->menu != menu)
411*10465441SEvalZero continue;
412*10465441SEvalZero prop->visible.expr = expr_alloc_and(expr_copy(basedep),
413*10465441SEvalZero prop->visible.expr);
414*10465441SEvalZero }
415*10465441SEvalZero }
416*10465441SEvalZero menu_add_symbol(P_CHOICE, sym, NULL);
417*10465441SEvalZero prop = sym_get_choice_prop(sym);
418*10465441SEvalZero for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
419*10465441SEvalZero ;
420*10465441SEvalZero *ep = expr_alloc_one(E_LIST, NULL);
421*10465441SEvalZero (*ep)->right.sym = menu->sym;
422*10465441SEvalZero }
423*10465441SEvalZero if (menu->list && (!menu->prompt || !menu->prompt->text)) {
424*10465441SEvalZero for (last_menu = menu->list; ; last_menu = last_menu->next) {
425*10465441SEvalZero last_menu->parent = parent;
426*10465441SEvalZero if (!last_menu->next)
427*10465441SEvalZero break;
428*10465441SEvalZero }
429*10465441SEvalZero last_menu->next = menu->next;
430*10465441SEvalZero menu->next = menu->list;
431*10465441SEvalZero menu->list = NULL;
432*10465441SEvalZero }
433*10465441SEvalZero }
434*10465441SEvalZero
435*10465441SEvalZero if (sym && !(sym->flags & SYMBOL_WARNED)) {
436*10465441SEvalZero if (sym->type == S_UNKNOWN)
437*10465441SEvalZero menu_warn(parent, "config symbol defined without type");
438*10465441SEvalZero
439*10465441SEvalZero if (sym_is_choice(sym) && !parent->prompt)
440*10465441SEvalZero menu_warn(parent, "choice must have a prompt");
441*10465441SEvalZero
442*10465441SEvalZero /* Check properties connected to this symbol */
443*10465441SEvalZero sym_check_prop(sym);
444*10465441SEvalZero sym->flags |= SYMBOL_WARNED;
445*10465441SEvalZero }
446*10465441SEvalZero
447*10465441SEvalZero if (sym && !sym_is_optional(sym) && parent->prompt) {
448*10465441SEvalZero sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
449*10465441SEvalZero expr_alloc_and(parent->prompt->visible.expr,
450*10465441SEvalZero expr_alloc_symbol(&symbol_mod)));
451*10465441SEvalZero }
452*10465441SEvalZero }
453*10465441SEvalZero
menu_has_prompt(struct menu * menu)454*10465441SEvalZero bool menu_has_prompt(struct menu *menu)
455*10465441SEvalZero {
456*10465441SEvalZero if (!menu->prompt)
457*10465441SEvalZero return false;
458*10465441SEvalZero return true;
459*10465441SEvalZero }
460*10465441SEvalZero
461*10465441SEvalZero /*
462*10465441SEvalZero * Determine if a menu is empty.
463*10465441SEvalZero * A menu is considered empty if it contains no or only
464*10465441SEvalZero * invisible entries.
465*10465441SEvalZero */
menu_is_empty(struct menu * menu)466*10465441SEvalZero bool menu_is_empty(struct menu *menu)
467*10465441SEvalZero {
468*10465441SEvalZero struct menu *child;
469*10465441SEvalZero
470*10465441SEvalZero for (child = menu->list; child; child = child->next) {
471*10465441SEvalZero if (menu_is_visible(child))
472*10465441SEvalZero return(false);
473*10465441SEvalZero }
474*10465441SEvalZero return(true);
475*10465441SEvalZero }
476*10465441SEvalZero
menu_is_visible(struct menu * menu)477*10465441SEvalZero bool menu_is_visible(struct menu *menu)
478*10465441SEvalZero {
479*10465441SEvalZero struct menu *child;
480*10465441SEvalZero struct symbol *sym;
481*10465441SEvalZero tristate visible;
482*10465441SEvalZero
483*10465441SEvalZero if (!menu->prompt)
484*10465441SEvalZero return false;
485*10465441SEvalZero
486*10465441SEvalZero if (menu->visibility) {
487*10465441SEvalZero if (expr_calc_value(menu->visibility) == no)
488*10465441SEvalZero return false;
489*10465441SEvalZero }
490*10465441SEvalZero
491*10465441SEvalZero sym = menu->sym;
492*10465441SEvalZero if (sym) {
493*10465441SEvalZero sym_calc_value(sym);
494*10465441SEvalZero visible = menu->prompt->visible.tri;
495*10465441SEvalZero } else
496*10465441SEvalZero visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
497*10465441SEvalZero
498*10465441SEvalZero if (visible != no)
499*10465441SEvalZero return true;
500*10465441SEvalZero
501*10465441SEvalZero if (!sym || sym_get_tristate_value(menu->sym) == no)
502*10465441SEvalZero return false;
503*10465441SEvalZero
504*10465441SEvalZero for (child = menu->list; child; child = child->next) {
505*10465441SEvalZero if (menu_is_visible(child)) {
506*10465441SEvalZero if (sym)
507*10465441SEvalZero sym->flags |= SYMBOL_DEF_USER;
508*10465441SEvalZero return true;
509*10465441SEvalZero }
510*10465441SEvalZero }
511*10465441SEvalZero
512*10465441SEvalZero return false;
513*10465441SEvalZero }
514*10465441SEvalZero
menu_get_prompt(struct menu * menu)515*10465441SEvalZero const char *menu_get_prompt(struct menu *menu)
516*10465441SEvalZero {
517*10465441SEvalZero if (menu->prompt)
518*10465441SEvalZero return menu->prompt->text;
519*10465441SEvalZero else if (menu->sym)
520*10465441SEvalZero return menu->sym->name;
521*10465441SEvalZero return NULL;
522*10465441SEvalZero }
523*10465441SEvalZero
menu_get_root_menu(struct menu * menu)524*10465441SEvalZero struct menu *menu_get_root_menu(struct menu *menu)
525*10465441SEvalZero {
526*10465441SEvalZero return &rootmenu;
527*10465441SEvalZero }
528*10465441SEvalZero
menu_get_parent_menu(struct menu * menu)529*10465441SEvalZero struct menu *menu_get_parent_menu(struct menu *menu)
530*10465441SEvalZero {
531*10465441SEvalZero enum prop_type type;
532*10465441SEvalZero
533*10465441SEvalZero for (; menu != &rootmenu; menu = menu->parent) {
534*10465441SEvalZero type = menu->prompt ? menu->prompt->type : 0;
535*10465441SEvalZero if (type == P_MENU)
536*10465441SEvalZero break;
537*10465441SEvalZero }
538*10465441SEvalZero return menu;
539*10465441SEvalZero }
540*10465441SEvalZero
menu_has_help(struct menu * menu)541*10465441SEvalZero bool menu_has_help(struct menu *menu)
542*10465441SEvalZero {
543*10465441SEvalZero return menu->help != NULL;
544*10465441SEvalZero }
545*10465441SEvalZero
menu_get_help(struct menu * menu)546*10465441SEvalZero const char *menu_get_help(struct menu *menu)
547*10465441SEvalZero {
548*10465441SEvalZero if (menu->help)
549*10465441SEvalZero return menu->help;
550*10465441SEvalZero else
551*10465441SEvalZero return "";
552*10465441SEvalZero }
553*10465441SEvalZero
get_prompt_str(struct gstr * r,struct property * prop,struct list_head * head)554*10465441SEvalZero static void get_prompt_str(struct gstr *r, struct property *prop,
555*10465441SEvalZero struct list_head *head)
556*10465441SEvalZero {
557*10465441SEvalZero int i, j;
558*10465441SEvalZero struct menu *submenu[8], *menu, *location = NULL;
559*10465441SEvalZero struct jump_key *jump = NULL;
560*10465441SEvalZero
561*10465441SEvalZero str_printf(r, _("Prompt: %s\n"), _(prop->text));
562*10465441SEvalZero menu = prop->menu->parent;
563*10465441SEvalZero for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
564*10465441SEvalZero bool accessible = menu_is_visible(menu);
565*10465441SEvalZero
566*10465441SEvalZero submenu[i++] = menu;
567*10465441SEvalZero if (location == NULL && accessible)
568*10465441SEvalZero location = menu;
569*10465441SEvalZero }
570*10465441SEvalZero if (head && location) {
571*10465441SEvalZero jump = xmalloc(sizeof(struct jump_key));
572*10465441SEvalZero
573*10465441SEvalZero if (menu_is_visible(prop->menu)) {
574*10465441SEvalZero /*
575*10465441SEvalZero * There is not enough room to put the hint at the
576*10465441SEvalZero * beginning of the "Prompt" line. Put the hint on the
577*10465441SEvalZero * last "Location" line even when it would belong on
578*10465441SEvalZero * the former.
579*10465441SEvalZero */
580*10465441SEvalZero jump->target = prop->menu;
581*10465441SEvalZero } else
582*10465441SEvalZero jump->target = location;
583*10465441SEvalZero
584*10465441SEvalZero if (list_empty(head))
585*10465441SEvalZero jump->index = 0;
586*10465441SEvalZero else
587*10465441SEvalZero jump->index = list_entry(head->prev, struct jump_key,
588*10465441SEvalZero entries)->index + 1;
589*10465441SEvalZero
590*10465441SEvalZero list_add_tail(&jump->entries, head);
591*10465441SEvalZero }
592*10465441SEvalZero
593*10465441SEvalZero if (i > 0) {
594*10465441SEvalZero str_printf(r, _(" Location:\n"));
595*10465441SEvalZero for (j = 4; --i >= 0; j += 2) {
596*10465441SEvalZero menu = submenu[i];
597*10465441SEvalZero if (jump && menu == location)
598*10465441SEvalZero jump->offset = strlen(r->s);
599*10465441SEvalZero str_printf(r, "%*c-> %s", j, ' ',
600*10465441SEvalZero _(menu_get_prompt(menu)));
601*10465441SEvalZero if (menu->sym) {
602*10465441SEvalZero str_printf(r, " (%s [=%s])", menu->sym->name ?
603*10465441SEvalZero menu->sym->name : _("<choice>"),
604*10465441SEvalZero sym_get_string_value(menu->sym));
605*10465441SEvalZero }
606*10465441SEvalZero str_append(r, "\n");
607*10465441SEvalZero }
608*10465441SEvalZero }
609*10465441SEvalZero }
610*10465441SEvalZero
611*10465441SEvalZero /*
612*10465441SEvalZero * get property of type P_SYMBOL
613*10465441SEvalZero */
get_symbol_prop(struct symbol * sym)614*10465441SEvalZero static struct property *get_symbol_prop(struct symbol *sym)
615*10465441SEvalZero {
616*10465441SEvalZero struct property *prop = NULL;
617*10465441SEvalZero
618*10465441SEvalZero for_all_properties(sym, prop, P_SYMBOL)
619*10465441SEvalZero break;
620*10465441SEvalZero return prop;
621*10465441SEvalZero }
622*10465441SEvalZero
get_symbol_props_str(struct gstr * r,struct symbol * sym,enum prop_type tok,const char * prefix)623*10465441SEvalZero static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
624*10465441SEvalZero enum prop_type tok, const char *prefix)
625*10465441SEvalZero {
626*10465441SEvalZero bool hit = false;
627*10465441SEvalZero struct property *prop;
628*10465441SEvalZero
629*10465441SEvalZero for_all_properties(sym, prop, tok) {
630*10465441SEvalZero if (!hit) {
631*10465441SEvalZero str_append(r, prefix);
632*10465441SEvalZero hit = true;
633*10465441SEvalZero } else
634*10465441SEvalZero str_printf(r, " && ");
635*10465441SEvalZero expr_gstr_print(prop->expr, r);
636*10465441SEvalZero }
637*10465441SEvalZero if (hit)
638*10465441SEvalZero str_append(r, "\n");
639*10465441SEvalZero }
640*10465441SEvalZero
641*10465441SEvalZero /*
642*10465441SEvalZero * head is optional and may be NULL
643*10465441SEvalZero */
get_symbol_str(struct gstr * r,struct symbol * sym,struct list_head * head)644*10465441SEvalZero static void get_symbol_str(struct gstr *r, struct symbol *sym,
645*10465441SEvalZero struct list_head *head)
646*10465441SEvalZero {
647*10465441SEvalZero struct property *prop;
648*10465441SEvalZero
649*10465441SEvalZero if (sym && sym->name) {
650*10465441SEvalZero str_printf(r, "Symbol: %s [=%s]\n", sym->name,
651*10465441SEvalZero sym_get_string_value(sym));
652*10465441SEvalZero str_printf(r, "Type : %s\n", sym_type_name(sym->type));
653*10465441SEvalZero if (sym->type == S_INT || sym->type == S_HEX) {
654*10465441SEvalZero prop = sym_get_range_prop(sym);
655*10465441SEvalZero if (prop) {
656*10465441SEvalZero str_printf(r, "Range : ");
657*10465441SEvalZero expr_gstr_print(prop->expr, r);
658*10465441SEvalZero str_append(r, "\n");
659*10465441SEvalZero }
660*10465441SEvalZero }
661*10465441SEvalZero }
662*10465441SEvalZero for_all_prompts(sym, prop)
663*10465441SEvalZero get_prompt_str(r, prop, head);
664*10465441SEvalZero
665*10465441SEvalZero prop = get_symbol_prop(sym);
666*10465441SEvalZero if (prop) {
667*10465441SEvalZero str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
668*10465441SEvalZero prop->menu->lineno);
669*10465441SEvalZero if (!expr_is_yes(prop->visible.expr)) {
670*10465441SEvalZero str_append(r, _(" Depends on: "));
671*10465441SEvalZero expr_gstr_print(prop->visible.expr, r);
672*10465441SEvalZero str_append(r, "\n");
673*10465441SEvalZero }
674*10465441SEvalZero }
675*10465441SEvalZero
676*10465441SEvalZero get_symbol_props_str(r, sym, P_SELECT, _(" Selects: "));
677*10465441SEvalZero if (sym->rev_dep.expr) {
678*10465441SEvalZero str_append(r, _(" Selected by: "));
679*10465441SEvalZero expr_gstr_print(sym->rev_dep.expr, r);
680*10465441SEvalZero str_append(r, "\n");
681*10465441SEvalZero }
682*10465441SEvalZero
683*10465441SEvalZero get_symbol_props_str(r, sym, P_IMPLY, _(" Implies: "));
684*10465441SEvalZero if (sym->implied.expr) {
685*10465441SEvalZero str_append(r, _(" Implied by: "));
686*10465441SEvalZero expr_gstr_print(sym->implied.expr, r);
687*10465441SEvalZero str_append(r, "\n");
688*10465441SEvalZero }
689*10465441SEvalZero
690*10465441SEvalZero str_append(r, "\n\n");
691*10465441SEvalZero }
692*10465441SEvalZero
get_relations_str(struct symbol ** sym_arr,struct list_head * head)693*10465441SEvalZero struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
694*10465441SEvalZero {
695*10465441SEvalZero struct symbol *sym;
696*10465441SEvalZero struct gstr res = str_new();
697*10465441SEvalZero int i;
698*10465441SEvalZero
699*10465441SEvalZero for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
700*10465441SEvalZero get_symbol_str(&res, sym, head);
701*10465441SEvalZero if (!i)
702*10465441SEvalZero str_append(&res, _("No matches found.\n"));
703*10465441SEvalZero return res;
704*10465441SEvalZero }
705*10465441SEvalZero
706*10465441SEvalZero
menu_get_ext_help(struct menu * menu,struct gstr * help)707*10465441SEvalZero void menu_get_ext_help(struct menu *menu, struct gstr *help)
708*10465441SEvalZero {
709*10465441SEvalZero struct symbol *sym = menu->sym;
710*10465441SEvalZero const char *help_text = nohelp_text;
711*10465441SEvalZero
712*10465441SEvalZero if (menu_has_help(menu)) {
713*10465441SEvalZero if (sym->name)
714*10465441SEvalZero str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
715*10465441SEvalZero help_text = menu_get_help(menu);
716*10465441SEvalZero }
717*10465441SEvalZero str_printf(help, "%s\n", _(help_text));
718*10465441SEvalZero if (sym)
719*10465441SEvalZero get_symbol_str(help, sym, NULL);
720*10465441SEvalZero }
721