TMPL_ATTR_FILTER_TYPE_INDEX, //!< Filter is an index type.
TMPL_ATTR_FILTER_TYPE_CONDITION, //!< Filter is a condition
TMPL_ATTR_FILTER_TYPE_TMPL, //!< Filter is a tmpl
+ TMPL_ATTR_FILTER_TYPE_EXPR, //!< Filter is an expression
} tmpl_attr_filter_type_t;
typedef struct {
union {
xlat_exp_head_t _CONST *cond; //!< xlat condition
tmpl_t _CONST *tmpl; //!< tmpl
+ xlat_exp_head_t _CONST *expr; //!< xlat expression
};
} tmpl_attr_filter_t;
#define ar_num filter.num
#define ar_cond filter.cond
#define ar_tmpl filter.tmpl
+#define ar_expr filter.expr
#define ar_filter_type filter.type
#define ar_filter_is_none(_ar) ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_NONE)
#define ar_filter_is_num(_ar) ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_INDEX)
#define ar_filter_is_cond(_ar) ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_CONDITION)
#define ar_filter_is_tmpl(_ar) ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_TMPL)
+#define ar_filter_is_expr(_ar) ((_ar)->ar_filter_type == TMPL_ATTR_FILTER_TYPE_EXPR)
/** @} */
/** A source or sink of value data.
slen = xlat_tokenize_condition(ar, &ar->ar_cond, &tmp, &p_rules, &t_rules);
if (slen < 0) goto error;
+ fr_assert(!xlat_impure_func(ar->ar_cond));
+
ar->ar_filter_type = TMPL_ATTR_FILTER_TYPE_CONDITION;
fr_sbuff_set(&our_name, &tmp); /* Advance name _AFTER_ doing checks */
break;
}
+ case '%': /* ${...} expansion */
+ {
+ fr_sbuff_t tmp = FR_SBUFF(&our_name);
+ fr_slen_t slen;
+ tmpl_rules_t t_rules;
+ fr_sbuff_parse_rules_t p_rules;
+ fr_sbuff_term_t const filter_terminals = FR_SBUFF_TERMS(L("]"));
+
+ if (!fr_sbuff_is_str(&our_name, "%{", 2)) {
+ fr_strerror_const("Invalid expression in attribute index");
+ goto error;
+ }
+
+ tmp = FR_SBUFF(&our_name);
+ t_rules = (tmpl_rules_t) {};
+ t_rules.attr = *at_rules;
+
+ p_rules = (fr_sbuff_parse_rules_t) {
+ .terminals = &filter_terminals,
+ .escapes = NULL
+ };
+
+ /*
+ * Check if it's an expression.
+ */
+ slen = xlat_tokenize_expression(ar, &ar->ar_cond, &tmp, &p_rules, &t_rules);
+ if (slen < 0) goto error;
+
+ if (xlat_impure_func(ar->ar_expr)) {
+ fr_strerror_const("Expression in attribute index cannot depend on functions which call external databases");
+ goto error;
+ }
+
+ ar->ar_filter_type = TMPL_ATTR_FILTER_TYPE_EXPR;
+
+ fr_sbuff_set(&our_name, &tmp); /* Advance name _AFTER_ doing checks */
+ break;
+ }
+
case 'n':
/*
* [n] is the last one
if (slen <= 0) goto error;
if (!tmpl_is_attr(ar->ar_tmpl)) {
- fr_strerror_printf("Invalid array index");
+ fr_strerror_const("Invalid array index");
goto error;
}
* For matching therefore, we really need to have a way to define "self".
*/
if (!fr_type_numeric[tmpl_attr_tail_da(ar->ar_tmpl)->type]) {
- fr_strerror_printf("Invalid data type for array index (must be numeric)");
+ fr_strerror_const("Invalid data type for array index (must be numeric)");
goto error;
}