kconfig: do not write choice values when their dependency becomes n
[carl9170fw.git] / config / symbol.c
index 50878dc025a5746d51316c6f1bd4c1e1b8a41707..13f7fdfe328dc36daf8f958da879be0e665c0a67 100644 (file)
@@ -77,7 +77,7 @@ const char *sym_type_name(enum symbol_type type)
 {
        switch (type) {
        case S_BOOLEAN:
-               return "boolean";
+               return "bool";
        case S_TRISTATE:
                return "tristate";
        case S_INT:
@@ -209,12 +209,26 @@ static void sym_set_all_changed(void)
 static void sym_calc_visibility(struct symbol *sym)
 {
        struct property *prop;
+       struct symbol *choice_sym = NULL;
        tristate tri;
 
        /* any prompt visible? */
        tri = no;
+
+       if (sym_is_choice_value(sym))
+               choice_sym = prop_get_symbol(sym_get_choice_prop(sym));
+
        for_all_prompts(sym, prop) {
                prop->visible.tri = expr_calc_value(prop->visible.expr);
+               /*
+                * Tristate choice_values with visibility 'mod' are
+                * not visible if the corresponding choice's value is
+                * 'yes'.
+                */
+               if (choice_sym && sym->type == S_TRISTATE &&
+                   prop->visible.tri == mod && choice_sym->curr.tri == yes)
+                       prop->visible.tri = no;
+
                tri = EXPR_OR(tri, prop->visible.tri);
        }
        if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
@@ -244,6 +258,15 @@ static void sym_calc_visibility(struct symbol *sym)
                sym->rev_dep.tri = tri;
                sym_set_changed(sym);
        }
+       tri = no;
+       if (sym->implied.expr && sym->dir_dep.tri != no)
+               tri = expr_calc_value(sym->implied.expr);
+       if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+               tri = yes;
+       if (sym->implied.tri != tri) {
+               sym->implied.tri = tri;
+               sym_set_changed(sym);
+       }
 }
 
 /*
@@ -348,11 +371,13 @@ void sym_calc_value(struct symbol *sym)
                sym->curr.tri = no;
                return;
        }
-       if (!sym_is_choice_value(sym))
-               sym->flags &= ~SYMBOL_WRITE;
+       sym->flags &= ~SYMBOL_WRITE;
 
        sym_calc_visibility(sym);
 
+       if (sym->visible != no)
+               sym->flags |= SYMBOL_WRITE;
+
        /* set default if recursively called */
        sym->curr = newval;
 
@@ -367,7 +392,6 @@ void sym_calc_value(struct symbol *sym)
                                /* if the symbol is visible use the user value
                                 * if available, otherwise try the default value
                                 */
-                               sym->flags |= SYMBOL_WRITE;
                                if (sym_has_value(sym)) {
                                        newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
                                                              sym->visible);
@@ -383,6 +407,10 @@ void sym_calc_value(struct symbol *sym)
                                        newval.tri = EXPR_AND(expr_calc_value(prop->expr),
                                                              prop->visible.tri);
                                }
+                               if (sym->implied.tri != no) {
+                                       sym->flags |= SYMBOL_WRITE;
+                                       newval.tri = EXPR_OR(newval.tri, sym->implied.tri);
+                               }
                        }
                calc_newval:
                        if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
@@ -399,18 +427,16 @@ void sym_calc_value(struct symbol *sym)
                        }
                        newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
                }
-               if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+               if (newval.tri == mod &&
+                   (sym_get_type(sym) == S_BOOLEAN || sym->implied.tri == yes))
                        newval.tri = yes;
                break;
        case S_STRING:
        case S_HEX:
        case S_INT:
-               if (sym->visible != no) {
-                       sym->flags |= SYMBOL_WRITE;
-                       if (sym_has_value(sym)) {
-                               newval.val = sym->def[S_DEF_USER].val;
-                               break;
-                       }
+               if (sym->visible != no && sym_has_value(sym)) {
+                       newval.val = sym->def[S_DEF_USER].val;
+                       break;
                }
                prop = sym_get_default_prop(sym);
                if (prop) {
@@ -484,6 +510,8 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
                return false;
        if (sym->visible <= sym->rev_dep.tri)
                return false;
+       if (sym->implied.tri == yes && val == mod)
+               return false;
        if (sym_is_choice_value(sym) && sym->visible == yes)
                return val == yes;
        return val >= sym->rev_dep.tri && val <= sym->visible;
@@ -736,6 +764,10 @@ const char *sym_get_string_default(struct symbol *sym)
        if (sym->type == S_BOOLEAN && val == mod)
                val = yes;
 
+       /* adjust the default value if this symbol is implied by another */
+       if (val < sym->implied.tri)
+               val = sym->implied.tri;
+
        switch (sym->type) {
        case S_BOOLEAN:
        case S_TRISTATE:
@@ -873,6 +905,10 @@ const char *sym_expand_string_value(const char *in)
        char *res;
        size_t reslen;
 
+       /*
+        * Note: 'in' might come from a token that's about to be
+        * freed, so make sure to always allocate a new string
+        */
        reslen = strlen(in) + 1;
        res = xmalloc(reslen);
        res[0] = '\0';
@@ -1027,7 +1063,7 @@ struct symbol **sym_re_search(const char *pattern)
        }
        if (sym_match_arr) {
                qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
-               sym_arr = malloc((cnt+1) * sizeof(struct symbol));
+               sym_arr = malloc((cnt+1) * sizeof(struct symbol *));
                if (!sym_arr)
                        goto sym_re_search_free;
                for (i = 0; i < cnt; i++)
@@ -1116,6 +1152,7 @@ static void sym_check_print_recursive(struct symbol *last_sym)
                if (stack->sym == last_sym)
                        fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
                                prop->file->name, prop->lineno);
+
                if (stack->expr) {
                        fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
                                prop->file->name, prop->lineno,
@@ -1145,6 +1182,11 @@ static void sym_check_print_recursive(struct symbol *last_sym)
                }
        }
 
+       fprintf(stderr,
+               "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n"
+               "subsection \"Kconfig recursive dependency limitations\"\n"
+               "\n");
+
        if (check_top == &cv_stack)
                dep_stack_remove();
 }
@@ -1336,6 +1378,8 @@ const char *prop_get_type_name(enum prop_type type)
                return "choice";
        case P_SELECT:
                return "select";
+       case P_IMPLY:
+               return "imply";
        case P_RANGE:
                return "range";
        case P_SYMBOL: