static bool bus_match_node_maybe_free(struct bus_match_node *node) { assert(node); if (node->child) return false; if (BUS_MATCH_IS_COMPARE(node->type) && !hashmap_isempty(node->compare.children)) return true; bus_match_node_free(node); return true; }
static void bus_match_node_free(struct bus_match_node *node) { assert(node); assert(node->parent); assert(!node->child); assert(node->type != BUS_MATCH_ROOT); assert(node->type < _BUS_MATCH_NODE_TYPE_MAX); if (node->parent->child) { /* We are apparently linked into the parent's child * list. Let's remove us from there. */ if (node->prev) { assert(node->prev->next == node); node->prev->next = node->next; } else { assert(node->parent->child == node); node->parent->child = node->next; } if (node->next) node->next->prev = node->prev; } if (node->type == BUS_MATCH_VALUE) { /* We might be in the parent's hash table, so clean * this up */ if (node->parent->type == BUS_MATCH_MESSAGE_TYPE) hashmap_remove(node->parent->compare.children, UINT_TO_PTR(node->value.u8)); else if (BUS_MATCH_CAN_HASH(node->parent->type) && node->value.str) hashmap_remove(node->parent->compare.children, node->value.str); free(node->value.str); } if (BUS_MATCH_IS_COMPARE(node->type)) { assert(hashmap_isempty(node->compare.children)); hashmap_free(node->compare.children); } free(node); }
static int bus_match_find_compare_value( struct bus_match_node *where, enum bus_match_node_type t, uint8_t value_u8, const char *value_str, struct bus_match_node **ret) { struct bus_match_node *c, *n; assert(where); assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); assert(BUS_MATCH_IS_COMPARE(t)); assert(ret); for (c = where->child; c && c->type != t; c = c->next) ; if (!c) return 0; if (t == BUS_MATCH_MESSAGE_TYPE) n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)); else if (BUS_MATCH_CAN_HASH(t)) n = hashmap_get(c->compare.children, value_str); else { for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next) ; } if (n) { *ret = n; return 1; } return 0; }
static int bus_match_add_compare_value( struct bus_match_node *where, enum bus_match_node_type t, uint8_t value_u8, const char *value_str, struct bus_match_node **ret) { struct bus_match_node *c = NULL, *n = NULL; int r; assert(where); assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE); assert(BUS_MATCH_IS_COMPARE(t)); assert(ret); for (c = where->child; c && c->type != t; c = c->next) ; if (c) { /* Comparison node already exists? Then let's see if * the value node exists too. */ if (t == BUS_MATCH_MESSAGE_TYPE) n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)); else if (BUS_MATCH_CAN_HASH(t)) n = hashmap_get(c->compare.children, value_str); else { for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next) ; } if (n) { *ret = n; return 0; } } else { /* Comparison node, doesn't exist yet? Then let's * create it. */ c = new0(struct bus_match_node, 1); if (!c) { r = -ENOMEM; goto fail; } c->type = t; c->parent = where; c->next = where->child; if (c->next) c->next->prev = c; where->child = c; if (t == BUS_MATCH_MESSAGE_TYPE) { c->compare.children = hashmap_new(trivial_hash_func, trivial_compare_func); if (!c->compare.children) { r = -ENOMEM; goto fail; } } else if (BUS_MATCH_CAN_HASH(t)) { c->compare.children = hashmap_new(string_hash_func, string_compare_func); if (!c->compare.children) { r = -ENOMEM; goto fail; } } } n = new0(struct bus_match_node, 1); if (!n) { r = -ENOMEM; goto fail; } n->type = BUS_MATCH_VALUE; n->value.u8 = value_u8; if (value_str) { n->value.str = strdup(value_str); if (!n->value.str) { r = -ENOMEM; goto fail; } } n->parent = c; if (c->compare.children) { if (t == BUS_MATCH_MESSAGE_TYPE) r = hashmap_put(c->compare.children, UINT_TO_PTR(value_u8), n); else r = hashmap_put(c->compare.children, n->value.str, n); if (r < 0) goto fail; } else { n->next = c->child; if (n->next) n->next->prev = n; c->child = n; } *ret = n; return 1; fail: if (c) bus_match_node_maybe_free(c); if (n) { free(n->value.str); free(n); } return r; }