static ssize_t tokenize_expression(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules,
- fr_token_t prev, fr_sbuff_parse_rules_t const *bracket_rules, bool expect_regex);
+ fr_token_t prev, fr_sbuff_parse_rules_t const *bracket_rules,
+ fr_sbuff_parse_rules_t const *input_rules, bool expect_regex, int depth);
static ssize_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules,
- fr_sbuff_parse_rules_t const *bracket_rules, bool expect_regex);
+ fr_sbuff_parse_rules_t const *bracket_rules,
+ fr_sbuff_parse_rules_t const *input_rules, bool expect_regex, int depth);
static fr_table_num_sorted_t const expr_quote_table[] = {
{ L("\""), T_DOUBLE_QUOTED_STRING }, /* Don't re-order, backslash throws off ordering */
*/
static ssize_t tokenize_unary(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules,
- fr_sbuff_parse_rules_t const *bracket_rules, bool expect_regex)
+ fr_sbuff_parse_rules_t const *bracket_rules,
+ fr_sbuff_parse_rules_t const *input_rules, bool expect_regex, int depth)
{
ssize_t slen;
xlat_exp_t *node = NULL, *unary = NULL;
* that we return that, and not the child node
*/
if (!func) {
- return tokenize_field(head, out, in, p_rules, t_rules, bracket_rules, expect_regex);
+ return tokenize_field(head, out, in, p_rules, t_rules, bracket_rules, input_rules, expect_regex, depth);
}
MEM(unary = xlat_exp_alloc(head, XLAT_FUNC, func->name, strlen(func->name)));
unary->call.func = func;
unary->flags = func->flags;
- slen = tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, expect_regex);
- if (slen <= 0) {
+ slen = tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules, input_rules, expect_regex, depth);
+ if (slen < 0) {
talloc_free(unary);
FR_SBUFF_ERROR_RETURN_ADJ(&our_in, slen);
}
*/
static ssize_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules,
- fr_sbuff_parse_rules_t const *bracket_rules, bool expect_regex)
+ fr_sbuff_parse_rules_t const *bracket_rules,
+ fr_sbuff_parse_rules_t const *input_rules, bool expect_regex, int depth)
{
ssize_t slen;
xlat_exp_t *node = NULL;
* value when we get the output of the expression.
*/
if (fr_sbuff_next_if_char(&our_in, '(')) {
- slen = tokenize_expression(head, &node, &our_in, bracket_rules, t_rules, T_INVALID, bracket_rules, false);
+ slen = tokenize_expression(head, &node, &our_in, bracket_rules, t_rules, T_INVALID, bracket_rules, input_rules, false, depth + 1);
if (slen <= 0) {
FR_SBUFF_ERROR_RETURN_ADJ(&our_in, slen);
}
*/
static ssize_t tokenize_expression(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules,
- fr_token_t prev, fr_sbuff_parse_rules_t const *bracket_rules, bool expect_regex)
+ fr_token_t prev, fr_sbuff_parse_rules_t const *bracket_rules,
+ fr_sbuff_parse_rules_t const *input_rules, bool expect_regex, int depth)
{
xlat_exp_t *lhs = NULL, *rhs = NULL, *node;
xlat_t *func = NULL;
* Get the LHS of the operation.
*/
if (expect_regex) {
- slen = tokenize_field(head, &lhs, &our_in, p_rules, t_rules, bracket_rules, expect_regex);
+ slen = tokenize_field(head, &lhs, &our_in, p_rules, t_rules, bracket_rules, input_rules, expect_regex, depth);
} else {
- slen = tokenize_unary(head, &lhs, &our_in, p_rules, t_rules, bracket_rules, false);
+ slen = tokenize_unary(head, &lhs, &our_in, p_rules, t_rules, bracket_rules, input_rules, false, depth);
}
- if (slen <= 0) return slen;
+ if (slen < 0) return slen;
+ if (slen == 0) {
+ fr_assert(lhs == NULL);
+ *out = NULL;
+ return fr_sbuff_set(in, &our_in);
+ }
redo:
#ifdef __clang_analyzer__
}
fr_sbuff_skip_whitespace(&our_in);
+ /*
+ * We hit a terminal sequence, stop.
+ */
+ if (input_rules && (depth == 0) && fr_sbuff_is_terminal(&our_in, input_rules->terminals)) goto done;
+
/*
* Remember where we were after parsing the LHS.
*/
* We now parse the RHS, allowing a (perhaps different) cast on the RHS.
*/
XLAT_DEBUG(" recurse RHS <-- %pV", fr_box_strvalue_len(fr_sbuff_current(&our_in), fr_sbuff_remaining(&our_in)));
- slen = tokenize_expression(head, &rhs, &our_in, p_rules, t_rules, op, bracket_rules,
- ((op == T_OP_REG_EQ) || (op == T_OP_REG_NE)));
+ slen = tokenize_expression(head, &rhs, &our_in, p_rules, t_rules, op, bracket_rules, input_rules,
+ ((op == T_OP_REG_EQ) || (op == T_OP_REG_NE)), depth);
if (slen <= 0) {
talloc_free(lhs);
FR_SBUFF_ERROR_RETURN_ADJ(&our_in, slen);
t_rules = &my_rules;
}
- slen = tokenize_expression(head, &node, in, terminal_rules, t_rules, T_INVALID, bracket_rules, false);
+ slen = tokenize_expression(head, &node, in, terminal_rules, t_rules, T_INVALID, bracket_rules, p_rules, false, 0);
talloc_free(bracket_rules);
talloc_free(terminal_rules);
my_rules.xlat.runtime_el = el;
my_rules.at_runtime = true;
- slen = tokenize_expression(head, &node, in, terminal_rules, &my_rules, T_INVALID, bracket_rules, false);
+ slen = tokenize_expression(head, &node, in, terminal_rules, &my_rules, T_INVALID, bracket_rules, p_rules, false, 0);
talloc_free(bracket_rules);
talloc_free(terminal_rules);