*
* Defaults are used if a NULL rules pointer is passed to the parsing function.
*/
-#define DEFAULT_RULES tmpl_rules_t const default_rules = { .attr = { .list_def = request_attr_request }}
+#define DEFAULT_RULES tmpl_rules_t default_rules = { .attr = { .list_def = request_attr_request }}
+
+#define CHECK_T_RULES do { \
+ if (!t_rules) { \
+ t_rules = &default_rules; \
+ if (tmpl_require_enum_prefix) default_rules.attr.prefix = TMPL_ATTR_REF_PREFIX_AUTO; \
+ } else if (tmpl_require_enum_prefix && (t_rules->attr.prefix == TMPL_ATTR_REF_PREFIX_YES)) { \
+ default_rules = *t_rules; \
+ default_rules.attr.prefix = TMPL_ATTR_REF_PREFIX_AUTO; \
+ t_rules = &default_rules; \
+ } \
+ } while (0)
/* clang-format off */
tmpl_attr_rules_t const *at_rules;
DEFAULT_RULES;
- if (!t_rules) {
- at_rules = &default_rules.attr;
- } else {
- at_rules = &t_rules->attr;
- }
+ CHECK_T_RULES;
+ at_rules = &t_rules->attr;
/*
* The caller wants to know the default namespace for
tmpl_request_list_talloc_reverse_free(&dst->data.attribute.rr);
tmpl_request_ref_list_copy(dst, &dst->data.attribute.rr, &src->data.attribute.rr);
+ /*
+ * Ensure that we copy over any parsing rules, defaults, etc.
+ */
+ dst->rules = src->rules;
+
TMPL_ATTR_VERIFY(dst);
return 0;
fr_dict_attr_err_t dict_err;
fr_dict_attr_t const *our_parent = parent;
+ fr_assert(!tmpl_require_enum_prefix || (vpt->rules.attr.prefix != TMPL_ATTR_REF_PREFIX_YES));
+
fr_sbuff_marker(&m_s, name);
if (depth > FR_DICT_MAX_TLV_STACK) {
if (tmpl_is_attr(vpt) && tmpl_attr_tail_is_normal(vpt) &&
(tmpl_rules_cast(vpt) == tmpl_attr_tail_da(vpt)->type)) vpt->rules.cast = FR_TYPE_NULL;
+ TMPL_VERIFY(vpt);
+
fr_sbuff_marker_release(&m_s);
return 0;
}
fr_sbuff_t our_name = FR_SBUFF(name); /* Take a local copy in case we need to back track */
bool is_raw = false;
tmpl_attr_rules_t const *at_rules;
+ tmpl_attr_rules_t our_at_rules;
fr_sbuff_marker_t m_l;
fr_dict_attr_t const *namespace;
DEFAULT_RULES;
- if (!t_rules) t_rules = &default_rules;
+ CHECK_T_RULES;
+
at_rules = &t_rules->attr;
+ fr_assert(!tmpl_require_enum_prefix || (at_rules->prefix != TMPL_ATTR_REF_PREFIX_YES));
+
if (err) *err = TMPL_ATTR_ERROR_NONE;
if (!fr_sbuff_extend(&our_name)) {
}
break;
}
+
+ /*
+ * Rewrite the prefix parsing to "auto", which affects the printing.
+ */
+ our_at_rules = *at_rules;
+ our_at_rules.prefix = TMPL_ATTR_REF_PREFIX_AUTO;
+ at_rules = &our_at_rules;
+
FALL_THROUGH; /* if we do require enum prefixes, then the '&' is optional */
case TMPL_ATTR_REF_PREFIX_AUTO:
*/
MEM(vpt = tmpl_alloc(ctx, TMPL_TYPE_ATTR, T_BARE_WORD, NULL, 0));
vpt->data.attribute.ref_prefix = TMPL_ATTR_REF_PREFIX_YES;
+ vpt->rules.attr.prefix = at_rules->prefix;
/*
* The "raw." prefix marks up the leaf attribute
fr_assert(ar != NULL);
if (tmpl_attr_is_list_attr(ar)) vpt->rules.attr.list_def = ar->ar_da;
+
+ fr_assert(!tmpl_require_enum_prefix || (vpt->rules.attr.prefix != TMPL_ATTR_REF_PREFIX_YES));
+
}
if (!tmpl_substr_terminal_check(&our_name, p_rules)) {
ssize_t slen, name_len;
DEFAULT_RULES;
- if (!t_rules) t_rules = &default_rules; /* Use the defaults */
+ CHECK_T_RULES;
name_len = strlen(name);
slen = tmpl_afrom_attr_substr(ctx, err, out, &FR_SBUFF_IN(name, name_len), NULL, t_rules);
tmpl_t *vpt = NULL;
DEFAULT_RULES;
- if (!t_rules) t_rules = &default_rules; /* Use the defaults */
+ CHECK_T_RULES;
*out = NULL;
if (slen > 0) goto done_bareword;
fr_assert(!*out);
+ fr_assert(!tmpl_require_enum_prefix || (t_rules->attr.prefix != TMPL_ATTR_REF_PREFIX_YES));
+
/*
* See if it's an attribute reference
* without the prefix.
if (unlikely(xlat_copy(vpt, vpt->data.xlat.ex, in->data.xlat.ex) < 0)) goto error;
}
+ TMPL_ATTR_VERIFY(vpt);
+
return vpt;
}
fr_assert(0);
}
+ TMPL_VERIFY(vpt);
+
return ret;
}
return 0;
}
+ /*
+ * Suppress the prefix on new syntax.
+ */
+ if (tmpl_require_enum_prefix && (ar_prefix == TMPL_ATTR_REF_PREFIX_YES)) {
+ ar_prefix = TMPL_ATTR_REF_PREFIX_AUTO;
+ }
+
/*
* Handle printing the request reference
* prefix.
TMPL_VERIFY(vpt);
+ /*
+ * Suppress the prefix on new syntax.
+ */
+ if (tmpl_require_enum_prefix && (ar_prefix == TMPL_ATTR_REF_PREFIX_YES)) {
+ ar_prefix = TMPL_ATTR_REF_PREFIX_AUTO;
+ }
+
switch (vpt->type) {
case TMPL_TYPE_ATTR_UNRESOLVED:
case TMPL_TYPE_ATTR:
fr_assert(tmpl_is_attr_unresolved(vpt) || tmpl_is_attr(vpt));
+ fr_assert(!tmpl_require_enum_prefix || (vpt->rules.attr.prefix != TMPL_ATTR_REF_PREFIX_YES));
+
/*
* Loop detection
*/
if (!tmpl_is_attr(vpt)) return;
+ fr_assert(!tmpl_require_enum_prefix || (vpt->rules.attr.prefix != TMPL_ATTR_REF_PREFIX_YES));
+
da = tmpl_attr_tail_da(vpt);
/*
/*
* Anal-retentive checks.
*/
- if (DEBUG_ENABLED3) {
+ if (!tmpl_require_enum_prefix && DEBUG_ENABLED3) {
if (tmpl_is_attr(map->lhs) && (map->lhs->name[0] != '&')) {
cf_log_warn(cp, "Please change attribute reference to '&%s %s ...'",
map->lhs->name, fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
/*
* Anal-retentive checks.
*/
- if (DEBUG_ENABLED3) {
+ if (!tmpl_require_enum_prefix && DEBUG_ENABLED3) {
if (tmpl_is_attr(map->lhs) && (map->lhs->name[0] != '&')) {
cf_log_warn(cp, "Please change attribute reference to '&%s %s ...'",
map->lhs->name, fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
/*
* Anal-retentive checks.
*/
- if (DEBUG_ENABLED3) {
+ if (!tmpl_require_enum_prefix && DEBUG_ENABLED3) {
if (tmpl_is_attr(map->lhs) && (map->lhs->name[0] != '&')) {
cf_log_warn(cp, "Please change attribute reference to '&%s %s ...'",
map->lhs->name, fr_table_str_by_value(fr_tokens_table, map->op, "<INVALID>"));
# define XLAT_HEXDUMP(...)
#endif
+extern bool tmpl_require_enum_prefix;
+
/** These rules apply to literal values and function arguments inside of an expansion
*
*/
xlat_exp_t *node;
fr_sbuff_marker_t m_s;
- tmpl_rules_t our_t_rules;
+ tmpl_rules_t our_t_rules;
XLAT_DEBUG("ATTRIBUTE <-- %.*s", (int) fr_sbuff_remaining(in), fr_sbuff_current(in));
+ /*
+ * Suppress the prefix on new syntax.
+ */
+ if (tmpl_require_enum_prefix && (attr_prefix == TMPL_ATTR_REF_PREFIX_YES)) {
+ attr_prefix = TMPL_ATTR_REF_PREFIX_AUTO;
+ }
+
/*
* We need a local copy as we always allow unknowns.
* This is because not all attribute references
}
done:
+ /*
+ * Remember that it was %{User-Name}
+ *
+ * This is a temporary hack until all of the unit tests
+ * pass without '&'.
+ */
+ UNCONST(tmpl_attr_rules_t *, &vpt->rules.attr)->xlat = true;
+
/*
* Attributes and module calls aren't pure.
*/
fr_assert(talloc_parent(node->vpt) == node);
fr_assert(!node->flags.pure);
+ /*
+ * Can't have prefix YES if we're using the new flag. The parser / tmpl alloc routines
+ * MUST have set this to prefix AUTO.
+ */
+ fr_assert(!tmpl_require_enum_prefix || (node->vpt->rules.attr.prefix != TMPL_ATTR_REF_PREFIX_YES));
+
/*
* Parsing &User-Name or User-Name gets printed as &User-Name.
*
FR_SBUFF_IN_STRCPY_RETURN(out, node->fmt);
goto done;
}
+
+ /*
+ * No '&', print the name, BUT without any attribute prefix.
+ */
+ if (tmpl_require_enum_prefix && !node->vpt->rules.attr.xlat) {
+ char const *p = node->fmt;
+
+ if (*p == '&') p++;
+
+ FR_SBUFF_IN_STRCPY_RETURN(out, p);
+ goto done;
+ }
break;
case XLAT_ONE_LETTER:
* tmpl tokenizer, and then pass the tmpl to the function. Which also means that
* we need to be able to have a fr_value_box_t which holds a ptr to a tmpl. And
* update the function arguments to say "we want a tmpl, not a string".
+ *
+ * @todo - tmpl_require_enum_prefix
*/
if (allow_attr && fr_sbuff_is_char(&our_in, '&')) {
if (xlat_tokenize_attribute(node->group, &our_in, our_p_rules, t_rules, TMPL_ATTR_REF_PREFIX_YES) < 0) goto error;