--- libelwix/src/Attic/patricia.c.bak 2024/01/22 14:17:02 1.1 +++ libelwix/src/Attic/patricia.c.bak 2024/01/22 14:17:02 1.1.2.1 @@ -0,0 +1,928 @@ +/************************************************************************* +* (C) 2007 AITNET ltd - Sofia/Bulgaria - +* by Michael Pounov +* +* $Author: misho $ +* $Id: patricia.c.bak,v 1.1.2.1 2024/01/22 14:17:02 misho Exp $ +* +************************************************************************** +The ELWIX and AITNET software is distributed under the following +terms: + +All of the documentation and software included in the ELWIX and AITNET +Releases is copyrighted by ELWIX - Sofia/Bulgaria + +Copyright 2004 - 2015 + by Michael Pounov . All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: +This product includes software developed by Michael Pounov +ELWIX - Embedded LightWeight unIX and its contributors. +4. Neither the name of AITNET nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ +/* + * This product includes software developed by the University of Michigan, + * Merit Network, Inc., and their contributors. + * + * This file had been called "radix.c" in the MRT sources. + * + * I renamed it to "patricia.c" since it's not an implementation of a general + * radix trie. Also I pulled in various requirements from "prefix.c" and + * "demo.c" so that it could be used as a standalone API. + * + * Added and patched existing code by AITNET - Michael Pounov + */ +#include "global.h" + + +static int num_active_patricia; + + +/* { from prefix.c */ +static inline int comp_with_mask(void *addr, void *dest, u_int mask) +{ + int n, m; + + if (/* mask/8 == 0 || */ !memcmp(addr, dest, mask / 8)) { + n = mask / 8; + m = ((-1) << (8 - (mask % 8))); + + if (!(mask % 8) || (((u_char*) addr)[n] & m) == (((u_char*) dest)[n] & m)) + return 1; + } + + return 0; +} + +/* this allows imcomplete prefix */ +static int my_inet_pton(int af, const char *src, void *dst) +{ + int i, c, val; + u_char xp[4] = { 0, 0, 0, 0 }; + + if (af == AF_INET) { + for (i = 0;; i++) { + c = *src++; + if (!isdigit(c)) + return -1; + val = 0; + do { + val = val * 10 + c - '0'; + if (val > 255) + return 0; + c = *src++; + } while (c && isdigit(c)); + + xp[i] = val; + if (!c) + break; + if (c != '.' || i >= 3) + return 0; + } + + memcpy(dst, xp, 4); + return 1; +#ifdef HAVE_IPV6 + } else + if (af == AF_INET6) { + return inet_pton(af, src, dst); +#endif /* HAVE_IPV6 */ + } else { + errno = EAFNOSUPPORT; + return -1; + } +} + +/* + * convert prefix information to ascii string with length + * thread safe and (almost) re-entrant implementation + */ +static char *prefix_toa2x(prefix_t *prefix, char *buff, int with_len) +{ + struct buffer { + char buffs[16][48 + 5]; + u_int i; + } *buffp; + u_char *a; + + if (!prefix) + return "(Null)"; + assert(prefix->ref_count >= 0); + if (!buff) { +#if 0 + THREAD_SPECIFIC_DATA(struct buffer, buffp, 1); +#else + { /* for scope only */ + static struct buffer local_buff; + buffp = &local_buff; + } +#endif + if (!buffp) { + /* XXX should we report an error? */ + return NULL; + } + + buff = buffp->buffs[buffp->i++ % 16]; + } + if (prefix->family == AF_INET) { + assert (prefix->bitlen <= 32); + a = prefix_touchar(prefix); + if (with_len) + snprintf(buff, with_len, "%d.%d.%d.%d/%d", a[0], a[1], a[2], + a[3], prefix->bitlen); + else + snprintf(buff, 16, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); + return buff; + } +#ifdef HAVE_IPV6 + else + if (prefix->family == AF_INET6) { + a = (char*) inet_ntop(AF_INET6, &prefix->add.sin6, buff, 48 /* a guess value */); + if (a && with_len) { + assert(prefix->bitlen <= 128); + snprintf(buff + strlen(buff), with_len - strlen(buff), + "/%d", prefix->bitlen); + } + return buff; + } +#endif /* HAVE_IPV6 */ + else + return NULL; +} + +static prefix_t *New_Prefix2(int family, void *dest, int bitlen, prefix_t *prefix) +{ + int dynamic_allocated = 0; + int default_bitlen = 32; + +#ifdef HAVE_IPV6 + if (family == AF_INET6) { + default_bitlen = 128; + if (!prefix) { + prefix = e_calloc(1, sizeof(prefix6_t)); + dynamic_allocated++; + } + memcpy(&prefix->add.sin6, dest, 16); + } else +#endif /* HAVE_IPV6 */ + if (family == AF_INET) { + if (!prefix) { + prefix = e_calloc(1, sizeof(prefix4_t)); + dynamic_allocated++; + } + memcpy(&prefix->add.sin, dest, 4); + } else + return NULL; + + prefix->bitlen = (bitlen >= 0) ? bitlen : default_bitlen; + prefix->family = family; + prefix->ref_count = 0; + if (dynamic_allocated) + prefix->ref_count++; + + return prefix; +} + +static inline prefix_t *New_Prefix(int family, void *dest, int bitlen) +{ + return New_Prefix2(family, dest, bitlen, NULL); +} + +// ------------------------------------------------------------------------------------ + +char *prefix_toa(prefix_t * prefix) +{ + return prefix_toa2x(prefix, NULL, 0); +} + +prefix_t *ascii2prefix(int family, char *string) +{ + u_long bitlen, maxbitlen = 0; + char *cp; + struct in_addr sin; +#ifdef HAVE_IPV6 + struct in6_addr sin6; +#endif /* HAVE_IPV6 */ + int result; + char save[MAXLINE]; + + if (!string) + return (NULL); + + /* easy way to handle both families */ + if (!family) { + family = AF_INET; +#ifdef HAVE_IPV6 + if (strchr(string, ':')) + family = AF_INET6; +#endif /* HAVE_IPV6 */ + } + + if (family == AF_INET) + maxbitlen = 32; +#ifdef HAVE_IPV6 + else + if (family == AF_INET6) + maxbitlen = 128; +#endif /* HAVE_IPV6 */ + + if ((cp = strchr(string, '/'))) { + bitlen = atol(cp + 1); + /* *cp = '\0'; */ + /* copy the string to save. Avoid destroying the string */ + assert(cp - string < MAXLINE); + memcpy(save, string, cp - string); + save[cp - string] = 0; + string = save; + if (bitlen > maxbitlen) + bitlen = maxbitlen; + } else + bitlen = maxbitlen; + + if (family == AF_INET) { + if ((result = my_inet_pton(AF_INET, string, &sin)) <= 0) + return NULL; + return New_Prefix(AF_INET, &sin, bitlen); + } +#ifdef HAVE_IPV6 + else + if (family == AF_INET6) { + if ((result = inet_pton(AF_INET6, string, &sin6)) <= 0) + return NULL; + return New_Prefix(AF_INET6, &sin6, bitlen); + } +#endif /* HAVE_IPV6 */ + else + return NULL; +} + +prefix_t *Ref_Prefix(prefix_t *prefix) +{ + if (!prefix) + return NULL; + + if (!prefix->ref_count) { + /* make a copy in case of a static prefix */ + return New_Prefix2(prefix->family, &prefix->add, prefix->bitlen, NULL); + } + prefix->ref_count++; + + return prefix; +} + +void Deref_Prefix(prefix_t *prefix) +{ + if (!prefix) + return; + + /* for secure programming, raise an assert. no static prefix can call this */ + assert(prefix->ref_count > 0); + prefix->ref_count--; + assert(prefix->ref_count >= 0); + if (prefix->ref_count <= 0) + Delete(prefix); +} + +/* } */ + +/* these routines support continuous mask only */ +patricia_tree_t *New_Patricia(int maxbits) +{ + patricia_tree_t *patricia; + + patricia = e_calloc(1, sizeof *patricia); + + patricia->maxbits = maxbits; + patricia->head = NULL; + patricia->num_active_node = 0; + + assert(maxbits <= PATRICIA_MAXBITS); /* XXX */ + num_active_patricia++; + + return patricia; +} + + +/* + * if func is supplied, it will be called as func(node->data) + * before deleting the node + */ +void Clear_Patricia(patricia_tree_t *patricia, void_fn_t func) +{ + assert(patricia); + if (patricia->head) { + patricia_node_t *Xstack[PATRICIA_MAXBITS+1]; + patricia_node_t **Xsp = Xstack; + patricia_node_t *Xrn = patricia->head; + + while (Xrn) { + patricia_node_t *l = Xrn->l; + patricia_node_t *r = Xrn->r; + + if (Xrn->prefix) { + Deref_Prefix(Xrn->prefix); + if (Xrn->data && func) + func(Xrn->data); + } else + assert(!Xrn->data); + Delete(Xrn); + patricia->num_active_node--; + + if (l) { + if (r) + *Xsp++ = r; + Xrn = l; + } else { + if (r) + Xrn = r; + else + Xrn = (Xsp != Xstack) ? *(--Xsp) : NULL; + } + } + } + + assert (!patricia->num_active_node); + /* Delete(patricia); */ +} + +void Destroy_Patricia(patricia_tree_t *patricia, void_fn_t func) +{ + Clear_Patricia(patricia, func); + Delete(patricia); + num_active_patricia--; +} + + +/* + * if func is supplied, it will be called as func(node->prefix, node->data) + */ +void patricia_process(patricia_tree_t *patricia, void_fn_t func) +{ + patricia_node_t *node; + + assert(func); + + PATRICIA_WALK(patricia->head, node) { + func(node->prefix, node->data); + } PATRICIA_WALK_END; +} + + +patricia_node_t *patricia_search_exact(patricia_tree_t *patricia, prefix_t *prefix) +{ + patricia_node_t *node; + u_char *addr; + u_int bitlen; + + assert(patricia); + assert(prefix); + assert(prefix->bitlen <= patricia->maxbits); + + if (!patricia->head) + return (NULL); + + node = patricia->head; + addr = prefix_touchar(prefix); + bitlen = prefix->bitlen; + + while (node->bit < bitlen) { + if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_search_exact: take right %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_search_exact: take right at %d\n", + node->bit); +#endif /* PATRICIA_DEBUG */ + node = node->r; + } else { +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_search_exact: take left %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_search_exact: take left at %d\n", + node->bit); +#endif /* PATRICIA_DEBUG */ + node = node->l; + } + + if (!node) + return NULL; + } + +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_search_exact: stop at %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_search_exact: stop at %d\n", node->bit); +#endif /* PATRICIA_DEBUG */ + if (node->bit > bitlen || !node->prefix) + return NULL; + assert(node->bit == bitlen); + assert(node->bit == node->prefix->bitlen); + if (comp_with_mask(prefix_touchar(node->prefix), prefix_touchar(prefix), bitlen)) { +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_search_exact: found %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + return node; + } + + return NULL; +} + + +/* if inclusive != 0, "best" may be the given prefix itself */ +patricia_node_t *patricia_search_best2(patricia_tree_t *patricia, prefix_t *prefix, int inclusive) +{ + patricia_node_t *node; + patricia_node_t *stack[PATRICIA_MAXBITS + 1]; + u_char *addr; + u_int bitlen; + int cnt = 0; + + assert(patricia); + assert(prefix); + assert(prefix->bitlen <= patricia->maxbits); + + if (!patricia->head) + return NULL; + + node = patricia->head; + addr = prefix_touchar(prefix); + bitlen = prefix->bitlen; + + while (node->bit < bitlen) { + if (node->prefix) { +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_search_best: push %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + stack[cnt++] = node; + } + + if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_search_best: take right %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_search_best: take right at %d\n", + node->bit); +#endif /* PATRICIA_DEBUG */ + node = node->r; + } else { +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_search_best: take left %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_search_best: take left at %d\n", + node->bit); +#endif /* PATRICIA_DEBUG */ + node = node->l; + } + + if (!node) + break; + } + + if (inclusive && node && node->prefix) + stack[cnt++] = node; + +#ifdef PATRICIA_DEBUG + if (!node) + fprintf(stderr, "patricia_search_best: stop at null\n"); + else + if (node->prefix) + fprintf(stderr, "patricia_search_best: stop at %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_search_best: stop at %d\n", node->bit); +#endif /* PATRICIA_DEBUG */ + + if (cnt <= 0) + return NULL; + + while (--cnt >= 0) { + node = stack[cnt]; +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_search_best: pop %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + if (comp_with_mask(prefix_touchar(node->prefix), prefix_touchar(prefix), + node->prefix->bitlen)) { +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_search_best: found %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + return node; + } + } + + return NULL; +} + +patricia_node_t *patricia_search_best(patricia_tree_t *patricia, prefix_t *prefix) +{ + return patricia_search_best2(patricia, prefix, 1); +} + + +patricia_node_t *patricia_lookup(patricia_tree_t *patricia, prefix_t *prefix) +{ + patricia_node_t *node, *new_node, *parent, *glue; + u_char *addr, *test_addr; + u_int bitlen, check_bit, differ_bit; + int i, j, r; + + assert(patricia); + assert(prefix); + assert(prefix->bitlen <= patricia->maxbits); + + if (!patricia->head) { + node = e_calloc(1, sizeof *node); + node->bit = prefix->bitlen; + node->prefix = Ref_Prefix(prefix); + node->parent = NULL; + node->l = node->r = NULL; + node->data = NULL; + patricia->head = node; +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: new_node #0 %s/%d (head)\n", + prefix_toa(prefix), prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + patricia->num_active_node++; + return node; + } + + addr = prefix_touchar(prefix); + bitlen = prefix->bitlen; + node = patricia->head; + + while (node->bit < bitlen || !node->prefix) { + if (node->bit < patricia->maxbits && + BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { + if (!node->r) + break; +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_lookup: take right %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_lookup: take right at %d\n", node->bit); +#endif /* PATRICIA_DEBUG */ + node = node->r; + } else { + if (!node->l) + break; +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_lookup: take left %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_lookup: take left at %d\n", node->bit); +#endif /* PATRICIA_DEBUG */ + node = node->l; + } + + assert(node); + } + + assert(node->prefix); +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: stop at %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + + test_addr = prefix_touchar(node->prefix); + /* find the first bit different */ + check_bit = (node->bit < bitlen) ? node->bit : bitlen; + differ_bit = 0; + for (i = 0; i * 8 < check_bit; i++) { + if (!(r = (addr[i] ^ test_addr[i]))) { + differ_bit = (i + 1) * 8; + continue; + } + /* I know the better way, but for now */ + for (j = 0; j < 8; j++) { + if (BIT_TEST(r, (0x80 >> j))) + break; + } + /* must be found */ + assert(j < 8); + differ_bit = i * 8 + j; + break; + } + + if (differ_bit > check_bit) + differ_bit = check_bit; +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: differ_bit %d\n", differ_bit); +#endif /* PATRICIA_DEBUG */ + + parent = node->parent; + while (parent && parent->bit >= differ_bit) { + node = parent; + parent = node->parent; +#ifdef PATRICIA_DEBUG + if (node->prefix) + fprintf(stderr, "patricia_lookup: up to %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); + else + fprintf(stderr, "patricia_lookup: up to %d\n", node->bit); +#endif /* PATRICIA_DEBUG */ + } + + if (differ_bit == bitlen && node->bit == bitlen) { + if (node->prefix) { +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: found %s/%d\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + return node; + } + node->prefix = Ref_Prefix(prefix); +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n", + prefix_toa(prefix), prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + assert(!node->data); + return node; + } + + new_node = e_calloc(1, sizeof *new_node); + new_node->bit = prefix->bitlen; + new_node->prefix = Ref_Prefix (prefix); + new_node->parent = NULL; + new_node->l = new_node->r = NULL; + new_node->data = NULL; + patricia->num_active_node++; + + if (node->bit == differ_bit) { + new_node->parent = node; + if (node->bit < patricia->maxbits && + BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { + assert(!node->r); + node->r = new_node; + } else { + assert(!node->l); + node->l = new_node; + } +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: new_node #2 %s/%d (child)\n", + prefix_toa(prefix), prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + return new_node; + } + + if (bitlen == differ_bit) { + if (bitlen < patricia->maxbits && + BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) + new_node->r = node; + else + new_node->l = node; + new_node->parent = node->parent; + if (!node->parent) { + assert(patricia->head == node); + patricia->head = new_node; + } else + if (node->parent->r == node) + node->parent->r = new_node; + else + node->parent->l = new_node; + node->parent = new_node; +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n", + prefix_toa(prefix), prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + } else { + glue = e_calloc(1, sizeof *glue); + glue->bit = differ_bit; + glue->prefix = NULL; + glue->parent = node->parent; + glue->data = NULL; + patricia->num_active_node++; + + if (differ_bit < patricia->maxbits && + BIT_TEST(addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07))) { + glue->r = new_node; + glue->l = node; + } else { + glue->r = node; + glue->l = new_node; + } + new_node->parent = glue; + + if (!node->parent) { + assert(patricia->head == node); + patricia->head = glue; + } else + if (node->parent->r == node) + node->parent->r = glue; + else + node->parent->l = glue; + node->parent = glue; +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n", + prefix_toa(prefix), prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + } + + return new_node; +} + + +void patricia_remove(patricia_tree_t *patricia, patricia_node_t *node) +{ + patricia_node_t *parent, *child; + + assert(patricia); + assert(node); + + if (node->r && node->l) { +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_remove: #0 %s/%d (r & l)\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + + /* this might be a placeholder node -- have to check and make sure + * there is a prefix aossciated with it ! */ + if (node->prefix) + Deref_Prefix(node->prefix); + node->prefix = NULL; + /* Also I needed to clear data pointer -- masaki */ + node->data = NULL; + return; + } + + if (!node->r && !node->l) { +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_remove: #1 %s/%d (!r & !l)\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + parent = node->parent; + Deref_Prefix(node->prefix); + Delete(node); + patricia->num_active_node--; + + if (!parent) { + assert(patricia->head == node); + patricia->head = NULL; + return; + } + + if (parent->r == node) { + parent->r = NULL; + child = parent->l; + } else { + assert(parent->l == node); + parent->l = NULL; + child = parent->r; + } + + if (parent->prefix) + return; + + /* we need to remove parent too */ + if (!parent->parent) { + assert(patricia->head == parent); + patricia->head = child; + } else + if (parent->parent->r == parent) + parent->parent->r = child; + else { + assert(parent->parent->l == parent); + parent->parent->l = child; + } + child->parent = parent->parent; + Delete(parent); + patricia->num_active_node--; + return; + } + +#ifdef PATRICIA_DEBUG + fprintf(stderr, "patricia_remove: #2 %s/%d (r ^ l)\n", + prefix_toa(node->prefix), node->prefix->bitlen); +#endif /* PATRICIA_DEBUG */ + if (node->r) + child = node->r; + else { + assert(node->l); + child = node->l; + } + parent = node->parent; + child->parent = parent; + + Deref_Prefix(node->prefix); + Delete(node); + patricia->num_active_node--; + + if (!parent) { + assert(patricia->head == node); + patricia->head = child; + return; + } + + if (parent->r == node) + parent->r = child; + else { + assert(parent->l == node); + parent->l = child; + } +} + +/* { from demo.c */ + +void lookup_then_remove(patricia_tree_t *tree, char *string) +{ + patricia_node_t *node; + + if ((node = try_search_exact(tree, string))) + patricia_remove(tree, node); +} + +patricia_node_t *make_and_lookup(patricia_tree_t *tree, char *string) +{ + prefix_t *prefix; + patricia_node_t *node; + + prefix = ascii2prefix(AF_INET, string); +#ifdef PATRICIA_DEBUG + printf("make_and_lookup: %s/%d\n", prefix_toa(prefix), prefix->bitlen); +#endif + node = patricia_lookup(tree, prefix); + Deref_Prefix(prefix); + + return node; +} + +patricia_node_t *try_search_exact(patricia_tree_t *tree, char *string) +{ + prefix_t *prefix; + patricia_node_t *node; + + prefix = ascii2prefix(AF_INET, string); +#ifdef PATRICIA_DEBUG + printf("try_search_exact: %s/%d\n", prefix_toa(prefix), prefix->bitlen); +#endif + node = patricia_search_exact(tree, prefix); +#ifdef PATRICIA_DEBUG + if (!node) + printf("try_search_exact: not found\n"); + else + printf("try_search_exact: %s/%d found\n", prefix_toa(node->prefix), node->prefix->bitlen); +#endif + Deref_Prefix(prefix); + + return node; +} + +patricia_node_t *try_search_best(patricia_tree_t *tree, char *string) +{ + prefix_t *prefix; + patricia_node_t *node; + + prefix = ascii2prefix(AF_INET, string); +#ifdef PATRICIA_DEBUG + printf("try_search_best: %s/%d\n", prefix_toa(prefix), prefix->bitlen); +#endif + node = patricia_search_best(tree, prefix); +#ifdef PATRICIA_DEBUG + if (!node) + printf("try_search_best: not found\n"); + else + printf("try_search_best: %s/%d found\n", prefix_toa(node->prefix), node->prefix->bitlen); +#endif + Deref_Prefix(prefix); + + return node; +} + +/* } */