From: Johannes Berg <johannes.berg@xxxxxxxxx> "count" works similar to "select"; take, for example, this snippet: config MY_COUNTER int config MY_DRIVER_1 bool "my driver 1" count MY_COUNTER config MY_DRIVER_2 bool "my driver 2" count MY_COUNTER This will get MY_COUNTER to have a value of 0, 1 or 2, depending on whether or not MY_DRIVER_1/MY_DRIVER_2 are not at all, one or both selected respectively. This can be useful for certain optimization purposes but I'm sure people will come up with other creative usage. Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> --- Documentation/kbuild/kconfig-language.txt | 7 +++++++ scripts/kconfig/expr.h | 1 + scripts/kconfig/menu.c | 28 +++++++++++++++++++++++++++- scripts/kconfig/symbol.c | 29 ++++++++++++++++++++++++++++- scripts/kconfig/zconf.gperf | 1 + scripts/kconfig/zconf.y | 16 ++++++++++++++-- 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt index 350f733bf2c7..cee587254d3b 100644 --- a/Documentation/kbuild/kconfig-language.txt +++ b/Documentation/kbuild/kconfig-language.txt @@ -113,6 +113,13 @@ applicable everywhere (see syntax). That will limit the usefulness but on the other hand avoid the illegal configurations all over. +- counting: "count" <symbol> ["if" <expr>] + If, for some reason, it is desired to understand the number of times a + given symbol is selected, that can be achieved by using "count" instead + of select. The <symbol> must be an int, and the default value is added + to the count. + A lot of the caveats for "select" apply here since it's very similar. + - limiting menu display: "visible if" <expr> This attribute is only applicable to menu blocks, if the condition is false, the menu block is not displayed to the user (the symbols diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 973b6f733368..c77c8c30dd52 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -139,6 +139,7 @@ enum prop_type { P_RANGE, /* range 7..100 (for a symbol) */ P_ENV, /* value from environment variable */ P_SYMBOL, /* where a symbol is defined */ + P_COUNT, /* count BAR - increments BAR counter */ }; struct property { diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index b05cc3d4a9be..0f7ef400741a 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -265,6 +265,18 @@ static void sym_check_prop(struct symbol *sym) "accept arguments of boolean and " "tristate type", sym2->name); break; + case P_COUNT: + sym2 = prop_get_symbol(prop); + if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) + prop_warn(prop, + "config symbol '%s' uses select, but is " + "not boolean or tristate", sym->name); + else if (sym2->type != S_INT) + prop_warn(prop, + "'%s' has wrong type. 'count' only " + "accept arguments of int type", + sym2->name); + break; case P_RANGE: if (sym->type != S_INT && sym->type != S_HEX) prop_warn(prop, "range is only allowed " @@ -333,6 +345,9 @@ void menu_finalize(struct menu *parent) struct symbol *es = prop_get_symbol(prop); es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); + } else if (prop->type == P_COUNT) { + struct symbol *es = prop_get_symbol(prop); + es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, expr_alloc_symbol(menu->sym)); } } } @@ -657,10 +672,21 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, str_printf(r, " && "); expr_gstr_print(prop->expr, r); } + for_all_properties(sym, prop, P_COUNT) { + if (!hit) { + str_append(r, " Counts: "); + hit = true; + } else + str_printf(r, " && "); + expr_gstr_print(prop->expr, r); + } if (hit) str_append(r, "\n"); if (sym->rev_dep.expr) { - str_append(r, _(" Selected by: ")); + if (sym->type != S_INT) + str_append(r, _(" Selected by: ")); + else + str_append(r, _(" Counted by: ")); expr_gstr_print(sym->rev_dep.expr, r); str_append(r, "\n"); } diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 50878dc025a5..14980b3af254 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -310,6 +310,20 @@ static struct symbol *sym_calc_choice(struct symbol *sym) return def_sym; } +static unsigned long long count_or_symbols(struct expr *e) +{ + switch (e->type) { + case E_SYMBOL: + return 1; + case E_OR: + return count_or_symbols(e->left.expr) + + count_or_symbols(e->right.expr); + default: + fprintf(stderr, "warning: unexpected expression in count"); + return 0; + } +} + void sym_calc_value(struct symbol *sym) { struct symbol_value newval, oldval; @@ -421,6 +435,15 @@ void sym_calc_value(struct symbol *sym) newval.val = ds->curr.val; } } + if (sym->rev_dep.expr) { + long long val = strtoll(newval.val, NULL, 0); + char *buf = xmalloc(22); + + val += count_or_symbols(sym->rev_dep.expr); + sprintf(buf, "%lld", val); + newval.val = buf; + sym->flags |= SYMBOL_WRITE; + } break; default: ; @@ -1197,7 +1220,9 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) goto out; for (prop = sym->prop; prop; prop = prop->next) { - if (prop->type == P_CHOICE || prop->type == P_SELECT) + if (prop->type == P_CHOICE || + prop->type == P_SELECT || + prop->type == P_COUNT) continue; stack.prop = prop; sym2 = sym_check_expr_deps(prop->visible.expr); @@ -1336,6 +1361,8 @@ const char *prop_get_type_name(enum prop_type type) return "choice"; case P_SELECT: return "select"; + case P_COUNT: + return "count"; case P_RANGE: return "range"; case P_SYMBOL: diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf index ac498f01b449..46ce5833887e 100644 --- a/scripts/kconfig/zconf.gperf +++ b/scripts/kconfig/zconf.gperf @@ -46,4 +46,5 @@ modules, T_OPT_MODULES, TF_OPTION defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION env, T_OPT_ENV, TF_OPTION allnoconfig_y, T_OPT_ALLNOCONFIG_Y,TF_OPTION +count, T_COUNT, TF_COMMAND %% diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 71bf8bff696a..18c43561860b 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -31,7 +31,7 @@ struct symbol *symbol_hash[SYMBOL_HASHSIZE]; static struct menu *current_menu, *current_entry; %} -%expect 30 +%expect 32 %union { @@ -76,6 +76,7 @@ static struct menu *current_menu, *current_entry; %token T_CLOSE_PAREN %token T_OPEN_PAREN %token T_EOL +%token <id>T_COUNT %left T_OR %left T_AND @@ -124,7 +125,7 @@ stmt_list: ; option_name: - T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE + T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_COUNT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE ; common_stmt: @@ -216,6 +217,12 @@ config_option: T_SELECT T_WORD if_expr T_EOL printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); }; +config_option: T_COUNT T_WORD if_expr T_EOL +{ + menu_add_symbol(P_COUNT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:count\n", zconf_curname(), zconf_lineno()); +}; + config_option: T_RANGE symbol symbol if_expr T_EOL { menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); @@ -664,6 +671,11 @@ static void print_symbol(FILE *out, struct menu *menu) expr_fprint(prop->expr, out); fputc('\n', out); break; + case P_COUNT: + fputs( " count ", out); + expr_fprint(prop->expr, out); + fputc('\n', out); + break; case P_RANGE: fputs( " range ", out); expr_fprint(prop->expr, out); -- 2.6.2 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html