#include <freeradius-devel/util/value.h>
#include <freeradius-devel/util/talloc.h>
#include "edit.h"
+#include "calc.h"
typedef enum {
FR_EDIT_INVALID = 0,
* After this function returns, the new VP has been inserted into the
* list.
*/
-int fr_edit_list_insert_after(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *pos, fr_pair_t *vp)
+int fr_edit_list_insert_pair_after(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *pos, fr_pair_t *vp)
{
if (!el) return 0;
*
* After this function returns, the VP has been removed from the list.
*/
-int fr_edit_list_delete(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *vp)
+int fr_edit_list_pair_delete(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *vp)
{
return edit_record(el, FR_EDIT_DELETE, vp, list, NULL);
}
*
* After this function returns, it's safe to edit the pair.
*/
-int fr_edit_list_save_value(fr_edit_list_t *el, fr_pair_t *vp)
+int fr_edit_list_save_pair_value(fr_edit_list_t *el, fr_pair_t *vp)
{
if (!el) return 0;
*
* After this function returns, the value has been updated.
*/
-int fr_edit_list_replace_value(fr_edit_list_t *el, fr_pair_t *vp, fr_value_box_t *box)
+int fr_edit_list_replace_pair_value(fr_edit_list_t *el, fr_pair_t *vp, fr_value_box_t *box)
{
if (!el) return 0;
* After this function returns, the new VP has replaced the old one,
* and the new one can be edited.
*/
-int fr_edit_list_replace(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *to_replace, fr_pair_t *vp)
+int fr_edit_list_replace_pair(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *to_replace, fr_pair_t *vp)
{
if (!el) return 0;
* 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)
+int fr_edit_list_free_pair_children(fr_edit_list_t *el, fr_pair_t *vp)
{
if (!el) return 0;
return edit_record(el, FR_EDIT_CLEAR, vp, NULL, NULL);
}
-/** Insert a list after a particular point in another list.
- *
- * This function mirrors fr_pair_list_append(), but with a bit more
- * control over where the to_insert list ends up.
- *
- * There's nothing magical about this function, it's just easier to
- * have it here than in multiple places in the code.
- */
-int fr_edit_list_insert_list_after(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *pos, fr_pair_list_t *to_insert)
-{
- fr_pair_t *prev, *vp;
-
- if (!el) return 0;
-
- prev = pos;
-
- /*
- * We have to record each individual insert as a separate
- * item. Some later edit may insert pairs in the middle
- * of the ones we've added.
- */
- while ((vp = fr_pair_list_head(to_insert)) != NULL) {
- (void) fr_pair_remove(to_insert, vp);
-
- if (edit_record(el, FR_EDIT_INSERT, vp, list, prev) < 0) {
- fr_pair_prepend(to_insert, vp); /* don't lose it! */
- return -1;
- }
-
- prev = vp;
- }
-
- return 0;
-}
-
-
/** Finalize the edits when we destroy the edit list.
*
* Which in large part means freeing the VPs which have been deleted,
* free temporary map
* commit(edit list)
*/
+
+/**********************************************************************
+ *
+ * Now we have helper functions which use the edit list to get things
+ * done.
+ *
+ **********************************************************************/
+
+/** Insert a list after a particular point in another list.
+ *
+ * This function mirrors fr_pair_list_append(), but with a bit more
+ * control over where the to_insert list ends up.
+ *
+ * There's nothing magical about this function, it's just easier to
+ * have it here than in multiple places in the code.
+ */
+int fr_edit_list_insert_list_after(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *pos, fr_pair_list_t *to_insert)
+{
+ fr_pair_t *prev, *vp;
+
+ if (!el) return 0;
+
+ prev = pos;
+
+ /*
+ * We have to record each individual insert as a separate
+ * item. Some later edit may insert pairs in the middle
+ * of the ones we've added.
+ */
+ while ((vp = fr_pair_list_head(to_insert)) != NULL) {
+ (void) fr_pair_remove(to_insert, vp);
+
+ if (edit_record(el, FR_EDIT_INSERT, vp, list, prev) < 0) {
+ fr_pair_prepend(to_insert, vp); /* don't lose it! */
+ return -1;
+ }
+
+ prev = vp;
+ }
+
+ return 0;
+}
+
+/** Apply operators to pairs.
+ *
+ * := is "if found vp, call fr_pair_replace(). Otherwise call fr_edit_list_insert_pair_tail()
+ * = is "if found vp, do nothing. Otherwise call fr_edit_list_insert_pair_tail()
+ *
+ */
+int fr_edit_list_apply_pair_assignment(fr_edit_list_t *el, fr_pair_t *vp, fr_token_t op, fr_value_box_t const *in)
+{
+ if (fr_edit_list_save_pair_value(el, vp) < 0) return -1;
+
+ if (fr_value_calc_assignment_op(vp, &vp->data, op, in) < 0) return -1;
+
+ return 0;
+}
+
+/** Apply operators to lists.
+ *
+ * = is "if found vp, do nothing. Otherwise call fr_edit_list_insert_pair_tail()
+ *
+ * The src list MUST have been talloc'd from the right place already.
+ */
+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)
+{
+ if (!fr_type_is_structural(dst->vp_type)) {
+ return -1;
+ }
+
+ switch (op) {
+ /*
+ * Over-ride existing value (i.e. children) with
+ * new list.
+ */
+ case T_OP_SET:
+ if (fr_edit_list_free_pair_children(el, dst) < 0) return -1;
+ FALL_THROUGH;
+
+ case T_OP_ADD_EQ:
+ return fr_edit_list_insert_list_tail(el, &dst->children, src);
+
+ case T_OP_PREPEND:
+ return fr_edit_list_insert_list_head(el, &dst->children, src);
+
+ default:
+ break;
+ }
+
+ fr_strerror_printf("Invalid assignment operator %s for destination type %s",
+ fr_tokens[op],
+ fr_table_str_by_value(fr_value_box_type_table, dst->type, "<INVALID>"));
+ return -1;
+}
+
+/** Apply operators to lists.
+ *
+ * = is "if found vp, do nothing. Otherwise call fr_edit_list_insert_pair_tail()
+ *
+ * The src list here is "const". This is a separate function, which
+ * means that in many cases we can avoid copying the source list.
+ *
+ * This isn't much use for simple operations, but it can have
+ * significant benefits for union, merge, etc. where only some of the
+ * source list is copied.
+ */
+int fr_edit_list_apply_list_assignment_const(fr_edit_list_t *el, fr_pair_t *dst, fr_token_t op, fr_pair_list_t const *src)
+{
+ fr_pair_list_t copy;
+
+ if (!fr_type_is_structural(dst->vp_type)) {
+ return -1;
+ }
+
+#define COPY do { \
+ fr_pair_list_init(©); \
+ if (fr_pair_list_copy(dst, ©, src) < 0) return -1; \
+ } while (0)
+
+
+ switch (op) {
+ /*
+ * Over-ride existing value (i.e. children) with
+ * new list.
+ */
+ case T_OP_SET:
+ if (fr_edit_list_free_pair_children(el, dst) < 0) return -1;
+ FALL_THROUGH;
+
+ case T_OP_ADD_EQ:
+ COPY;
+
+ return fr_edit_list_insert_list_tail(el, &dst->children, ©);
+
+ case T_OP_PREPEND:
+ COPY;
+
+ return fr_edit_list_insert_list_head(el, &dst->children, ©);
+
+ default:
+ break;
+ }
+
+ fr_strerror_printf("Invalid assignment operator %s for destination type %s",
+ fr_tokens[op],
+ fr_table_str_by_value(fr_value_box_type_table, dst->type, "<INVALID>"));
+ return -1;
+}
#define fr_edit_list_commit(_x) talloc_free(_x)
-int fr_edit_list_insert_after(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *pos, fr_pair_t *vp) CC_HINT(nonnull(2,4));
+/*
+ * Functions to modify #fr_pair_t
+ */
+int fr_edit_list_insert_pair_after(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *pos, fr_pair_t *vp) CC_HINT(nonnull(2,4));
+
+#define fr_edit_list_insert_pair_head(_el, _list, _vp) fr_edit_list_insert_after(_el, _list, NULL, _vp)
+
+#define fr_edit_list_insert_pair_tail(_el, _list, _vp) fr_edit_list_insert_after(_el, _list, fr_pair_list_tail(_list), _vp)
+
+int fr_edit_list_pair_delete(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *vp) CC_HINT(nonnull(2,3));
-int fr_edit_list_delete(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *vp) CC_HINT(nonnull(2,3));
+int fr_edit_list_save_pair_value(fr_edit_list_t *el, fr_pair_t *vp) CC_HINT(nonnull(2));
-int fr_edit_list_save_value(fr_edit_list_t *el, fr_pair_t *vp) CC_HINT(nonnull(2));
+int fr_edit_list_replace_pair_value(fr_edit_list_t *el, fr_pair_t *vp, fr_value_box_t *box) CC_HINT(nonnull(2,3));
-int fr_edit_list_replace_value(fr_edit_list_t *el, fr_pair_t *vp, fr_value_box_t *box) CC_HINT(nonnull(2,3));
+int fr_edit_list_replace_pair(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *to_replace, fr_pair_t *vp) CC_HINT(nonnull(2,3,4));
-int fr_edit_list_replace(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *to_replace, fr_pair_t *vp) CC_HINT(nonnull(2,3,4));
+int fr_edit_list_free_pair_children(fr_edit_list_t *el, fr_pair_t *vp) CC_HINT(nonnull(2));
+int fr_edit_list_apply_pair_assignment(fr_edit_list_t *el, fr_pair_t *vp, fr_token_t op, fr_value_box_t const *in);
+
+/*
+ * Functions to modify #fr_pair_list_t
+ */
int fr_edit_list_insert_list_after(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *pos, fr_pair_list_t *to_insert) CC_HINT(nonnull(2,4));
+#define fr_edit_list_insert_list_head(_el, _list, _to_insert) fr_edit_list_insert_list_after(_el, _list, NULL, _to_insert)
+
+#define fr_edit_list_insert_list_tail(_el, _list, _to_insert) fr_edit_list_insert_list_after(_el, _list, fr_pair_list_tail(_list), _to_insert)
+
+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) CC_HINT(nonnull(1,2,4));
-int fr_edit_list_free_children(fr_edit_list_t *el, fr_pair_t *vp) CC_HINT(nonnull(2));
+int fr_edit_list_apply_list_assignment_const(fr_edit_list_t *el, fr_pair_t *dst, fr_token_t op, fr_pair_list_t const *src) CC_HINT(nonnull(1,2,4));
#ifdef __cplusplus
}
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, vp);
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp);
TEST_CHECK(rcode == 0);
fr_edit_list_commit(el);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, vp);
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp);
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, vp);
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp);
TEST_CHECK(rcode == 0);
fr_edit_list_commit(el);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, middle);
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, middle);
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, vp); /* middle */
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp); /* middle */
TEST_CHECK(rcode == 0);
vp = fr_pair_list_tail(&local_pairs);
fr_assert(vp != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, vp); /* tail */
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp); /* tail */
TEST_CHECK(rcode == 0);
fr_edit_list_commit(el);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, vp); /* middle */
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp); /* middle */
TEST_CHECK(rcode == 0);
vp = fr_pair_list_tail(&local_pairs);
fr_assert(vp != NULL);
- rcode = fr_edit_list_delete(el, &local_pairs, vp); /* tail */
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp); /* tail */
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_save_value(el, vp);
+ rcode = fr_edit_list_save_pair_value(el, vp);
TEST_CHECK(rcode == 0);
TEST_CHECK(vp->vp_uint32 == 0);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_save_value(el, vp);
+ rcode = fr_edit_list_save_pair_value(el, vp);
TEST_CHECK(rcode == 0);
TEST_CHECK(vp->vp_uint32 == 0);
TEST_CHECK((vp = fr_pair_afrom_da(autofree, fr_dict_attr_test_string)) != NULL);
- rcode = fr_edit_list_insert_after(el, &local_pairs, NULL, vp);
+ rcode = fr_edit_list_insert_pair_after(el, &local_pairs, NULL, vp);
TEST_CHECK(rcode == 0);
fr_edit_list_commit(el);
TEST_CHECK((vp = fr_pair_afrom_da(autofree, fr_dict_attr_test_string)) != NULL);
- rcode = fr_edit_list_insert_after(el, &local_pairs, NULL, vp);
+ rcode = fr_edit_list_insert_pair_after(el, &local_pairs, NULL, vp);
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);
TEST_CHECK((vp = fr_pair_afrom_da(autofree, fr_dict_attr_test_string)) != NULL);
- rcode = fr_edit_list_insert_after(el, &local_pairs, middle, vp);
+ rcode = fr_edit_list_insert_pair_after(el, &local_pairs, middle, vp);
TEST_CHECK(rcode == 0);
fr_edit_list_commit(el);
TEST_CHECK((vp = fr_pair_afrom_da(autofree, fr_dict_attr_test_string)) != NULL);
- rcode = fr_edit_list_insert_after(el, &local_pairs, middle, vp);
+ rcode = fr_edit_list_insert_pair_after(el, &local_pairs, middle, vp);
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_save_value(el, vp);
+ rcode = fr_edit_list_save_pair_value(el, vp);
TEST_CHECK(rcode == 0);
TEST_CHECK(vp->vp_uint32 == 0);
vp->vp_uint32 = 1;
TEST_CHECK(vp->vp_uint32 == 1);
- rcode = fr_edit_list_delete(el, &local_pairs, vp);
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp);
TEST_CHECK(rcode == 0);
fr_edit_list_commit(el);
el = fr_edit_list_alloc(NULL, 5);
fr_assert(el != NULL);
- rcode = fr_edit_list_save_value(el, vp);
+ rcode = fr_edit_list_save_pair_value(el, vp);
TEST_CHECK(rcode == 0);
TEST_CHECK(vp->vp_uint32 == 0);
vp->vp_uint32 = 1;
TEST_CHECK(vp->vp_uint32 == 1);
- rcode = fr_edit_list_delete(el, &local_pairs, vp);
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp);
TEST_CHECK(rcode == 0);
/*
TEST_CHECK((vp = fr_pair_afrom_da(autofree, fr_dict_attr_test_string)) != NULL);
- rcode = fr_edit_list_insert_after(el, &local_pairs, NULL, vp);
+ rcode = fr_edit_list_insert_pair_after(el, &local_pairs, NULL, vp);
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);
TEST_CASE("Expected (count == 4) after inserting a new one");
TEST_CHECK(count == 4);
- rcode = fr_edit_list_delete(el, &local_pairs, vp);
+ rcode = fr_edit_list_pair_delete(el, &local_pairs, vp);
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);
TEST_CHECK((vp = fr_pair_afrom_da(autofree, fr_dict_attr_test_string)) != NULL);
- rcode = fr_edit_list_insert_after(el, &local_pairs, NULL, vp);
+ rcode = fr_edit_list_insert_pair_after(el, &local_pairs, NULL, vp);
TEST_CHECK(rcode == 0);
count = fr_pair_list_len(&local_pairs);