static inline void r_add_child_check(RNode *root, guint8 *key, gpointer value, RNodeGetValueFunc value_func) { guint8 *at; if (((at = strchr(key, '@')) != NULL)) { /* there is an @ somewhere in the string */ if ((at - key) > 0) { /* there are some literal characters before @ so add a new child till @ */ *at = '\0'; RNode *child = r_new_node(key, NULL); r_add_child(root, child); /* and insert the rest begining from @ under the newly created literal node */ *at = '@'; r_insert_node(child, at, value, value_func); } else { /* @ is the first so let's insert it simply and let insert_node handle @ */ r_insert_node(root, key, value, value_func); } } else { /* either we don't care about parser or no @ in the text, so insert everything as * a simple literal node */ RNode *child = r_new_node(key, value); r_add_child(root, child); } }
PDBProgram * pdb_program_new(void) { PDBProgram *self = g_new0(PDBProgram, 1); self->rules = r_new_node((guint8 *) "", NULL); self->ref_cnt = 1; return self; }
void r_insert_node(RNode *root, guint8 *key, gpointer value, RNodeGetValueFunc value_func) { RNode *node; gint keylen = strlen(key); gint nodelen = root->keylen; gint i = 0; if (key[0] == '@') { guint8 *end; if (keylen >= 2 && key[1] == '@') { /* we found and escape, so check if we already have a child with '@', or add a child like that */ node = r_find_child_by_first_character(root, key[1]); if (!node) { /* no child so we create one * if we are at the end of the key than use value, otherwise it is just a gap node */ node = r_new_node("@", (keylen == 2 ? value : NULL)); r_add_child(root, node); } else if (keylen == 2) { /* if we are at the end of the key set the value if it is not already exists, * otherwise it is duplicate node */ if (!node->value) node->value = value; else msg_error("Duplicate key in parser radix tree", evt_tag_str("key", "@"), evt_tag_str("value", value_func ? value_func(value) : "unknown"), NULL); } /* go down building the tree if there is key left */ if (keylen > 2) r_insert_node(node, key + 2, value, value_func); } else if ((keylen >= 2) && (end = strchr((const gchar *)key + 1, '@')) != NULL) { /* we are a parser node */ *end = '\0'; RParserNode *parser_node = r_new_pnode(key + 1); if (parser_node) { node = r_find_pchild(root, parser_node); if (!node) { node = r_new_node(NULL, NULL); node->parser = parser_node; r_add_pchild(root, node); } else { r_free_pnode_only(parser_node); } if ((end - key) < (keylen - 1)) { /* the key is not over so go on building the tree */ r_insert_node(node, end + 1, value, value_func); } else { /* the key is over so set value if it is not yet set */ if (!node->value) { node->value = value; } else { /* FIXME: print parser type in string format */ msg_error("Duplicate parser node in radix tree", evt_tag_int("type", node->parser->type), evt_tag_str("name", log_msg_get_value_name(node->parser->handle, NULL)), evt_tag_str("value", value_func ? value_func(value) : "unknown"), NULL); } } } } else msg_error("Key contains '@' without escaping", evt_tag_str("key", key), evt_tag_str("value", value_func ? value_func(value) : "unknown"), NULL); } else { /* we are not starting with @ sign or we are not interested in @ at all */ while (i < keylen && i < nodelen) { /* check if key is the same, or if it is a parser */ if ((key[i] != root->key[i]) || (key[i] == '@')) break; i++; } if (nodelen == 0 || i == 0 || (i < keylen && i >= nodelen)) { /*either at the root or we need to go down the tree on the right child */ node = r_find_child_by_first_character(root, key[i]); if (node) { /* @ is always a singel node, and we also have an @ so insert us under root */ if (key[i] == '@') r_insert_node(root, key + i, value, value_func); else r_insert_node(node, key + i, value, value_func); } else { r_add_child_check(root, key + i, value, value_func); } } else if (i == keylen && i == nodelen) { /* exact match */ if (!root->value) root->value = value; else msg_error("Duplicate key in radix tree", evt_tag_str("key", key), evt_tag_str("value", value_func ? value_func(value) : "unknown"), NULL); } else if (i > 0 && i < nodelen) { RNode *old_tree; guint8 *new_key; /* we need to split the current node */ old_tree = r_new_node(root->key + i, root->value); if (root->num_children) { old_tree->children = root->children; old_tree->num_children = root->num_children; root->children = NULL; root->num_children = 0; } if (root->num_pchildren) { old_tree->pchildren = root->pchildren; old_tree->num_pchildren = root->num_pchildren; root->pchildren = NULL; root->num_pchildren = 0; } root->value = NULL; new_key = g_strndup(root->key, i); g_free(root->key); root->key = new_key; root->keylen = i; r_add_child(root, old_tree); if (i < keylen) { /* we add a new sub tree */ r_add_child_check(root, key + i, value, value_func); } else { /* the split is us */ root->value = value; } } else { /* simply a new children */ r_add_child_check(root, key + i, value, value_func); } } }