fr_type_t type;
unlang_t *c;
+ fr_type_t key_type;
+ char const *key_name;
+
unlang_group_t *g;
unlang_foreach_t *gext;
*/
type_name = cf_section_argv(cs, 0); /* AFTER name1, name2 */
+ key_name = cf_section_argv(cs, 2);
+ if (key_name) {
+ key_type = fr_table_value_by_str(fr_type_table, key_name, FR_TYPE_VOID);
+ } else {
+ key_type = FR_TYPE_VOID;
+ }
+ key_name = cf_section_argv(cs, 3);
+
if (tmpl_is_xlat(vpt)) {
if (!type_name) {
/*
return NULL;
}
+ if ((key_type != FR_TYPE_VOID) && !fr_type_is_numeric(key_type)) {
+ cf_log_err(cs, "Invalid data type '%s' for 'key' variable - it should be numeric", fr_type_to_str(key_type));
+ return NULL;
+ }
+
goto get_name;
+ } else {
+ fr_assert(tmpl_is_attr(vpt));
+
+ if ((key_type != FR_TYPE_VOID) && (key_type != FR_TYPE_STRING)) {
+ cf_log_err(cs, "Invalid data type '%s' for 'key' variable - it should be 'string'", fr_type_to_str(key_type));
+ return NULL;
+ }
}
if (type_name) {
*/
gext->value = fr_dict_attr_by_name(NULL, var->root, variable_name);
fr_assert(gext->value != NULL);
+
+ /*
+ * Define the local key variable. Note that we don't copy any children.
+ */
+ if (key_type != FR_TYPE_VOID) {
+ if (define_local_variable(cf_section_to_item(cs), var, &t_rules, key_type, key_name, NULL) < 0) goto fail;
+
+ gext->key = fr_dict_attr_by_name(NULL, var->root, key_name);
+ fr_assert(gext->key != NULL);
+ }
}
if (!compile_children(g, &unlang_ctx2, true)) return NULL;
static int xlat_foreach_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; /* up to 10 for foreach */
+#define BUFFER_SIZE (256)
+
/** State of a foreach loop
*
*/
fr_pair_t *value; //!< local variable which contains the value
tmpl_t const *vpt; //!< pointer to the vpt
+ uint32_t index; //!< for xlat results
+ char *buffer; //!< for key values
+
bool success; //!< for xlat expansion
fr_value_box_list_t list; //!< value box list for looping over xlats
return UNLANG_ACTION_PUSHED_CHILD;
}
+static int unlang_foreach_key_update(request_t *request, unlang_frame_state_foreach_t *state)
+{
+ fr_value_box_clear_value(&state->key->data);
+
+ if (tmpl_is_attr(state->vpt)) {
+ if (tmpl_dcursor_print(&FR_SBUFF_IN(state->buffer, BUFFER_SIZE), &state->cc) > 0) {
+ fr_value_box_strdup(state->key, &state->key->data, NULL, state->buffer, false);
+ }
+ } else {
+ fr_value_box_t box;
+
+ fr_value_box(&box, state->index, false);
+
+ if (fr_value_box_cast(state->key, &state->key->data, state->key->vp_type, state->key->da, &box) < 0) {
+ RDEBUG("Failed casting 'foreach' key variable '%s' from %u", state->key->da->name, state->index);
+ return -1;
+ }
+ }
+
+ return 0;
+}
static unlang_action_t unlang_foreach_attr_next(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
return UNLANG_ACTION_CALCULATE_RESULT;
}
+ if (state->key) {
+ state->index++;
+
+ if (unlang_foreach_key_update(request, state) < 0) goto next;
+ }
+
/*
* Copy the data.
*/
vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
fr_assert(vp != NULL);
+ /*
+ * Update the key with the current path or index.
+ */
+ if (state->key) {
+ if (unlang_foreach_key_update(request, state) < 0) {
+ *p_result = RLM_MODULE_FAIL;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+ }
+
if (vp->vp_type == FR_TYPE_GROUP) {
fr_assert(state->value->vp_type == FR_TYPE_GROUP);
fr_assert(state->value != NULL);
if (tmpl_is_attr(gext->vpt)) {
+ if (gext->key) {
+ if (fr_pair_append_by_da(request->local_ctx, &state->key, &request->local_pairs, gext->key) < 0) {
+ REDEBUG("Failed creating %s", gext->key->name);
+ *p_result = RLM_MODULE_FAIL;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+ fr_assert(state->key != NULL);
+
+ MEM(state->buffer = talloc_array(state, char, BUFFER_SIZE));
+ }
+
return unlang_foreach_attr_init(p_result, request, frame, state);
}