kconfig: adjust warning message for conflicting types
[carl9170fw.git] / config / menu.c
index a5241859326a90cd1828734121c465bd01704b17..9e69f1934836e17c85025387d4073746005012a8 100644 (file)
@@ -48,7 +48,7 @@ void menu_add_entry(struct symbol *sym)
 {
        struct menu *menu;
 
-       menu = malloc(sizeof(*menu));
+       menu = xmalloc(sizeof(*menu));
        memset(menu, 0, sizeof(*menu));
        menu->sym = sym;
        menu->parent = current_menu;
@@ -119,9 +119,10 @@ void menu_set_type(int type)
                sym->type = type;
                return;
        }
-       menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
-           sym->name ? sym->name : "<choice>",
-           sym_type_name(sym->type), sym_type_name(type));
+       menu_warn(current_entry,
+               "ignoring type redefinition of '%s' from '%s' to '%s'",
+               sym->name ? sym->name : "<choice>",
+               sym_type_name(sym->type), sym_type_name(type));
 }
 
 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
@@ -146,11 +147,24 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
                        struct menu *menu = current_entry;
 
                        while ((menu = menu->parent) != NULL) {
+                               struct expr *dup_expr;
+
                                if (!menu->visibility)
                                        continue;
+                               /*
+                                * Do not add a reference to the
+                                * menu's visibility expression but
+                                * use a copy of it.  Otherwise the
+                                * expression reduction functions
+                                * will modify expressions that have
+                                * multiple references which can
+                                * cause unwanted side effects.
+                                */
+                               dup_expr = expr_copy(menu->visibility);
+
                                prop->visible.expr
                                        = expr_alloc_and(prop->visible.expr,
-                                                        menu->visibility);
+                                                        dup_expr);
                        }
                }
 
