*/
static int apply_edits(request_t *request, unlang_frame_state_edit_t *state, edit_map_t *current, map_t const *map)
{
- fr_pair_t *vp, *vp_to_free = NULL;
+ fr_pair_t *vp;
fr_pair_list_t *children;
fr_value_box_t const *rhs_box = NULL;
+ bool copy_vps = true;
+ int rcode;
fr_assert(current->lhs.vp != NULL);
if (!current->rhs.vpt) {
children = ¤t->rhs.pair_list;
+ copy_vps = false;
goto apply_list;
}
if (fr_type_is_group(da->type)) da = fr_dict_root(request->dict);
children = ¤t->rhs.pair_list;
+ copy_vps = false;
switch (rhs_box->type) {
case FR_TYPE_STRING:
* treats the RHS as a one-member list.
*/
if (fr_type_is_leaf(vp->vp_type)) {
- vp_to_free = fr_pair_copy(request, vp);
- if (!vp_to_free) return -1;
+ fr_pair_t *vp_copy;
+
+ vp_copy = fr_pair_copy(request, vp);
+ if (!vp_copy) return -1;
fr_assert(fr_pair_list_empty(¤t->rhs.pair_list));
- fr_pair_append(¤t->rhs.pair_list, vp_to_free);
+ fr_pair_append(¤t->rhs.pair_list, vp_copy);
children = ¤t->rhs.pair_list;
-
- vp_to_free = NULL; /* it's not in the pair list, and will be freed there */
+ copy_vps = false;
} else {
/*
return -1;
}
- children = &vp->children;
+ children = &vp->vp_group; /* and copy_vps for any VP we edit */
}
/*
RDEBUG2("}");
}
- if (fr_edit_list_apply_list_assignment(state->el,
- current->lhs.vp,
- map->op,
- children) < 0) {
- RPERROR("Failed performing list %s operation", fr_tokens[map->op]);
- talloc_free(vp_to_free);
- return -1;
- }
+ rcode = fr_edit_list_apply_list_assignment(state->el, current->lhs.vp, map->op, children, copy_vps);
+ if (rcode < 0) RPERROR("Failed performing list %s operation", fr_tokens[map->op]);
- talloc_free(vp_to_free);
- return 0;
+ /*
+ * If the child list wasn't copied, then we just created it, and we need to free it.
+ */
+ if (!copy_vps) fr_pair_list_free(children);
+ return rcode;
leaf:
/*
return fr_value_calc_assignment_op(vp, &vp->data, op, in);
}
+#undef COPY
+#define COPY(_x) do { if (copy) { \
+ c = fr_pair_copy(dst, _x); \
+ if (!c) return -1; \
+ } else { \
+ c = talloc_steal(dst, _x); \
+ } \
+ } while (0)
/** A UNION B
*
*/
-static int list_union(fr_edit_list_t *el, fr_pair_t *dst, fr_pair_list_t *src)
+static int list_union(fr_edit_list_t *el, fr_pair_t *dst, fr_pair_list_t *src, bool copy)
{
- fr_pair_t *a, *b;
+ fr_pair_t *a, *b, *c;
fr_dcursor_t cursor1, cursor2;
/*
* A is done, so we always union in B at the end of A.
*/
if (!a) {
- if (fr_edit_list_insert_pair_tail(el, &dst->children, fr_pair_copy(dst, b)) < 0) {
+ COPY(b);
+
+ if (fr_edit_list_insert_pair_tail(el, &dst->children, c) < 0) {
return -1;
}
* to the destination list, before A.
*/
if (rcode > 0) {
- if (fr_edit_list_insert_pair_before(el, &dst->children, a, fr_pair_copy(dst, b)) < 0) {
+ COPY(b);
+
+ if (fr_edit_list_insert_pair_before(el, &dst->children, a, c) < 0) {
return -1;
}
* been added in.
*/
if (fr_type_is_structural(a->vp_type)) {
- rcode = list_union(el, a, &b->children);
+ rcode = list_union(el, a, &b->children, copy);
if (rcode < 0) return rcode;
fr_dcursor_next(&cursor1);
continue;
}
- /*
- *
- */
- if (fr_edit_list_insert_pair_after(el, &dst->children, a, fr_pair_copy(dst, b)) < 0) {
+ COPY(b);
+ if (fr_edit_list_insert_pair_after(el, &dst->children, a, c) < 0) {
return -1;
}
*
* with priority to A
*/
-static int list_merge_lhs(fr_edit_list_t *el, fr_pair_t *dst, fr_pair_list_t *src)
+static int list_merge_lhs(fr_edit_list_t *el, fr_pair_t *dst, fr_pair_list_t *src, bool copy)
{
- fr_pair_t *a, *b;
+ fr_pair_t *a, *b, *c;
fr_dcursor_t cursor1, cursor2;
fr_pair_list_sort(&dst->children, fr_pair_cmp_by_parent_num);
* A is done, so we always merge in B at the end of A.
*/
if (!a) {
- if (fr_edit_list_insert_pair_tail(el, &dst->children, fr_pair_copy(dst, b)) < 0) {
+ COPY(b);
+
+ if (fr_edit_list_insert_pair_tail(el, &dst->children, c) < 0) {
return -1;
}
* to before A.
*/
if (rcode > 0) {
- if (fr_edit_list_insert_pair_before(el, &dst->children, a, fr_pair_copy(dst, b)) < 0) {
+ COPY(b);
+
+ if (fr_edit_list_insert_pair_before(el, &dst->children, a, c) < 0) {
return -1;
}
fr_assert(a->da == b->da);
if (fr_type_is_structural(a->vp_type)) {
- rcode = list_merge_lhs(el, a, &b->children);
+ rcode = list_merge_lhs(el, a, &b->children, copy);
if (rcode < 0) return rcode;
}
*
* with priority to B
*/
-static int list_merge_rhs(fr_edit_list_t *el, fr_pair_t *dst, fr_pair_list_t *src)
+static int list_merge_rhs(fr_edit_list_t *el, fr_pair_t *dst, fr_pair_list_t *src, bool copy)
{
- fr_pair_t *a, *b;
+ fr_pair_t *a, *b, *c;
fr_dcursor_t cursor1, cursor2;
fr_pair_list_sort(&dst->children, fr_pair_cmp_by_parent_num);
* A is done, so we always merge in B at the end of A.
*/
if (!a) {
- if (fr_edit_list_insert_pair_tail(el, &dst->children, fr_pair_copy(dst, b)) < 0) {
+ COPY(b);
+
+ if (fr_edit_list_insert_pair_tail(el, &dst->children, c) < 0) {
return -1;
}
* to before A.
*/
if (rcode < 0) {
- if (fr_edit_list_insert_pair_before(el, &dst->children, a, fr_pair_copy(dst, b)) < 0) {
+ COPY(b);
+
+ if (fr_edit_list_insert_pair_before(el, &dst->children, a, c) < 0) {
return -1;
}
fr_assert(a->da == b->da);
if (fr_type_is_structural(a->vp_type)) {
- rcode = list_merge_rhs(el, a, &b->children);
+ rcode = list_merge_rhs(el, a, &b->children, copy);
if (rcode < 0) return rcode;
}
*
* The src list is sorted, but is otherwise not modified.
*/
-int fr_edit_list_apply_list_assignment(fr_edit_list_t *el, fr_pair_t *dst, fr_token_t op, fr_pair_list_t *src)
+int fr_edit_list_apply_list_assignment(fr_edit_list_t *el, fr_pair_t *dst, fr_token_t op, fr_pair_list_t *src, bool copy)
{
- fr_pair_list_t copy;
+ fr_pair_list_t list;
if (!fr_type_is_structural(dst->vp_type)) {
fr_strerror_printf("Cannot perform list assignment to non-structural type '%s'",
return -1;
}
-#define COPY do { \
- fr_pair_list_init(©); \
- if (fr_pair_list_copy(dst, ©, src) < 0) return -1; \
+#undef COPY
+#define COPY do { if (copy) { \
+ fr_pair_list_init(&list); \
+ if (fr_pair_list_copy(dst, &list, src) < 0) return -1;\
+ src = &list; \
+ } else { \
+ fr_pair_list_steal(dst, src); \
+ } \
} while (0)
}
COPY;
- return fr_edit_list_insert_list_tail(el, &dst->children, ©);
+ return fr_edit_list_insert_list_tail(el, &dst->children, src);
case T_OP_PREPEND:
if (&dst->children == src) {
}
COPY;
- return fr_edit_list_insert_list_head(el, &dst->children, ©);
+ return fr_edit_list_insert_list_head(el, &dst->children, src);
case T_OP_AND_EQ:
if (&dst->children == src) return 0; /* A INTERSECTION A == A */
case T_OP_OR_EQ:
if (&dst->children == src) return 0; /* A UNION A == A */
- return list_union(el, dst, src);
+ return list_union(el, dst, src, copy);
case T_OP_GE:
if (&dst->children == src) return 0; /* A MERGE A == A */
- return list_merge_lhs(el, dst, src);
+ return list_merge_lhs(el, dst, src, copy);
case T_OP_LE:
if (&dst->children == src) return 0; /* A MERGE A == A */
- return list_merge_rhs(el, dst, src);
+ return list_merge_rhs(el, dst, src, copy);
default:
break;