Skip to content

Commit d0342dd

Browse files
committed
allow index in addition to path
1 parent 7ad7d25 commit d0342dd

File tree

4 files changed

+54
-9
lines changed

4 files changed

+54
-9
lines changed

doc/antora/modules/reference/pages/unlang/foreach.adoc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ loop over each i in attribute[0..n]
9696

9797
Using a key variable allows the loop to determine exactly which attribute is being modified. Or for dynamic expansions, which of `0..n` values are being examined.
9898

99-
For attributes, the `<key-type>` must be `string`. For dynamic expansions, it must be a numerical type such as `uint32`.
99+
For attributes, the `<key-type>` must be `string` or `uint32`. For dynamic expansions, it must be a numerical type such as `uint32`.
100100

101-
.Key variable with attribute
101+
.Key variable with attribute reference
102102
[source,unlang]
103103
----
104104
string total
@@ -118,6 +118,18 @@ When the loop is finished, the `total` variable will have the following value:
118118
"Tmp-Integer-0[0] = 1, "Tmp-Integer-0[1] = 3, "Tmp-Integer-0[2] = 5, "Tmp-Integer-0[3] = 11, "
119119
----
120120

121+
.Key variable with attribute index
122+
[source,unlang]
123+
----
124+
string total
125+
Tmp-Integer-0 := { 1, 3, 5, 11 }
126+
127+
foreach uint32 index, uint32 self (Tmp-Integer-0) {
128+
...
129+
}
130+
----
131+
132+
121133
A dynamic expansion can use a keyed index. If the `SELECT` statement below returns a list of `"a", "b", "c", "d"`. then we have the following example:
122134

123135
.Key variable with expansion

src/lib/unlang/compile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3355,8 +3355,8 @@ static unlang_t *compile_foreach(unlang_t *parent, unlang_compile_t *unlang_ctx,
33553355
} else {
33563356
fr_assert(tmpl_is_attr(vpt));
33573357

3358-
if ((key_type != FR_TYPE_VOID) && (key_type != FR_TYPE_STRING)) {
3359-
cf_log_err(cs, "Invalid data type '%s' for 'key' variable - it should be 'string'", fr_type_to_str(key_type));
3358+
if ((key_type != FR_TYPE_VOID) && (key_type != FR_TYPE_STRING) && (key_type != FR_TYPE_UINT32)) {
3359+
cf_log_err(cs, "Invalid data type '%s' for 'key' variable - it should be 'string' or 'uint32'", fr_type_to_str(key_type));
33603360
return NULL;
33613361
}
33623362
}

src/lib/unlang/foreach.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,22 @@ static void unlang_foreach_attr_key_update(UNUSED request_t *request, unlang_fra
342342
{
343343
if (!state->key) return;
344344

345-
fr_value_box_clear_value(&state->key->data);
346-
if (tmpl_dcursor_print(&FR_SBUFF_IN(state->buffer, BUFFER_SIZE), &state->cc) > 0) {
347-
fr_value_box_strdup(state->key, &state->key->data, NULL, state->buffer, false);
345+
switch (state->key->vp_type) {
346+
case FR_TYPE_UINT32:
347+
state->key->vp_uint32++;
348+
break;
349+
350+
case FR_TYPE_STRING:
351+
fr_value_box_clear_value(&state->key->data);
352+
if (tmpl_dcursor_print(&FR_SBUFF_IN(state->buffer, BUFFER_SIZE), &state->cc) > 0) {
353+
fr_value_box_strdup(state->key, &state->key->data, NULL, state->buffer, false);
354+
}
355+
break;
356+
357+
default:
358+
fr_assert(0);
359+
break;
360+
348361
}
349362
}
350363

@@ -474,9 +487,9 @@ static unlang_action_t unlang_foreach_attr_init(rlm_rcode_t *p_result, request_t
474487
fr_assert(vp != NULL);
475488

476489
/*
477-
* Update the key with the current path or index.
490+
* Update the key with the current path. Attribute indexes start at zero.
478491
*/
479-
unlang_foreach_attr_key_update(request, state);
492+
if (state->key->vp_type == FR_TYPE_STRING) unlang_foreach_attr_key_update(request, state);
480493

481494
if (vp->vp_type == FR_TYPE_GROUP) {
482495
fr_assert(state->value->vp_type == FR_TYPE_GROUP);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#
2+
# PRE: foreach-key-ref
3+
#
4+
string total
5+
6+
Tmp-String-0 := { "a", "b", "c", "d" }
7+
8+
#
9+
# Ensure that attributes can be referenced, and
10+
# that the count is correct.
11+
#
12+
foreach uint32 index, string value (Tmp-String-0[*]) {
13+
total += Tmp-String-0[index]
14+
}
15+
16+
if (total != "abcd") {
17+
test_fail
18+
}
19+
20+
success

0 commit comments

Comments
 (0)