size_t at_in = fr_sbuff_used_total(out);
xlat_exp_t *child = xlat_exp_head(node->call.args);
+ fr_assert(child != NULL);
+
FR_SBUFF_IN_CHAR_RETURN(out, '(');
xlat_print_node(out, node->call.args, child, e_rules); /* prints a space after the first argument */
*/
FR_SBUFF_IN_STRCPY_RETURN(out, fr_tokens[node->call.func->token]);
FR_SBUFF_IN_CHAR_RETURN(out, ' ');
+
child = xlat_exp_next(node->call.args, child);
+ fr_assert(child != NULL);
+
xlat_print_node(out, node->call.args, child, e_rules);
FR_SBUFF_IN_CHAR_RETURN(out, ')');
static void xlat_func_append_arg(xlat_exp_t *head, xlat_exp_t *node)
{
- xlat_exp_t *group, **tail;
+ xlat_exp_t *group;
fr_assert(head->type == XLAT_FUNC);
fr_assert(node->type != XLAT_GROUP);
group->fmt = node->fmt; /* not entirely correct, but good enough for now */
MEM(group->group = xlat_exp_head_alloc(group));
- group->group->next = talloc_steal(group->group, node);
+ talloc_steal(group->group, node);
+ xlat_exp_insert_tail(group->group, node);
- group->flags = node->flags;
- xlat_flags_merge(&head->call.args->flags, &group->flags);
- xlat_flags_merge(&head->flags, &group->flags);
+ xlat_exp_insert_tail(head->call.args, group);
- tail = &head->call.args->next;
- while (*tail) tail = &((*tail)->next);
-
- *tail = group;
+ xlat_flags_merge(&head->flags, &head->call.args->flags);
}
fr_sbuff_parse_rules_t const *bracket_rules)
{
ssize_t slen;
- xlat_exp_t *unary = NULL;
+ xlat_exp_t *node, *unary = NULL;
xlat_t *func = NULL;
+ char const *fmt = NULL;
fr_sbuff_t our_in = FR_SBUFF(in);
XLAT_DEBUG("UNARY <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
* we allocate.
*/
if (fr_sbuff_next_if_char(&our_in, '!')) { /* unary not */
+ fmt = "!";
func = xlat_func_find("unary_not", 9);
fr_assert(func != NULL);
}
else if (fr_sbuff_next_if_char(&our_in, '-')) { /* unary minus */
+ fmt = "-";
func = xlat_func_find("unary_minus", 11);
fr_assert(func != NULL);
}
MEM(unary = xlat_exp_alloc(head, XLAT_FUNC, func->name, strlen(func->name)));
MEM(unary->call.args = xlat_exp_head_alloc(unary));
+ unary->fmt = fmt;
unary->call.func = func;
unary->flags = func->flags;
- slen = tokenize_field(unary->call.args, &unary->call.args->next, &our_in, p_rules, t_rules, bracket_rules);
+ slen = tokenize_field(unary->call.args, &node, &our_in, p_rules, t_rules, bracket_rules);
if (slen <= 0) {
talloc_free(unary);
FR_SBUFF_ERROR_RETURN_ADJ(&our_in, slen);
}
- if (!xlat_exp_head(unary->call.args)) {
+ if (!node) {
fr_strerror_const("Empty expression is invalid");
FR_SBUFF_ERROR_RETURN_ADJ(&our_in, -slen);
}
- *out = unary;
- xlat_flags_merge(&head->flags, &unary->flags);
+ xlat_exp_insert_tail(unary->call.args, node);
+ xlat_flags_merge(&unary->flags, &unary->call.args->flags);
+ /*
+ * Don't add it to head->flags, that will be done when it's actually inserted.
+ */
+
+ *out = unary;
return fr_sbuff_set(in, &our_in);
}
#endif
*out = node;
- xlat_flags_merge(&head->flags, &node->flags);
return fr_sbuff_set(in, &our_in);
}
* (EXPR)
* !EXPR
* A OP B
+ *
+ * If "out" is NULL then the expression is added to "head".
+ * Otherwise, it's returned to the caller.
*/
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,
*/
if (fr_sbuff_extend(&our_in) == 0) {
done:
- *out = lhs;
+
+ if (!out) {
+ xlat_exp_insert_tail(head, lhs);
+ } else {
+ *out = lhs;
+ }
+
return fr_sbuff_set(in, &our_in);
}
}
/*
- * @todo - purify the node.
- *
* @todo - also if the have differenting data types on the LHS and RHS, and one of them is an
* XLAT_BOX, then try to upcast the XLAT_BOX to the destination data type before returning. This
* optimization minimizes the amount of run-time work we have to do.
xlat_func_append_arg(node, lhs);
xlat_func_append_arg(node, rhs);
+ fr_assert(xlat_exp_head(node->call.args) != NULL);
+
lhs = node;
goto redo;
}
MEM(head = xlat_exp_head_alloc(ctx));
- slen = tokenize_expression(head, &head->next, in, terminal_rules, t_rules, T_INVALID, bracket_rules);
+ slen = tokenize_expression(head, NULL, in, terminal_rules, t_rules, T_INVALID, bracket_rules);
talloc_free(bracket_rules);
talloc_free(terminal_rules);
MEM(head = xlat_exp_head_alloc(ctx));
- slen = tokenize_expression(head, &head->next, in, terminal_rules, &my_rules, T_INVALID, bracket_rules);
+ slen = tokenize_expression(head, NULL, in, terminal_rules, &my_rules, T_INVALID, bracket_rules);
talloc_free(bracket_rules);
talloc_free(terminal_rules);
xlat_flags_t flags; //!< Flags that control resolution and evaluation.
xlat_type_t type; //!< type of this expansion.
- xlat_exp_t *next; //!< Next in the list.
+ fr_dlist_t entry;
union {
xlat_exp_head_t *alternate[2]; //!< alternate expansions
struct xlat_exp_head {
char const *fmt; //!< The original format string (a talloced buffer).
xlat_flags_t flags; //!< Flags that control resolution and evaluation.
- xlat_exp_t *next; //!< Next in the list.
+ fr_dlist_head_t dlist;
};
/*
* xlat_tokenize.c
*/
-int xlat_tokenize_expansion(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
+int xlat_tokenize_expansion(xlat_exp_head_t *head, fr_sbuff_t *in,
tmpl_attr_rules_t const *t_rules);
-int xlat_tokenize_function_args(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
+int xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in,
tmpl_attr_rules_t const *rules);
ssize_t xlat_print_node(fr_sbuff_t *out, xlat_exp_head_t const *head, xlat_exp_t const *node, fr_sbuff_escape_rules_t const *e_rules);
static inline xlat_exp_t *xlat_exp_head(xlat_exp_head_t const *head)
{
- if (!head || !head->next) return NULL;
+ if (!head) return NULL;
- return UNCONST(xlat_exp_t *, (head->next));
+ return fr_dlist_head(&head->dlist);
}
/** Iterate over the contents of a list, only one level
* @param[in] _iter Name of iteration variable.
* Will be declared in the scope of the loop.
*/
-#define xlat_exp_foreach(_list_head, _iter) \
- for (xlat_exp_t *_iter = xlat_exp_head(_list_head); _iter; _iter = _iter->next)
+#define xlat_exp_foreach(_list_head, _iter) fr_dlist_foreach(&((_list_head)->dlist), xlat_exp_t, _iter)
-static inline xlat_exp_t *xlat_exp_next(UNUSED xlat_exp_head_t const *head, xlat_exp_t const *item)
+static inline xlat_exp_t *xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
{
- if (!item->next) return NULL;
+ return fr_dlist_next(&head->dlist, node);
+}
- return UNCONST(xlat_exp_t *, item->next);
+static inline int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
+{
+ xlat_flags_merge(&head->flags, &node->flags);
+ return fr_dlist_insert_tail(&head->dlist, node);
}
static inline xlat_exp_head_t *xlat_exp_head_alloc(TALLOC_CTX *ctx)
{
- return talloc_zero(ctx, xlat_exp_head_t);
+ xlat_exp_head_t *head;
+
+ head = talloc_zero(ctx, xlat_exp_head_t);
+ if (!head) return NULL;
+
+ fr_dlist_init(&head->dlist, xlat_exp_t, entry);
+ return head;
}
#ifdef __cplusplus
}
#endif
-/** Free a linked list of xlat nodes
- *
- * @param[in,out] head to free. Will be set to NULL
- */
-void xlat_exp_free(xlat_exp_head_t **head)
-{
- xlat_exp_t *to_free = xlat_exp_head(*head), *next;
-
- while (to_free) {
- next = to_free->next;
- talloc_free(to_free);
- to_free = next;
- };
- *head = NULL;
-}
-
static int xlat_tokenize_string(xlat_exp_head_t *head, fr_sbuff_t *in, bool brace,
fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *t_rules);
-static inline int xlat_tokenize_alternation(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
+static inline int xlat_tokenize_alternation(xlat_exp_head_t *head, fr_sbuff_t *in,
tmpl_attr_rules_t const *t_rules, bool func_args)
{
xlat_exp_t *node;
MEM(node->alternate[1] = xlat_exp_head_alloc(node));
if (func_args) {
- if (xlat_tokenize_function_args(node->alternate[0], &node->alternate[0]->next, in, t_rules) < 0) {
+ if (xlat_tokenize_function_args(node->alternate[0], in, t_rules) < 0) {
error:
talloc_free(node);
return -1;
}
} else {
- if (xlat_tokenize_expansion(node->alternate[0], &node->alternate[0]->next, in, t_rules) < 0) goto error;
+ if (xlat_tokenize_expansion(node->alternate[0], in, t_rules) < 0) goto error;
}
if (!fr_sbuff_adv_past_str_literal(in, ":-")) {
if (xlat_tokenize_string(node->alternate[1], in,
true, &xlat_expansion_rules, t_rules) < 0) goto error;
- if (!node->alternate[1]->next) {
+ if (!xlat_exp_head(node->alternate[1])) {
talloc_free(node);
fr_strerror_const("Empty expansion is invalid");
goto error;
xlat_flags_merge(&node->flags, &node->alternate[1]->flags);
done:
- xlat_flags_merge(&head->flags, &node->flags);
- *out = node;
+ xlat_exp_insert_tail(head, node);
return 0;
}
* @verbatim %{<num>} @endverbatim
*
*/
-static inline int xlat_tokenize_regex(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in)
+static inline int xlat_tokenize_regex(xlat_exp_head_t *head, fr_sbuff_t *in)
{
uint8_t num;
xlat_exp_t *node;
fr_sbuff_marker_release(&m_s);
fr_sbuff_next(in); /* Skip '}' */
- xlat_flags_merge(&head->flags, &node->flags);
- *out = node;
+ xlat_exp_insert_tail(head, node);
return 0;
}
* - 0 if the string was parsed into a function.
* - <0 on parse error.
*/
-static inline int xlat_tokenize_function_mono(xlat_exp_head_t *head, xlat_exp_t **out,
+static inline int xlat_tokenize_function_mono(xlat_exp_head_t *head,
fr_sbuff_t *in,
tmpl_attr_rules_t const *rules)
{
if (!fr_sbuff_is_char(in, ':')) {
fr_strerror_const("Can't find function/argument separator");
bad_function:
- *out = NULL;
fr_sbuff_set(in, &m_s); /* backtrack */
fr_sbuff_marker_release(&m_s);
return -1;
}
xlat_flags_merge(&node->flags, &node->call.args->flags);
- xlat_flags_merge(&head->flags, &node->flags);
- *out = node;
+ xlat_exp_insert_tail(head, node);
return 0;
}
* - 0 if the string was parsed into a function.
* - <0 on parse error.
*/
-int xlat_tokenize_function_args(xlat_exp_head_t *head, xlat_exp_t **out,
- fr_sbuff_t *in,
+int xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in,
tmpl_attr_rules_t const *rules)
{
xlat_exp_t *node;
if (!fr_sbuff_is_char(in, ':')) {
fr_strerror_const("Can't find function/argument separator");
bad_function:
- *out = NULL;
fr_sbuff_set(in, &m_s); /* backtrack */
fr_sbuff_marker_release(&m_s);
return -1;
goto error;
}
- xlat_flags_merge(&head->flags, &node->flags);
- *out = node;
+ xlat_exp_insert_tail(head, node);
return 0;
}
/** Parse an attribute ref or a virtual attribute
*
*/
-static inline int xlat_tokenize_attribute(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
+static inline int xlat_tokenize_attribute(xlat_exp_head_t *head, fr_sbuff_t *in,
fr_sbuff_parse_rules_t const *p_rules, tmpl_attr_rules_t const *t_rules)
{
ssize_t slen;
*/
if (err == TMPL_ATTR_ERROR_MISSING_TERMINATOR) fr_sbuff_set(in, &m_s);
error:
- *out = NULL;
fr_sbuff_marker_release(&m_s);
talloc_free(node);
return -1;
goto error;
}
- xlat_flags_merge(&head->flags, &node->flags);
- *out = node;
+ xlat_exp_insert_tail(head, node);
+
fr_sbuff_marker_release(&m_s);
return 0;
}
-int xlat_tokenize_expansion(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuff_t *in,
+int xlat_tokenize_expansion(xlat_exp_head_t *head, fr_sbuff_t *in,
tmpl_attr_rules_t const *t_rules)
{
size_t len;
* %{...}:-bar}
*/
if (fr_sbuff_adv_past_str_literal(in, "%{")) {
- return xlat_tokenize_alternation(head, out, in, t_rules, false);
+ return xlat_tokenize_alternation(head, in, t_rules, false);
}
/*
* %(...):-bar}
*/
if (fr_sbuff_adv_past_str_literal(in, "%(")) {
- return xlat_tokenize_alternation(head, out, in, t_rules, true);
+ return xlat_tokenize_alternation(head, in, t_rules, true);
}
/*
if (fr_sbuff_is_digit(in)) {
int ret;
- ret = xlat_tokenize_regex(head, out, in);
+ ret = xlat_tokenize_regex(head, in);
if (ret <= 0) return ret;
/* ret==1 means "nope, it's an attribute" */
fr_sbuff_set(in, &s_m); /* backtrack */
fr_sbuff_marker_release(&s_m);
- return xlat_tokenize_function_mono(head, out, in, t_rules);
+ return xlat_tokenize_function_mono(head, in, t_rules);
/*
* Hint token is a:
fr_sbuff_set(in, &s_m); /* backtrack */
fr_sbuff_marker_release(&s_m);
- return xlat_tokenize_attribute(head, out, in, &attr_p_rules, t_rules);
+ return xlat_tokenize_attribute(head, in, &attr_p_rules, t_rules);
/*
* Hint token was whitespace
return -1;
}
-/*
- * Temporary things until we swap to using tlists
- */
-#define xlat_exp_append(_tail, _node) do { \
- *_tail = _node; \
- _tail = &(_node)->next; \
- _node = NULL; \
- } while (0)
-
-static void xlat_exp_list_free(xlat_exp_t **head)
-{
- xlat_exp_t *node = *head;
-
- while (node) {
- xlat_exp_t *next = node->next;
- talloc_free(node);
- node = next;
- }
-
- *head = NULL;
-}
-
/** Parse an xlat string i.e. a non-expansion or non-function
*
* When this function is being used outside of an xlat expansion, i.e. on a string
);
fr_sbuff_term_t *tokens;
fr_sbuff_unescape_rules_t const *escapes;
- xlat_exp_t *first, **tail;
-
- first = NULL;
- tail = &first;
XLAT_DEBUG("STRING <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in)));
escapes ? escapes->name : "(none)",
fr_box_strvalue_len(str, talloc_array_length(str) - 1));
XLAT_HEXDUMP((uint8_t const *)str, talloc_array_length(str) - 1, " VALUE-BOX ");
- xlat_exp_append(tail, node);
+
+ xlat_exp_insert_tail(head, node);
} else if (slen < 0) {
error:
talloc_free(node);
- xlat_exp_list_free(&first);
/*
* Free our temporary array of terminals
if (fr_sbuff_adv_past_str_literal(in, "%{")) {
if (slen == 0) TALLOC_FREE(node); /* Free the empty node */
- if (xlat_tokenize_expansion(head, &node, in, t_rules) < 0) goto error;
- xlat_exp_append(tail, node);
+ if (xlat_tokenize_expansion(head, in, t_rules) < 0) goto error;
continue;
}
if (fr_sbuff_adv_past_str_literal(in, "%(")) {
if (slen == 0) TALLOC_FREE(node); /* Free the empty node */
- if (xlat_tokenize_function_args(head, &node, in, t_rules) < 0) goto error;
- xlat_exp_append(tail, node);
+ if (xlat_tokenize_function_args(head, in, t_rules) < 0) goto error;
continue;
}
node->flags.pure = true; /* value boxes are always pure */
node->flags.needs_async = false; /* value boxes are always non-async */
- xlat_flags_merge(&head->flags, &node->flags);
- xlat_exp_append(tail, node);
+ xlat_exp_insert_tail(head, node);
continue;
}
* Empty input, emit no arguments
*/
} else if (slen == 0) {
- talloc_free(node);
+ TALLOC_FREE(node);
XLAT_DEBUG("VALUE-BOX <-- (empty)");
}
break;
* Free our temporary array of terminals
*/
if (tokens != &expansions) talloc_free(tokens);
-
- head->next = first;
+
return 0;
}
/*
* Zero length expansion, return a zero length node.
*/
- if (!head->next) {
+ if (!xlat_exp_head(head)) {
*out = head;
return 0;
}
fr_sbuff_marker_t m;
fr_sbuff_parse_rules_t const *our_p_rules; /* Bareword parse rules */
fr_sbuff_parse_rules_t tmp_p_rules;
- xlat_exp_t **tail;
xlat_exp_head_t *head;
MEM(head = xlat_exp_head_alloc(ctx));
- tail = &head->next;
if (p_rules && p_rules->terminals) {
tmp_p_rules = (fr_sbuff_parse_rules_t){ /* Stack allocated due to CL scope */
char *str;
xlat_exp_t *child;
- node->group->next = child = xlat_exp_alloc_null(node->group);
+ child = xlat_exp_alloc_null(node->group);
xlat_exp_set_type(child, XLAT_BOX);
slen = fr_sbuff_out_aunescape_until(child, &str, &our_in, SIZE_MAX,
xlat_exp_set_name_buffer_shallow(child, str);
fr_value_box_strdup_shallow(&child->data, NULL, str, false);
+ xlat_exp_insert_tail(node->group, child);
}
break;
xlat_exp_set_name_buffer_shallow(node, fmt);
node->flags = node->group->flags;
- xlat_flags_merge(&head->flags, &node->flags);
- xlat_exp_append(tail, node);
+
+ xlat_exp_insert_tail(head, node);
/*
* If we're not and the end of the string
node->vpt = talloc_move(node, vpt_p);
done:
- head->next = node;
- head->flags = node->flags;
+ xlat_exp_insert_tail(head, node);
*out = head;
return 0;
*/
int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in)
{
- xlat_exp_t **tail;
xlat_exp_head_t *head;
if (!in) {
head = xlat_exp_head_alloc(ctx);
head->flags = in->flags;
- tail = &head->next;
/*
* Copy everything in the list of nodes
break;
}
- xlat_exp_append(tail, node);
+ xlat_exp_insert_tail(head, node);
}
*out = head;