FR_EDIT_INVALID = 0,
FR_EDIT_DELETE, //!< delete a VP
FR_EDIT_VALUE, //!< edit a VP in place
+ FR_EDIT_CLEAR, //!< clear the children of a structural entry.
FR_EDIT_INSERT, //!< insert a VP into a list, after another one.
} fr_edit_op_t;
"invalid",
"delete",
"value",
+ "clear",
"insert",
};
#endif
union {
fr_value_box_t data; //!< original data
- fr_pair_list_t children; //!< original child list,
- //!< for T_OP_SET of structural entries
+ fr_pair_list_t children; //!< original child list, for "clear"
struct {
fr_pair_list_t *list; //!< parent list
fr_value_box_copy_shallow(NULL, &vp->data, &e->data);
break;
+ case FR_EDIT_CLEAR:
+ fr_assert(fr_type_is_structural(vp->vp_type));
+
+ fr_pair_list_free(&vp->vp_group);
+ fr_pair_list_append(&vp->vp_group, &e->children);
+ break;
+
case FR_EDIT_DELETE:
fr_assert(e->list != NULL);
#ifndef NDEBUG
fr_assert(0);
return -1;
+ case FR_EDIT_CLEAR:
+ /*
+ * If we're clearing it, we MUST have
+ * previously inserted it. So just nuke
+ * it's children, as merging the
+ * operations of "insert with stuff" and
+ * then "clear" is just "insert empty
+ * pair".
+ *
+ * However, we don't yet delete the
+ * children, as there may be other edit
+ * operations which are referring to
+ * them.
+ */
+ fr_assert(e->op == FR_EDIT_INSERT);
+ fr_assert(fr_type_is_structural(vp->vp_type));
+
+ fr_pair_list_append(&el->deleted_pairs, &vp->vp_group);
+ break;
+
/*
* We're being asked to delete something
* we previously inserted, or previously
* original one, and then track the
* deletion.
*/
- fr_assert(e->op == FR_EDIT_VALUE);
edit_undo(e);
/*
e->data.tainted);
break;
+ case FR_EDIT_CLEAR:
+ fr_assert(list == NULL);
+ fr_assert(ref == NULL);
+
+ fr_assert(fr_type_is_structural(vp->vp_type));
+ fr_pair_list_init(&e->children);
+ fr_pair_list_append(&e->children, &vp->vp_group);
+ break;
+
case FR_EDIT_INSERT:
fr_assert(list != NULL);
}
+/** Replace a pair with another one.
+ *
+ * This function mirrors fr_pair_replace().
+ *
+ * After this function returns, the new VP has replaced the old one,
+ * and the new one can be edited.
+ */
+int fr_edit_list_free_children(fr_edit_list_t *el, fr_pair_t *vp)
+{
+ if (!el) return 0;
+
+ if (!fr_type_is_structural(vp->vp_type)) return -1;
+
+ /*
+ * Record the list, even if it's empty. That way if we
+ * later add children to it, the "undo" operation can
+ * reset the children list to be empty.
+ */
+ return edit_record(el, FR_EDIT_CLEAR, vp, NULL, NULL);
+}
+
/** Finalize the edits when we destroy the edit list.
*
* Which in large part means freeing the VPs which have been deleted,
- * and then deleting the edit list.
+ * or saved, and then deleting the edit list.
*/
static int _edit_list_destructor(fr_edit_list_t *el)
{
talloc_free(e->vp);
break;
+ case FR_EDIT_CLEAR:
+ fr_pair_list_free(&e->children);
+ break;
+
case FR_EDIT_VALUE:
fr_assert(fr_type_is_leaf(e->vp->vp_type));
fr_value_box_clear(&e->data);