@@ -184,12 +198,15 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
 
 void menu_add_option(int token, char *arg)
 {
-       struct property *prop;
-
        switch (token) {
        case T_OPT_MODULES:
-               prop = prop_alloc(P_DEFAULT, modules_sym);
-               prop->expr = expr_alloc_symbol(current_entry->sym);
+               if (modules_sym)
+                       zconf_error("symbol '%s' redefines option 'modules'"
+                                   " already defined by symbol '%s'",
+                                   current_entry->sym->name,
+                                   modules_sym->name
+                                   );
+               modules_sym = current_entry->sym;
                break;
        case T_OPT_DEFCONFIG_LIST:
                if (!sym_defconfig_list)
@@ -430,6 +447,22 @@ bool menu_has_prompt(struct menu *menu)
        return true;
 }
 
+/*
+ * Determine if a menu is empty.
+ * A menu is considered empty if it contains no or only
+ * invisible entries.
+ */
+bool menu_is_empty(struct menu *menu)
+{
+       struct menu *child;
+
+       for (child = menu->list; child; child = child->next) {
+               if (menu_is_visible(child))
+                       return(false);
+       }
+       return(true);
+}
+
 bool menu_is_visible(struct menu *menu)
 {
        struct menu *child;
@@ -507,21 +540,14 @@ const char *menu_get_help(struct menu *menu)
                return "";
 }
 
-static int get_prompt_str(struct gstr *r, struct property *prop, struct menu
-                         **jumps, int jump_nb)
+static void get_prompt_str(struct gstr *r, struct property *prop,
+                          struct list_head *head)
 {
        int i, j;
-       char header[4];
        struct menu *submenu[8], *menu, *location = NULL;
+       struct jump_key *jump;
 
        str_printf(r, _("Prompt: %s\n"), _(prop->text));
-       str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
-               prop->menu->lineno);
-       if (!expr_is_yes(prop->visible.expr)) {
-               str_append(r, _("  Depends on: "));
-               expr_gstr_print(prop->visible.expr, r);
-               str_append(r, "\n");
-       }
        menu = prop->menu->parent;
        for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
                bool accessible = menu_is_visible(menu);
@@ -530,7 +556,9 @@ static int get_prompt_str(struct gstr *r, struct property *prop, struct menu
                if (location == NULL && accessible)
                        location = menu;
        }
-       if (jumps && jump_nb < JUMP_NB && location) {
+       if (head && location) {
+               jump = xmalloc(sizeof(struct jump_key));
+
                if (menu_is_visible(prop->menu)) {
                        /*
                         * There is not enough room to put the hint at the
@@ -538,19 +566,27 @@ static int get_prompt_str(struct gstr *r, struct property *prop, struct menu
                         * last "Location" line even when it would belong on
                         * the former.
                         */
-                       jumps[jump_nb] = prop->menu;
+                       jump->target = prop->menu;
                } else
-                       jumps[jump_nb] = location;
-               snprintf(header, 4, "(%d)", jump_nb + 1);
-       } else
-               location = NULL;
+                       jump->target = location;
+
+               if (list_empty(head))
+                       jump->index = 0;
+               else
+                       jump->index = list_entry(head->prev, struct jump_key,
+                                                entries)->index + 1;
+
+               list_add_tail(&jump->entries, head);
+       }
 
        if (i > 0) {
                str_printf(r, _("  Location:\n"));
-               for (j = 1; --i >= 0; j += 2) {
+               for (j = 4; --i >= 0; j += 2) {
                        menu = submenu[i];
-                       str_printf(r, "%s%*c-> %s", menu == location ? header
-                                  : "   ", j, ' ', _(menu_get_prompt(menu)));
+                       if (head && location && menu == location)
+                               jump->offset = r->len - 1;
+                       str_printf(r, "%*c-> %s", j, ' ',
+                                  _(menu_get_prompt(menu)));
                        if (menu->sym) {
                                str_printf(r, " (%s [=%s])", menu->sym->name ?
                                        menu->sym->name : _("<choice>"),
@@ -559,20 +595,28 @@ static int get_prompt_str(struct gstr *r, struct property *prop, struct menu
                        str_append(r, "\n");
                }
        }
+}
+
+/*
+ * get property of type P_SYMBOL
+ */
+static struct property *get_symbol_prop(struct symbol *sym)
+{
+       struct property *prop = NULL;
 
-       return location ? 1 : 0;
+       for_all_properties(sym, prop, P_SYMBOL)
+               break;
+       return prop;
 }
 
 /*
- * jumps is optional and may be NULL
- * returns the number of jumps inserted
+ * head is optional and may be NULL
  */
-int get_symbol_str(struct gstr *r, struct symbol *sym, struct menu **jumps,
-                  int jump_nb)
+void get_symbol_str(struct gstr *r, struct symbol *sym,
+                   struct list_head *head)
 {
        bool hit;
        struct property *prop;
-       int i = 0;
 
        if (sym && sym->name) {
                str_printf(r, "Symbol: %s [=%s]\n", sym->name,
@@ -588,7 +632,19 @@ int get_symbol_str(struct gstr *r, struct symbol *sym, struct menu **jumps,
                }
        }
        for_all_prompts(sym, prop)
-               i += get_prompt_str(r, prop, jumps, jump_nb + i);
+               get_prompt_str(r, prop, head);
+
+       prop = get_symbol_prop(sym);
+       if (prop) {
+               str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
+                       prop->menu->lineno);
+               if (!expr_is_yes(prop->visible.expr)) {
+                       str_append(r, _("  Depends on: "));
+                       expr_gstr_print(prop->visible.expr, r);
+                       str_append(r, "\n");
+               }
+       }
+
        hit = false;
        for_all_properties(sym, prop, P_SELECT) {
                if (!hit) {
@@ -606,18 +662,16 @@ int get_symbol_str(struct gstr *r, struct symbol *sym, struct menu **jumps,
                str_append(r, "\n");
        }
        str_append(r, "\n\n");
-
-       return i;
 }
 
-struct gstr get_relations_str(struct symbol **sym_arr, struct menu **jumps)
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
 {
        struct symbol *sym;
        struct gstr res = str_new();
-       int i, jump_nb = 0;
+       int i;
 
        for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
-               jump_nb += get_symbol_str(&res, sym, jumps, jump_nb);
+               get_symbol_str(&res, sym, head);
        if (!i)
                str_append(&res, _("No matches found.\n"));
        return res;
@@ -636,5 +690,5 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help)
        }
        str_printf(help, "%s\n", _(help_text));
        if (sym)
-               get_symbol_str(help, sym, NULL, 0);
+               get_symbol_str(help, sym, NULL);
 }