*/
FR_DLIST_TYPES(tmpl_attr_list)
+/** Different types of filter that can be applied to an attribute reference
+ *
+ */
+typedef enum {
+ TMPL_ATTR_FILTER_TYPE_NONE = 0, //!< No filter present.
+ TMPL_ATTR_FILTER_TYPE_INDEX, //!< Filter is an index type.
+} tmpl_attr_filter_type_t;
+
+typedef struct {
+ tmpl_attr_filter_type_t _CONST type; //!< Type of filter this is.
+ int16_t _CONST num; //!< For array references.
+} tmpl_attr_filter_t;
+
/** An element in a list of nested attribute references
*
*/
typedef struct {
- FR_DLIST_ENTRY(tmpl_attr_list) _CONST entry; //!< Entry in the doubly linked list
+ FR_DLIST_ENTRY(tmpl_attr_list) _CONST entry; //!< Entry in the doubly linked list
///< of attribute references.
fr_dict_attr_t const * _CONST da; //!< Resolved dictionary attribute.
bool _CONST resolve_only; //!< This reference and those before it
///< in the list can only be used for
///< resolution, not building out trees.
- int16_t _CONST num; //!< For array references.
+
tmpl_attr_type_t _CONST type; //!< Type of attribute reference.
-} tmpl_attr_t;
+ tmpl_attr_filter_t _CONST filter; //!< Filter associated with the attribute reference.
+} tmpl_attr_t;
/** Define manipulation functions for the attribute reference list
*
#define ar_unresolved unresolved.name
#define ar_unresolved_raw unresolved.is_raw
#define ar_unresolved_namespace unresolved.namespace
-#define ar_num num
#define ar_is_normal(_ar) ((_ar)->ar_type == TMPL_ATTR_TYPE_NORMAL)
#define ar_is_unspecified(_ar) ((_ar)->ar_type == TMPL_ATTR_TYPE_UNSPEC)
#define ar_is_unknown(_ar) ((_ar)->ar_type == TMPL_ATTR_TYPE_UNKNOWN)
#define ar_is_unresolved(_ar) ((_ar)->ar_type == TMPL_ATTR_TYPE_UNRESOLVED)
+
+#define ar_num filter.num
+#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)
/** @} */
/** A source or sink of value data.
MEM(ar = talloc(ctx, tmpl_attr_t));
*ar = (tmpl_attr_t){
.type = type,
- .num = NUM_UNSPEC
+ .filter = {
+ .num = NUM_UNSPEC
+ }
};
tmpl_attr_list_insert_tail(tmpl_attr(vpt), ar);
}
/** @} */
-/** Descriptive return values for filter parsing
- *
- */
-typedef enum {
- TMPL_ATTR_REF_HAS_FILTER = 1,
- TMPL_ATTR_REF_NO_FILTER = 0,
- TMPL_ATTR_REF_BAD_FILTER = -1
-} tmpl_attr_filter_t;
-
/** Insert an attribute reference into a tmpl
*
* Not all attribute references can be used to create new attributes,
* @param[in] name containing more attribute ref data.
* @param[in] t_rules see tmpl_attr_afrom_attr_substr.
* @return
- * - TMPL_ATTR_REF_HAS_FILTER on success with filter parsed.
- * - TMPL_ATTR_REF_NO_FILTER on success with no filter.
- * - TMPL_ATTR_REF_BAD_FILTER on failure.
+ * - >0 if a filter was parsed.
+ * - 0 if no filter was available.
+ * - <0 on filter parse error.
*/
-static tmpl_attr_filter_t tmpl_attr_parse_filter(tmpl_attr_error_t *err, tmpl_attr_t *ar,
- fr_sbuff_t *name, tmpl_attr_rules_t const *t_rules)
+static fr_slen_t tmpl_attr_parse_filter(tmpl_attr_error_t *err, tmpl_attr_t *ar,
+ fr_sbuff_t *name, tmpl_attr_rules_t const *t_rules)
{
+ fr_sbuff_t our_name = FR_SBUFF(name);
+
/*
* Parse array subscript (and eventually complex filters)
*/
- if (!fr_sbuff_next_if_char(name, '[')) return TMPL_ATTR_REF_NO_FILTER;
+ if (!fr_sbuff_next_if_char(&our_name, '[')) return 0;
if (t_rules->disallow_filters) {
fr_strerror_const("Filters not allowed here");
if (err) *err = TMPL_ATTR_ERROR_FILTER_NOT_ALLOWED;
-
- return TMPL_ATTR_REF_BAD_FILTER;
+ return -1; /* Error at index 0 */
}
- switch (*fr_sbuff_current(name)) {
+ ar->ar_filter_type = TMPL_ATTR_FILTER_TYPE_INDEX;
+ fr_sbuff_switch(&our_name, '\0') {
case '#':
ar->ar_num = NUM_COUNT;
- fr_sbuff_next(name);
+ fr_sbuff_next(&our_name);
break;
case '*':
ar->ar_num = NUM_ALL;
- fr_sbuff_next(name);
+ fr_sbuff_next(&our_name);
break;
case 'n':
ar->ar_num = NUM_LAST;
- fr_sbuff_next(name);
+ fr_sbuff_next(&our_name);
break;
+ /* Used as EOB here */
+ missing_closing:
+ case '\0':
+ fr_strerror_const("No closing ']' for array index");
+ if (err) *err = TMPL_ATTR_ERROR_INVALID_ARRAY_INDEX;
+ error:
+ return fr_sbuff_error(&our_name);
+
default:
{
fr_sbuff_parse_error_t sberr = FR_SBUFF_PARSE_OK;
- fr_sbuff_t tmp = FR_SBUFF(name);
+ fr_sbuff_t tmp = FR_SBUFF(&our_name);
if (fr_sbuff_out(&sberr, &ar->ar_num, &tmp) < 0) {
if (sberr == FR_SBUFF_PARSE_ERROR_NOT_FOUND) {
fr_strerror_const("Invalid array index");
if (err) *err = TMPL_ATTR_ERROR_INVALID_ARRAY_INDEX;
- error:
- return TMPL_ATTR_REF_BAD_FILTER;
+ goto error;
}
fr_strerror_const("Invalid array index");
if (err) *err = TMPL_ATTR_ERROR_INVALID_ARRAY_INDEX;
goto error;
}
- fr_sbuff_set(name, &tmp); /* Advance name _AFTER_ doing checks */
+ fr_sbuff_set(&our_name, &tmp); /* Advance name _AFTER_ doing checks */
}
break;
}
* Always advance here, so the error
* marker points to the bad char.
*/
- if (!fr_sbuff_next_if_char(name, ']')) {
- fr_strerror_const("No closing ']' for array index");
- if (err) *err = TMPL_ATTR_ERROR_INVALID_ARRAY_INDEX;
- goto error;
- }
+ if (!fr_sbuff_next_if_char(&our_name, ']')) goto missing_closing;
- return TMPL_ATTR_REF_HAS_FILTER;
+ return fr_sbuff_set(name, &our_name);
}
/** Parse an unresolved attribute, i.e. one which can't be found in the current dictionary
int ret;
char *unresolved;
size_t len;
+ fr_slen_t slen;
if (depth > FR_DICT_MAX_TLV_STACK) {
fr_strerror_const("Attribute nesting too deep");
.ar_parent = parent,
};
- if (tmpl_attr_parse_filter(err, ar, name, t_rules) < 0) goto error;
-
+ slen = tmpl_attr_parse_filter(err, ar, name, t_rules);
+ if (slen < 0) {
+ fr_sbuff_advance(name, -slen);
+ goto error;
+ }
/*
* Insert the ar into the list of attribute references
*/
tmpl_attr_t *ar = NULL;
fr_dict_attr_t const *da;
fr_sbuff_marker_t m_s;
- tmpl_attr_filter_t filter;
fr_dict_attr_err_t dict_err;
fr_dict_attr_t const *our_parent = parent;
* - The type of attribute.
* - If this is the leaf attribute reference.
*/
- if ((filter = tmpl_attr_parse_filter(err, ar, name, t_rules)) == TMPL_ATTR_REF_BAD_FILTER) goto error;
+ slen = tmpl_attr_parse_filter(err, ar, name, t_rules);
+ if (slen < 0) {
+ fr_sbuff_advance(name, -slen);
+ goto error;
+ }
/*
* At the end of the attribute reference. If there's a
if (main_config && main_config->tmpl_tokenize_all_nested) {
our_parent = da; /* Only update the parent if we're not stripping */
- } else if ((filter == TMPL_ATTR_REF_NO_FILTER) && (ar->type == TMPL_ATTR_TYPE_NORMAL)) {
+ } else if (ar_filter_is_none(ar) && ar_is_normal(ar)) {
TALLOC_FREE(ar);
} else {
our_parent = da; /* Only update the parent if we're not stripping */
*/
if (!t_attr_rules->list_as_attr && (tmpl_attr_list_num_elements(&vpt->data.attribute.ar) == 0)) {
tmpl_attr_t *ar;
+ fr_slen_t slen;
MEM(ar = talloc_zero(vpt, tmpl_attr_t));
- switch (tmpl_attr_parse_filter(err, ar, &our_name, t_attr_rules)) {
- case 0: /* No filter */
+ slen = tmpl_attr_parse_filter(err, ar, &our_name, t_attr_rules);
+ if (slen == 0) { /* No filter */
talloc_free(ar);
- break;
-
- case 1: /* Found a filter */
+ } else if (slen > 0) { /* Found a filter */
tmpl_attr_list_insert_tail(&vpt->data.attribute.ar, ar);
- break;
-
- default: /* Parse error */
+ } else if (slen < 0) { /* Filter error */
+ fr_sbuff_advance(&our_name, -slen);
goto error;
}
-
vpt->type = TMPL_TYPE_LIST;
}