| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> |
|---|
| 3 | | - * Released under the terms of the GNU GPL v2.0. |
|---|
| 4 | 4 | */ |
|---|
| 5 | 5 | |
|---|
| 6 | 6 | #include <ctype.h> |
|---|
| .. | .. |
|---|
| 65 | 65 | struct menu *menu_add_menu(void) |
|---|
| 66 | 66 | { |
|---|
| 67 | 67 | last_entry_ptr = ¤t_entry->list; |
|---|
| 68 | | - return current_menu = current_entry; |
|---|
| 68 | + current_menu = current_entry; |
|---|
| 69 | + return current_menu; |
|---|
| 69 | 70 | } |
|---|
| 70 | 71 | |
|---|
| 71 | 72 | void menu_end_menu(void) |
|---|
| .. | .. |
|---|
| 124 | 125 | sym_type_name(sym->type), sym_type_name(type)); |
|---|
| 125 | 126 | } |
|---|
| 126 | 127 | |
|---|
| 127 | | -static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) |
|---|
| 128 | +static struct property *menu_add_prop(enum prop_type type, struct expr *expr, |
|---|
| 129 | + struct expr *dep) |
|---|
| 128 | 130 | { |
|---|
| 129 | | - struct property *prop = prop_alloc(type, current_entry->sym); |
|---|
| 131 | + struct property *prop; |
|---|
| 130 | 132 | |
|---|
| 133 | + prop = xmalloc(sizeof(*prop)); |
|---|
| 134 | + memset(prop, 0, sizeof(*prop)); |
|---|
| 135 | + prop->type = type; |
|---|
| 136 | + prop->file = current_file; |
|---|
| 137 | + prop->lineno = zconf_lineno(); |
|---|
| 131 | 138 | prop->menu = current_entry; |
|---|
| 132 | 139 | prop->expr = expr; |
|---|
| 133 | 140 | prop->visible.expr = dep; |
|---|
| 134 | 141 | |
|---|
| 135 | | - if (prompt) { |
|---|
| 136 | | - if (isspace(*prompt)) { |
|---|
| 137 | | - prop_warn(prop, "leading whitespace ignored"); |
|---|
| 138 | | - while (isspace(*prompt)) |
|---|
| 139 | | - prompt++; |
|---|
| 140 | | - } |
|---|
| 141 | | - if (current_entry->prompt && current_entry != &rootmenu) |
|---|
| 142 | | - prop_warn(prop, "prompt redefined"); |
|---|
| 142 | + /* append property to the prop list of symbol */ |
|---|
| 143 | + if (current_entry->sym) { |
|---|
| 144 | + struct property **propp; |
|---|
| 143 | 145 | |
|---|
| 144 | | - /* Apply all upper menus' visibilities to actual prompts. */ |
|---|
| 145 | | - if(type == P_PROMPT) { |
|---|
| 146 | | - struct menu *menu = current_entry; |
|---|
| 147 | | - |
|---|
| 148 | | - while ((menu = menu->parent) != NULL) { |
|---|
| 149 | | - struct expr *dup_expr; |
|---|
| 150 | | - |
|---|
| 151 | | - if (!menu->visibility) |
|---|
| 152 | | - continue; |
|---|
| 153 | | - /* |
|---|
| 154 | | - * Do not add a reference to the |
|---|
| 155 | | - * menu's visibility expression but |
|---|
| 156 | | - * use a copy of it. Otherwise the |
|---|
| 157 | | - * expression reduction functions |
|---|
| 158 | | - * will modify expressions that have |
|---|
| 159 | | - * multiple references which can |
|---|
| 160 | | - * cause unwanted side effects. |
|---|
| 161 | | - */ |
|---|
| 162 | | - dup_expr = expr_copy(menu->visibility); |
|---|
| 163 | | - |
|---|
| 164 | | - prop->visible.expr |
|---|
| 165 | | - = expr_alloc_and(prop->visible.expr, |
|---|
| 166 | | - dup_expr); |
|---|
| 167 | | - } |
|---|
| 168 | | - } |
|---|
| 169 | | - |
|---|
| 170 | | - current_entry->prompt = prop; |
|---|
| 146 | + for (propp = ¤t_entry->sym->prop; |
|---|
| 147 | + *propp; |
|---|
| 148 | + propp = &(*propp)->next) |
|---|
| 149 | + ; |
|---|
| 150 | + *propp = prop; |
|---|
| 171 | 151 | } |
|---|
| 172 | | - prop->text = prompt; |
|---|
| 173 | 152 | |
|---|
| 174 | 153 | return prop; |
|---|
| 175 | 154 | } |
|---|
| 176 | 155 | |
|---|
| 177 | | -struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) |
|---|
| 156 | +struct property *menu_add_prompt(enum prop_type type, char *prompt, |
|---|
| 157 | + struct expr *dep) |
|---|
| 178 | 158 | { |
|---|
| 179 | | - return menu_add_prop(type, prompt, NULL, dep); |
|---|
| 159 | + struct property *prop = menu_add_prop(type, NULL, dep); |
|---|
| 160 | + |
|---|
| 161 | + if (isspace(*prompt)) { |
|---|
| 162 | + prop_warn(prop, "leading whitespace ignored"); |
|---|
| 163 | + while (isspace(*prompt)) |
|---|
| 164 | + prompt++; |
|---|
| 165 | + } |
|---|
| 166 | + if (current_entry->prompt) |
|---|
| 167 | + prop_warn(prop, "prompt redefined"); |
|---|
| 168 | + |
|---|
| 169 | + /* Apply all upper menus' visibilities to actual prompts. */ |
|---|
| 170 | + if (type == P_PROMPT) { |
|---|
| 171 | + struct menu *menu = current_entry; |
|---|
| 172 | + |
|---|
| 173 | + while ((menu = menu->parent) != NULL) { |
|---|
| 174 | + struct expr *dup_expr; |
|---|
| 175 | + |
|---|
| 176 | + if (!menu->visibility) |
|---|
| 177 | + continue; |
|---|
| 178 | + /* |
|---|
| 179 | + * Do not add a reference to the menu's visibility |
|---|
| 180 | + * expression but use a copy of it. Otherwise the |
|---|
| 181 | + * expression reduction functions will modify |
|---|
| 182 | + * expressions that have multiple references which |
|---|
| 183 | + * can cause unwanted side effects. |
|---|
| 184 | + */ |
|---|
| 185 | + dup_expr = expr_copy(menu->visibility); |
|---|
| 186 | + |
|---|
| 187 | + prop->visible.expr = expr_alloc_and(prop->visible.expr, |
|---|
| 188 | + dup_expr); |
|---|
| 189 | + } |
|---|
| 190 | + } |
|---|
| 191 | + |
|---|
| 192 | + current_entry->prompt = prop; |
|---|
| 193 | + prop->text = prompt; |
|---|
| 194 | + |
|---|
| 195 | + return prop; |
|---|
| 180 | 196 | } |
|---|
| 181 | 197 | |
|---|
| 182 | 198 | void menu_add_visibility(struct expr *expr) |
|---|
| .. | .. |
|---|
| 187 | 203 | |
|---|
| 188 | 204 | void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) |
|---|
| 189 | 205 | { |
|---|
| 190 | | - menu_add_prop(type, NULL, expr, dep); |
|---|
| 206 | + menu_add_prop(type, expr, dep); |
|---|
| 191 | 207 | } |
|---|
| 192 | 208 | |
|---|
| 193 | 209 | void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) |
|---|
| 194 | 210 | { |
|---|
| 195 | | - menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); |
|---|
| 211 | + menu_add_prop(type, expr_alloc_symbol(sym), dep); |
|---|
| 196 | 212 | } |
|---|
| 197 | 213 | |
|---|
| 198 | | -void menu_add_option(int token, char *arg) |
|---|
| 214 | +void menu_add_option_modules(void) |
|---|
| 199 | 215 | { |
|---|
| 200 | | - switch (token) { |
|---|
| 201 | | - case T_OPT_MODULES: |
|---|
| 202 | | - if (modules_sym) |
|---|
| 203 | | - zconf_error("symbol '%s' redefines option 'modules'" |
|---|
| 204 | | - " already defined by symbol '%s'", |
|---|
| 205 | | - current_entry->sym->name, |
|---|
| 206 | | - modules_sym->name |
|---|
| 207 | | - ); |
|---|
| 208 | | - modules_sym = current_entry->sym; |
|---|
| 209 | | - break; |
|---|
| 210 | | - case T_OPT_DEFCONFIG_LIST: |
|---|
| 211 | | - if (!sym_defconfig_list) |
|---|
| 212 | | - sym_defconfig_list = current_entry->sym; |
|---|
| 213 | | - else if (sym_defconfig_list != current_entry->sym) |
|---|
| 214 | | - zconf_error("trying to redefine defconfig symbol"); |
|---|
| 215 | | - sym_defconfig_list->flags |= SYMBOL_NO_WRITE; |
|---|
| 216 | | - break; |
|---|
| 217 | | - case T_OPT_ALLNOCONFIG_Y: |
|---|
| 218 | | - current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; |
|---|
| 219 | | - break; |
|---|
| 220 | | - } |
|---|
| 216 | + if (modules_sym) |
|---|
| 217 | + zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'", |
|---|
| 218 | + current_entry->sym->name, modules_sym->name); |
|---|
| 219 | + modules_sym = current_entry->sym; |
|---|
| 220 | +} |
|---|
| 221 | + |
|---|
| 222 | +void menu_add_option_defconfig_list(void) |
|---|
| 223 | +{ |
|---|
| 224 | + if (!sym_defconfig_list) |
|---|
| 225 | + sym_defconfig_list = current_entry->sym; |
|---|
| 226 | + else if (sym_defconfig_list != current_entry->sym) |
|---|
| 227 | + zconf_error("trying to redefine defconfig symbol"); |
|---|
| 228 | + sym_defconfig_list->flags |= SYMBOL_NO_WRITE; |
|---|
| 229 | +} |
|---|
| 230 | + |
|---|
| 231 | +void menu_add_option_allnoconfig_y(void) |
|---|
| 232 | +{ |
|---|
| 233 | + current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; |
|---|
| 221 | 234 | } |
|---|
| 222 | 235 | |
|---|
| 223 | 236 | static int menu_validate_number(struct symbol *sym, struct symbol *sym2) |
|---|
| .. | .. |
|---|
| 329 | 342 | * choice value symbols. |
|---|
| 330 | 343 | */ |
|---|
| 331 | 344 | parentdep = expr_alloc_symbol(sym); |
|---|
| 332 | | - } else if (parent->prompt) |
|---|
| 333 | | - /* Menu node for 'menu' */ |
|---|
| 334 | | - parentdep = parent->prompt->visible.expr; |
|---|
| 335 | | - else |
|---|
| 336 | | - /* Menu node for 'if' */ |
|---|
| 345 | + } else { |
|---|
| 346 | + /* Menu node for 'menu', 'if' */ |
|---|
| 337 | 347 | parentdep = parent->dep; |
|---|
| 348 | + } |
|---|
| 338 | 349 | |
|---|
| 339 | 350 | /* For each child menu node... */ |
|---|
| 340 | 351 | for (menu = parent->list; menu; menu = menu->next) { |
|---|
| .. | .. |
|---|
| 701 | 712 | return ""; |
|---|
| 702 | 713 | } |
|---|
| 703 | 714 | |
|---|
| 715 | +static void get_def_str(struct gstr *r, struct menu *menu) |
|---|
| 716 | +{ |
|---|
| 717 | + str_printf(r, "Defined at %s:%d\n", |
|---|
| 718 | + menu->file->name, menu->lineno); |
|---|
| 719 | +} |
|---|
| 720 | + |
|---|
| 721 | +static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) |
|---|
| 722 | +{ |
|---|
| 723 | + if (!expr_is_yes(expr)) { |
|---|
| 724 | + str_append(r, prefix); |
|---|
| 725 | + expr_gstr_print(expr, r); |
|---|
| 726 | + str_append(r, "\n"); |
|---|
| 727 | + } |
|---|
| 728 | +} |
|---|
| 729 | + |
|---|
| 704 | 730 | static void get_prompt_str(struct gstr *r, struct property *prop, |
|---|
| 705 | 731 | struct list_head *head) |
|---|
| 706 | 732 | { |
|---|
| .. | .. |
|---|
| 708 | 734 | struct menu *submenu[8], *menu, *location = NULL; |
|---|
| 709 | 735 | struct jump_key *jump = NULL; |
|---|
| 710 | 736 | |
|---|
| 711 | | - str_printf(r, "Prompt: %s\n", prop->text); |
|---|
| 737 | + str_printf(r, " Prompt: %s\n", prop->text); |
|---|
| 738 | + |
|---|
| 739 | + get_dep_str(r, prop->menu->dep, " Depends on: "); |
|---|
| 740 | + /* |
|---|
| 741 | + * Most prompts in Linux have visibility that exactly matches their |
|---|
| 742 | + * dependencies. For these, we print only the dependencies to improve |
|---|
| 743 | + * readability. However, prompts with inline "if" expressions and |
|---|
| 744 | + * prompts with a parent that has a "visible if" expression have |
|---|
| 745 | + * differing dependencies and visibility. In these rare cases, we |
|---|
| 746 | + * print both. |
|---|
| 747 | + */ |
|---|
| 748 | + if (!expr_eq(prop->menu->dep, prop->visible.expr)) |
|---|
| 749 | + get_dep_str(r, prop->visible.expr, " Visible if: "); |
|---|
| 750 | + |
|---|
| 712 | 751 | menu = prop->menu->parent; |
|---|
| 713 | 752 | for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { |
|---|
| 714 | 753 | bool accessible = menu_is_visible(menu); |
|---|
| .. | .. |
|---|
| 758 | 797 | } |
|---|
| 759 | 798 | } |
|---|
| 760 | 799 | |
|---|
| 761 | | -/* |
|---|
| 762 | | - * get property of type P_SYMBOL |
|---|
| 763 | | - */ |
|---|
| 764 | | -static struct property *get_symbol_prop(struct symbol *sym) |
|---|
| 765 | | -{ |
|---|
| 766 | | - struct property *prop = NULL; |
|---|
| 767 | | - |
|---|
| 768 | | - for_all_properties(sym, prop, P_SYMBOL) |
|---|
| 769 | | - break; |
|---|
| 770 | | - return prop; |
|---|
| 771 | | -} |
|---|
| 772 | | - |
|---|
| 773 | 800 | static void get_symbol_props_str(struct gstr *r, struct symbol *sym, |
|---|
| 774 | 801 | enum prop_type tok, const char *prefix) |
|---|
| 775 | 802 | { |
|---|
| .. | .. |
|---|
| 809 | 836 | } |
|---|
| 810 | 837 | } |
|---|
| 811 | 838 | } |
|---|
| 812 | | - for_all_prompts(sym, prop) |
|---|
| 813 | | - get_prompt_str(r, prop, head); |
|---|
| 814 | 839 | |
|---|
| 815 | | - prop = get_symbol_prop(sym); |
|---|
| 816 | | - if (prop) { |
|---|
| 817 | | - str_printf(r, " Defined at %s:%d\n", prop->menu->file->name, |
|---|
| 818 | | - prop->menu->lineno); |
|---|
| 819 | | - if (!expr_is_yes(prop->visible.expr)) { |
|---|
| 820 | | - str_append(r, " Depends on: "); |
|---|
| 821 | | - expr_gstr_print(prop->visible.expr, r); |
|---|
| 822 | | - str_append(r, "\n"); |
|---|
| 840 | + /* Print the definitions with prompts before the ones without */ |
|---|
| 841 | + for_all_properties(sym, prop, P_SYMBOL) { |
|---|
| 842 | + if (prop->menu->prompt) { |
|---|
| 843 | + get_def_str(r, prop->menu); |
|---|
| 844 | + get_prompt_str(r, prop->menu->prompt, head); |
|---|
| 823 | 845 | } |
|---|
| 824 | 846 | } |
|---|
| 825 | 847 | |
|---|
| 826 | | - get_symbol_props_str(r, sym, P_SELECT, " Selects: "); |
|---|
| 827 | | - if (sym->rev_dep.expr) { |
|---|
| 828 | | - expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n"); |
|---|
| 829 | | - expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n"); |
|---|
| 830 | | - expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n"); |
|---|
| 848 | + for_all_properties(sym, prop, P_SYMBOL) { |
|---|
| 849 | + if (!prop->menu->prompt) { |
|---|
| 850 | + get_def_str(r, prop->menu); |
|---|
| 851 | + get_dep_str(r, prop->menu->dep, " Depends on: "); |
|---|
| 852 | + } |
|---|
| 831 | 853 | } |
|---|
| 832 | 854 | |
|---|
| 833 | | - get_symbol_props_str(r, sym, P_IMPLY, " Implies: "); |
|---|
| 855 | + get_symbol_props_str(r, sym, P_SELECT, "Selects: "); |
|---|
| 856 | + if (sym->rev_dep.expr) { |
|---|
| 857 | + expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n"); |
|---|
| 858 | + expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n"); |
|---|
| 859 | + expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n"); |
|---|
| 860 | + } |
|---|
| 861 | + |
|---|
| 862 | + get_symbol_props_str(r, sym, P_IMPLY, "Implies: "); |
|---|
| 834 | 863 | if (sym->implied.expr) { |
|---|
| 835 | | - expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n"); |
|---|
| 836 | | - expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n"); |
|---|
| 837 | | - expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n"); |
|---|
| 864 | + expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n"); |
|---|
| 865 | + expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n"); |
|---|
| 866 | + expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n"); |
|---|
| 838 | 867 | } |
|---|
| 839 | 868 | |
|---|
| 840 | 869 | str_append(r, "\n\n"); |
|---|