if (tmpl_require_enum_prefix) return 0;
if (!t_rules->enumv) return 0;
+
+ } else if (t_rules->enumv &&
+ ((t_rules->enumv->type == FR_TYPE_IPV6_ADDR) ||
+ ((t_rules->enumv->type == FR_TYPE_IPV6_PREFIX)))) {
+
+ /*
+ * We can't have enumerated names for IPv6 addresses.
+ *
+ * @todo - allow them ONLY if the RHS string is a valid enum name.
+ */
+ return 0;
}
vpt = tmpl_alloc_null(ctx);
return tmpl_afrom_value_substr(ctx, out, in, quote, &my_t_rules, true, p_rules);
}
+ /*
+ * Prefer enum names to IPv6 addresses.
+ */
+ if (t_rules->enumv && fr_sbuff_is_str_literal(&our_in, "::")) {
+ slen = tmpl_afrom_enum(ctx, out, &our_in, p_rules, t_rules);
+ if (slen > 0) goto done_bareword;
+ fr_assert(!*out);
+ }
+
/*
* See if it's a boolean value
*/
* We can't parse it as anything, that's an error.
*/
if (tmpl_require_enum_prefix) {
- fr_strerror_const("Failed parsing input");
- FR_SBUFF_ERROR_RETURN(&our_in);
+ if (!fr_sbuff_is_str_literal(&our_in, "::")) {
+ fr_strerror_const("Failed parsing input");
+ FR_SBUFF_ERROR_RETURN(&our_in);
+ }
}
/*
unary->flags = func->flags;
unary->flags.impure_func = !func->flags.pure;
- if (tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, out_c, (c == '!')) < 0) {
+ if (tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, out_c, (c == '!')) <= 0) {
talloc_free(unary);
FR_SBUFF_ERROR_RETURN(&our_in);
}
}
our_t_rules.cast = FR_TYPE_NULL;
- our_t_rules.enumv = NULL;
+// our_t_rules.enumv = NULL;
+
+ /*
+ * As a special case, we allow
+ *
+ * &reply = "foo = bar"
+ *
+ * and then we don't parse the RHS as any enum.
+ */
+ if ( our_t_rules.enumv && !fr_type_is_leaf(our_t_rules.enumv->type)) {
+ our_t_rules.enumv = enumv = NULL;
+ }
/*
* If we still have '(', then recurse for other expressions
our_t_rules.cast = FR_TYPE_NULL;
our_t_rules.enumv = NULL;
+ fr_sbuff_skip_whitespace(&our_in);
+ if (fr_sbuff_is_char(&our_in, ')')) {
+ fr_strerror_printf("Empty expressions are invalid.");
+ FR_SBUFF_ERROR_RETURN(&our_in);
+ }
+
/*
* No input rules means "ignore external terminal sequences, as we're expecting a ')' as
* our terminal sequence.
*/
- if (tokenize_expression(head, &node, &our_in, bracket_rules, &our_t_rules, T_INVALID, bracket_rules, NULL, cond) < 0) {
+ if (tokenize_expression(head, &node, &our_in, bracket_rules, &our_t_rules, T_INVALID, bracket_rules, NULL, cond) <= 0) {
FR_SBUFF_ERROR_RETURN(&our_in);
}
* our_t_rules, and will try to parse any data there as
* of the correct type.
*/
- if (tmpl_afrom_substr(node, &vpt, &our_in, quote, p_rules, &our_t_rules) < 0) {
+ slen = tmpl_afrom_substr(node, &vpt, &our_in, quote, p_rules, &our_t_rules);
+ if ((slen < 0) || ((slen == 0) && (quote == T_BARE_WORD))) {
error:
FR_SBUFF_ERROR_RETURN(&our_in);
}
fr_sbuff_skip_whitespace(&our_in);
-#if 0
/*
* A bare word which is NOT a known attribute. That's an error.
*/
- if (tmpl_is_data_unresolved(vpt)) {
+ if (tmpl_require_enum_prefix && tmpl_is_data_unresolved(vpt)) {
fr_assert(quote == T_BARE_WORD);
fr_strerror_const("Failed parsing input");
fr_sbuff_set(&our_in, &opand_m);
goto error;
}
-#endif
/*
* The tmpl has a cast, and it's the same as the explicit cast we were given, we can sometimes
cast_type = FR_TYPE_NULL;
}
+ } else if (tmpl_is_attr_unresolved(vpt)) {
+ fr_assert(t_rules->attr.allow_unresolved);
+
} else if (tmpl_is_data_unresolved(vpt)) {
- /*
- * A bare word which is NOT a known attribute. That's an error.
- */
+ fr_assert(!tmpl_require_enum_prefix);
+
fr_assert(quote == T_BARE_WORD);
fr_strerror_const("Failed parsing input");
fr_sbuff_set(&our_in, &opand_m);
* Get the LHS of the operation.
*/
slen = tokenize_unary(head, &lhs, &our_in, p_rules, t_rules, bracket_rules, &c, cond);
- if (slen < 0) FR_SBUFF_ERROR_RETURN(&our_in);
+ if (slen <= 0) FR_SBUFF_ERROR_RETURN(&our_in);
if (slen == 0) {
fr_assert(lhs == NULL);
slen = tokenize_regex_rhs(head, &rhs, &our_in, t_rules, bracket_rules);
} else {
- slen = tokenize_expression(head, &rhs, &our_in, p_rules, t_rules, op, bracket_rules, input_rules, cond);
+ tmpl_rules_t our_t_rules = *t_rules;
+
+ /*
+ * The terminal rules for expressions includes "-" and "+", both of which are allowed in
+ * enum names. If we pass the enumv down to the next function, it will see
+ * "Access-Accept", and then only parse "Access". Which is wrong.
+ *
+ * For now, if we _don't_ have tmpl_require_enum_prefix, then we don't pass the enumv,
+ * and we somehow skip the entire enum name. The name is then resolved later by
+ * something...
+ */
+ if (tmpl_require_enum_prefix && (lhs->type == XLAT_TMPL) && tmpl_is_attr(lhs->vpt) &&
+ fr_sbuff_is_str_literal(&our_in, "::")) {
+ our_t_rules.enumv = tmpl_attr_tail_da(lhs->vpt);
+ }
+
+ slen = tokenize_expression(head, &rhs, &our_in, p_rules, &our_t_rules, op, bracket_rules, input_rules, cond);
}
- if (slen < 0) {
+ if (slen <= 0) {
talloc_free(lhs);
FR_SBUFF_ERROR_RETURN(&our_in);
}
talloc_free(bracket_rules);
talloc_free(terminal_rules);
- if (slen < 0) {
+ if (slen <= 0) {
talloc_free(head);
FR_SBUFF_ERROR_RETURN(in);
}
* error.
*/
if ((node->type == XLAT_TMPL) && tmpl_is_data_unresolved(node->vpt)) {
- fr_strerror_const("Unexpected text - attribute names must prefixed with '&'");
+ if (!tmpl_require_enum_prefix) {
+ fr_strerror_const("Unexpected text - attribute names must be prefixed with '&'");
+ } else {
+ fr_strerror_const("Unknown attribute");
+ }
return -1;
}