^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "lkc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static const char nohelp_text[] = "There is no help available for this option.";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) struct menu rootmenu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static struct menu **last_entry_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct file *file_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct file *current_file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) void menu_warn(struct menu *menu, const char *fmt, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) va_list ap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) va_start(ap, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) vfprintf(stderr, fmt, ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) fprintf(stderr, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) va_end(ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static void prop_warn(struct property *prop, const char *fmt, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) va_list ap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) va_start(ap, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) vfprintf(stderr, fmt, ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) fprintf(stderr, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) va_end(ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) void _menu_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) current_entry = current_menu = &rootmenu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) last_entry_ptr = &rootmenu.list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) void menu_add_entry(struct symbol *sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct menu *menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) menu = xmalloc(sizeof(*menu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) memset(menu, 0, sizeof(*menu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) menu->sym = sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) menu->parent = current_menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) menu->file = current_file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) menu->lineno = zconf_lineno();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *last_entry_ptr = menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) last_entry_ptr = &menu->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) current_entry = menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) menu_add_symbol(P_SYMBOL, sym, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct menu *menu_add_menu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) last_entry_ptr = ¤t_entry->list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) current_menu = current_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return current_menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) void menu_end_menu(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) last_entry_ptr = ¤t_menu->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) current_menu = current_menu->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * without modules
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static struct expr *rewrite_m(struct expr *e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (!e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) switch (e->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) case E_NOT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) e->left.expr = rewrite_m(e->left.expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case E_OR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) case E_AND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) e->left.expr = rewrite_m(e->left.expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) e->right.expr = rewrite_m(e->right.expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case E_SYMBOL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* change 'm' into 'm' && MODULES */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (e->left.sym == &symbol_mod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) void menu_add_dep(struct expr *dep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) current_entry->dep = expr_alloc_and(current_entry->dep, dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) void menu_set_type(int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct symbol *sym = current_entry->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (sym->type == type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (sym->type == S_UNKNOWN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) sym->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) menu_warn(current_entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) "ignoring type redefinition of '%s' from '%s' to '%s'",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) sym->name ? sym->name : "<choice>",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) sym_type_name(sym->type), sym_type_name(type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static struct property *menu_add_prop(enum prop_type type, struct expr *expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct expr *dep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) prop = xmalloc(sizeof(*prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) memset(prop, 0, sizeof(*prop));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) prop->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) prop->file = current_file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) prop->lineno = zconf_lineno();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) prop->menu = current_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) prop->expr = expr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) prop->visible.expr = dep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) /* append property to the prop list of symbol */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (current_entry->sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct property **propp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) for (propp = ¤t_entry->sym->prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) *propp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) propp = &(*propp)->next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) *propp = prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct property *menu_add_prompt(enum prop_type type, char *prompt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct expr *dep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct property *prop = menu_add_prop(type, NULL, dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (isspace(*prompt)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) prop_warn(prop, "leading whitespace ignored");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) while (isspace(*prompt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) prompt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (current_entry->prompt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) prop_warn(prop, "prompt redefined");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* Apply all upper menus' visibilities to actual prompts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (type == P_PROMPT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct menu *menu = current_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) while ((menu = menu->parent) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct expr *dup_expr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (!menu->visibility)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * Do not add a reference to the menu's visibility
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * expression but use a copy of it. Otherwise the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * expression reduction functions will modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * expressions that have multiple references which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * can cause unwanted side effects.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) dup_expr = expr_copy(menu->visibility);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) prop->visible.expr = expr_alloc_and(prop->visible.expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) dup_expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) current_entry->prompt = prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) prop->text = prompt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) void menu_add_visibility(struct expr *expr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) current_entry->visibility = expr_alloc_and(current_entry->visibility,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) menu_add_prop(type, expr, dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) menu_add_prop(type, expr_alloc_symbol(sym), dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) void menu_add_option_modules(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (modules_sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) current_entry->sym->name, modules_sym->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) modules_sym = current_entry->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) void menu_add_option_defconfig_list(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (!sym_defconfig_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) sym_defconfig_list = current_entry->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) else if (sym_defconfig_list != current_entry->sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) zconf_error("trying to redefine defconfig symbol");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) sym_defconfig_list->flags |= SYMBOL_NO_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) void menu_add_option_allnoconfig_y(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return sym2->type == S_INT || sym2->type == S_HEX ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static void sym_check_prop(struct symbol *sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct symbol *sym2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) char *use;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) for (prop = sym->prop; prop; prop = prop->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) switch (prop->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case P_DEFAULT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) prop->expr->type != E_SYMBOL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) prop_warn(prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) "default for config symbol '%s'"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) " must be a single symbol", sym->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (prop->expr->type != E_SYMBOL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) sym2 = prop_get_symbol(prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (sym->type == S_HEX || sym->type == S_INT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (!menu_validate_number(sym, sym2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) prop_warn(prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) "'%s': number is invalid",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) sym->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (sym_is_choice(sym)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct property *choice_prop =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) sym_get_choice_prop(sym2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (!choice_prop ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) prop_get_symbol(choice_prop) != sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) prop_warn(prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) "choice default symbol '%s' is not contained in the choice",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) sym2->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) case P_SELECT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) case P_IMPLY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) use = prop->type == P_SELECT ? "select" : "imply";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) sym2 = prop_get_symbol(prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) prop_warn(prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) "config symbol '%s' uses %s, but is "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) "not bool or tristate", sym->name, use);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) else if (sym2->type != S_UNKNOWN &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) sym2->type != S_BOOLEAN &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) sym2->type != S_TRISTATE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) prop_warn(prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) "'%s' has wrong type. '%s' only "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) "accept arguments of bool and "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) "tristate type", sym2->name, use);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) case P_RANGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (sym->type != S_INT && sym->type != S_HEX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) prop_warn(prop, "range is only allowed "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) "for int or hex symbols");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (!menu_validate_number(sym, prop->expr->left.sym) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) !menu_validate_number(sym, prop->expr->right.sym))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) prop_warn(prop, "range is invalid");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) void menu_finalize(struct menu *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) struct menu *menu, *last_menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) struct symbol *sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct expr *parentdep, *basedep, *dep, *dep2, **ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) sym = parent->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (parent->list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * This menu node has children. We (recursively) process them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * and propagate parent dependencies before moving on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (sym && sym_is_choice(sym)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (sym->type == S_UNKNOWN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) /* find the first choice value to find out choice type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) current_entry = parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) for (menu = parent->list; menu; menu = menu->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (menu->sym && menu->sym->type != S_UNKNOWN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) menu_set_type(menu->sym->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) /* set the type of the remaining choice values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) for (menu = parent->list; menu; menu = menu->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) current_entry = menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (menu->sym && menu->sym->type == S_UNKNOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) menu_set_type(sym->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * Use the choice itself as the parent dependency of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * the contained items. This turns the mode of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * choice into an upper bound on the visibility of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * choice value symbols.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) parentdep = expr_alloc_symbol(sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /* Menu node for 'menu', 'if' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) parentdep = parent->dep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /* For each child menu node... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) for (menu = parent->list; menu; menu = menu->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) * Propagate parent dependencies to the child menu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * node, also rewriting and simplifying expressions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) basedep = rewrite_m(menu->dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) basedep = expr_transform(basedep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) basedep = expr_alloc_and(expr_copy(parentdep), basedep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) basedep = expr_eliminate_dups(basedep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) menu->dep = basedep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (menu->sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) * Note: For symbols, all prompts are included
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * too in the symbol's own property list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) prop = menu->sym->prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * For non-symbol menu nodes, we just need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * handle the prompt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) prop = menu->prompt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* For each property... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) for (; prop; prop = prop->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (prop->menu != menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * Two possibilities:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * 1. The property lacks dependencies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * and so isn't location-specific,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * e.g. an 'option'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * 2. The property belongs to a symbol
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * defined in multiple locations and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * is from some other location. It
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * will be handled there in that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * case.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * Skip the property.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * Propagate parent dependencies to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * property's condition, rewriting and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * simplifying expressions at the same time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) dep = rewrite_m(prop->visible.expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) dep = expr_transform(dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) dep = expr_alloc_and(expr_copy(basedep), dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) dep = expr_eliminate_dups(dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (menu->sym && menu->sym->type != S_TRISTATE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) dep = expr_trans_bool(dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) prop->visible.expr = dep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * Handle selects and implies, which modify the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * dependencies of the selected/implied symbol
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (prop->type == P_SELECT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) struct symbol *es = prop_get_symbol(prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) } else if (prop->type == P_IMPLY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct symbol *es = prop_get_symbol(prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) es->implied.expr = expr_alloc_or(es->implied.expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (sym && sym_is_choice(sym))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) expr_free(parentdep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * Recursively process children in the same fashion before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * moving on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) for (menu = parent->list; menu; menu = menu->next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) menu_finalize(menu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) } else if (sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * Automatic submenu creation. If sym is a symbol and A, B, C,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * ... are consecutive items (symbols, menus, ifs, etc.) that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * all depend on sym, then the following menu structure is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * created:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * sym
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * +-A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) * +-B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) * +-C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * This also works recursively, giving the following structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * if A is a symbol and B depends on A:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * sym
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * +-A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * | +-B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * +-C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * ...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) basedep = expr_eliminate_dups(expr_transform(basedep));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) /* Examine consecutive elements after sym */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) last_menu = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) for (menu = parent->next; menu; menu = menu->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (!expr_contains_symbol(dep, sym))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /* No dependency, quit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (expr_depends_symbol(dep, sym))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* Absolute dependency, put in submenu */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) goto next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * Also consider it a dependency on sym if our
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) * dependencies contain sym and are a "superset" of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) * sym's dependencies, e.g. '(sym || Q) && R' when sym
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) * depends on R.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * Note that 'R' might be from an enclosing menu or if,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * making this a more common case than it might seem.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) dep = expr_eliminate_dups(expr_transform(dep));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) dep2 = expr_copy(basedep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) expr_eliminate_eq(&dep, &dep2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) expr_free(dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (!expr_is_yes(dep2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) /* Not superset, quit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) expr_free(dep2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /* Superset, put in submenu */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) expr_free(dep2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) next:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) menu_finalize(menu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) menu->parent = parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) last_menu = menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) expr_free(basedep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (last_menu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) parent->list = parent->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) parent->next = last_menu->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) last_menu->next = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) for (menu = parent->list; menu; menu = menu->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (sym && sym_is_choice(sym) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) menu->sym && !sym_is_choice_value(menu->sym)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) current_entry = menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) menu->sym->flags |= SYMBOL_CHOICEVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (!menu->prompt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) menu_warn(menu, "choice value must have a prompt");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) for (prop = menu->sym->prop; prop; prop = prop->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (prop->type == P_DEFAULT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) prop_warn(prop, "defaults for choice "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) "values not supported");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (prop->menu == menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) if (prop->type == P_PROMPT &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) prop->menu->parent->sym != sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) prop_warn(prop, "choice value used outside its choice group");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /* Non-tristate choice values of tristate choices must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * depend on the choice being set to Y. The choice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * values' dependencies were propagated to their
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * properties above, so the change here must be re-
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * propagated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) menu->dep = expr_alloc_and(basedep, menu->dep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) for (prop = menu->sym->prop; prop; prop = prop->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (prop->menu != menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) prop->visible.expr = expr_alloc_and(expr_copy(basedep),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) prop->visible.expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) menu_add_symbol(P_CHOICE, sym, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) prop = sym_get_choice_prop(sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) *ep = expr_alloc_one(E_LIST, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) (*ep)->right.sym = menu->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) * This code serves two purposes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * (1) Flattening 'if' blocks, which do not specify a submenu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) * and only add dependencies.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * (Automatic submenu creation might still create a submenu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * from an 'if' before this code runs.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * (2) "Undoing" any automatic submenus created earlier below
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * promptless symbols.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * Before:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * if ... (or promptless symbol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * +-B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * +-C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * D
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * After:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * if ... (or promptless symbol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) * B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) * D
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (menu->list && (!menu->prompt || !menu->prompt->text)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) for (last_menu = menu->list; ; last_menu = last_menu->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) last_menu->parent = parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (!last_menu->next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) last_menu->next = menu->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) menu->next = menu->list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) menu->list = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (sym && !(sym->flags & SYMBOL_WARNED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (sym->type == S_UNKNOWN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) menu_warn(parent, "config symbol defined without type");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) if (sym_is_choice(sym) && !parent->prompt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) menu_warn(parent, "choice must have a prompt");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) /* Check properties connected to this symbol */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) sym_check_prop(sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) sym->flags |= SYMBOL_WARNED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) * For non-optional choices, add a reverse dependency (corresponding to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) * a select) of '<visibility> && m'. This prevents the user from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) * setting the choice mode to 'n' when the choice is visible.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * This would also work for non-choice symbols, but only non-optional
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) * as a type of symbol.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (sym && !sym_is_optional(sym) && parent->prompt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) expr_alloc_and(parent->prompt->visible.expr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) expr_alloc_symbol(&symbol_mod)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) bool menu_has_prompt(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (!menu->prompt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * Determine if a menu is empty.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) * A menu is considered empty if it contains no or only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * invisible entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) bool menu_is_empty(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) struct menu *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) for (child = menu->list; child; child = child->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (menu_is_visible(child))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return(false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) return(true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) bool menu_is_visible(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) struct menu *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) struct symbol *sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) tristate visible;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (!menu->prompt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) if (menu->visibility) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (expr_calc_value(menu->visibility) == no)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) sym = menu->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) sym_calc_value(sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) visible = menu->prompt->visible.tri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (visible != no)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (!sym || sym_get_tristate_value(menu->sym) == no)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) for (child = menu->list; child; child = child->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) if (menu_is_visible(child)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) if (sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) sym->flags |= SYMBOL_DEF_USER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) const char *menu_get_prompt(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (menu->prompt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) return menu->prompt->text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) else if (menu->sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return menu->sym->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) struct menu *menu_get_root_menu(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) return &rootmenu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) struct menu *menu_get_parent_menu(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) enum prop_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) for (; menu != &rootmenu; menu = menu->parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) type = menu->prompt ? menu->prompt->type : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) if (type == P_MENU)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) return menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) bool menu_has_help(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) return menu->help != NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) const char *menu_get_help(struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (menu->help)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return menu->help;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static void get_def_str(struct gstr *r, struct menu *menu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) str_printf(r, "Defined at %s:%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) menu->file->name, menu->lineno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (!expr_is_yes(expr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) str_append(r, prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) expr_gstr_print(expr, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) str_append(r, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) static void get_prompt_str(struct gstr *r, struct property *prop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) struct menu *submenu[8], *menu, *location = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) struct jump_key *jump = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) str_printf(r, " Prompt: %s\n", prop->text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) get_dep_str(r, prop->menu->dep, " Depends on: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) * Most prompts in Linux have visibility that exactly matches their
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) * dependencies. For these, we print only the dependencies to improve
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) * readability. However, prompts with inline "if" expressions and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) * prompts with a parent that has a "visible if" expression have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) * differing dependencies and visibility. In these rare cases, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) * print both.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) if (!expr_eq(prop->menu->dep, prop->visible.expr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) get_dep_str(r, prop->visible.expr, " Visible if: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) menu = prop->menu->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) bool accessible = menu_is_visible(menu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) submenu[i++] = menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) if (location == NULL && accessible)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) location = menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (head && location) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) jump = xmalloc(sizeof(struct jump_key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) if (menu_is_visible(prop->menu)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) * There is not enough room to put the hint at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) * beginning of the "Prompt" line. Put the hint on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) * last "Location" line even when it would belong on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) * the former.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) jump->target = prop->menu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) jump->target = location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) if (list_empty(head))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) jump->index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) jump->index = list_entry(head->prev, struct jump_key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) entries)->index + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) list_add_tail(&jump->entries, head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) if (i > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) str_printf(r, " Location:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) for (j = 4; --i >= 0; j += 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) menu = submenu[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (jump && menu == location)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) jump->offset = strlen(r->s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) str_printf(r, "%*c-> %s", j, ' ',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) menu_get_prompt(menu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) if (menu->sym) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) str_printf(r, " (%s [=%s])", menu->sym->name ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) menu->sym->name : "<choice>",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) sym_get_string_value(menu->sym));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) str_append(r, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) enum prop_type tok, const char *prefix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) bool hit = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) for_all_properties(sym, prop, tok) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) if (!hit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) str_append(r, prefix);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) hit = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) str_printf(r, " && ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) expr_gstr_print(prop->expr, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (hit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) str_append(r, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) * head is optional and may be NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) static void get_symbol_str(struct gstr *r, struct symbol *sym,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) struct property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (sym && sym->name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) str_printf(r, "Symbol: %s [=%s]\n", sym->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) sym_get_string_value(sym));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) str_printf(r, "Type : %s\n", sym_type_name(sym->type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) if (sym->type == S_INT || sym->type == S_HEX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) prop = sym_get_range_prop(sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) if (prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) str_printf(r, "Range : ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) expr_gstr_print(prop->expr, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) str_append(r, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) /* Print the definitions with prompts before the ones without */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) for_all_properties(sym, prop, P_SYMBOL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (prop->menu->prompt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) get_def_str(r, prop->menu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) get_prompt_str(r, prop->menu->prompt, head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) for_all_properties(sym, prop, P_SYMBOL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) if (!prop->menu->prompt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) get_def_str(r, prop->menu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) get_dep_str(r, prop->menu->dep, " Depends on: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) get_symbol_props_str(r, sym, P_SELECT, "Selects: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) if (sym->rev_dep.expr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) get_symbol_props_str(r, sym, P_IMPLY, "Implies: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) if (sym->implied.expr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) str_append(r, "\n\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) struct symbol *sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) struct gstr res = str_new();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) get_symbol_str(&res, sym, head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (!i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) str_append(&res, "No matches found.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) void menu_get_ext_help(struct menu *menu, struct gstr *help)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) struct symbol *sym = menu->sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) const char *help_text = nohelp_text;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) if (menu_has_help(menu)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) if (sym->name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) help_text = menu_get_help(menu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) str_printf(help, "%s\n", help_text);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) if (sym)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) get_symbol_str(help, sym, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) }