From: Johannes Berg <[email protected]>
"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 <[email protected]>
---
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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html