.Syntax
[source,unlang]
----
-foreach <type> <key-name> (<attribute-reference>) {
+foreach <key-name> (<attribute-reference>) {
[ statements ]
}
----
There is no limit on how many `foreach` statements can be nested.
-<type>::
-
-A xref:type/index.adoc[data type], or the string `auto`.
-
<key-name>::
The name of the local variable which is used as the name of key when iterating over the attributes.
The local variable is created automatically when the `foreach` loop is entered, and is deleted automatically when the `foreach` loop exits.
+The data type of the local variable is taken from the attribute reference.
+
The `<key-name>` can be modified during the course of the `foreach` loop. Modifications to the variable are copied back to the referenced attribute when the loop is done. See below for an example.
The only limitation on the `<key-name>` is that it must be unique.
over. The reference can be to one attribute, to an array, a child, or
be a subset of attributes.
-== Data type of the Key
-
-The key variable can be given an explicit data type. This data type does not have to be the same data type as the attribute being looped over. If the types are different, then the data is cast from the source type to the key type.
-
-The explicit data type is needed for future functionality, which will allow `foreach` to iterate over xref:xlat/index.adoc[dynamic expansions].
-
-.Example
-[source,unlang]
-----
-foreach string child (&TLV[*].Child-1) {
- &reply += {
- Reply-Message = "TLV contains %{child}"
- }
-}
-----
-
-When the iterator is an attribute reference, it is simplest to use `auto` as the data type. The `foreach` iterator will then create the local variable `<key-name>`, with the data type given by the attribute which is being looped over.
-
-In the example below, the `key` variable will have data type `octets`, as the `Class` attribute has data type `octets`.
-
-.Example of 'auto' type
-[source,unlang]
-----
-foreach auto key (&Class) {
- &reply += {
- Reply-Message = "Contains %{key}"
- }
-}
-----
-
== Modifying Loop variables
An attribute which is a "leaf" data type (e.g. `uint32`, and not
----
&Tmp-Integer-0 := { 1, 3, 5, 11 }
-foreach uint32 self (&Tmp-Integer-0) {
+foreach self (&Tmp-Integer-0) {
&self += 19
}
----
return cf_section_to_item(css);
}
- if (strcmp(stack->buff[1], "auto") == 0) {
- type = FR_TYPE_VOID;
+ fr_skip_whitespace(ptr);
- } else {
- type = fr_table_value_by_str(fr_type_table, stack->buff[1], FR_TYPE_NULL);
- switch (type) {
- default:
- break;
+ /*
+ *
+ */
+ if (*ptr == '(') {
+ type = FR_TYPE_NULL;
- case FR_TYPE_NULL:
- case FR_TYPE_VOID:
- case FR_TYPE_VALUE_BOX:
- case FR_TYPE_MAX:
- (void) parse_error(stack, ptr2, "Unknown or invalid variable type in 'foreach'");
- return NULL;
- }
+ strcpy(stack->buff[2], stack->buff[1]);
+ goto parse_expression;
+ }
+
+ type = fr_table_value_by_str(fr_type_table, stack->buff[1], FR_TYPE_NULL);
+ switch (type) {
+ default:
+ break;
+
+ case FR_TYPE_NULL:
+ case FR_TYPE_VOID:
+ case FR_TYPE_VALUE_BOX:
+ case FR_TYPE_MAX:
+ (void) parse_error(stack, ptr2, "Unknown or invalid variable type in 'foreach'");
+ return NULL;
}
fr_skip_whitespace(ptr);
/*
* "(" whitespace EXPRESSION whitespace ")"
*/
+parse_expression:
ptr++;
fr_skip_whitespace(ptr);
unlang_variable_t *var;
fr_dict_attr_t const *da = tmpl_attr_tail_da(vpt);
- type = fr_table_value_by_str(fr_type_table, type_name, FR_TYPE_NULL);
- fr_assert(type != FR_TYPE_NULL);
+ type = fr_table_value_by_str(fr_type_table, type_name, FR_TYPE_VOID);
+ fr_assert(type != FR_TYPE_VOID);
- if (type == FR_TYPE_VOID) type = da->type;
+ if (type == FR_TYPE_NULL) type = da->type;
variable_name = cf_section_argv(cs, 1);