modules/rx/rx_search.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following functions.
  1. rx_build_stack
  2. rx_nod_append
  3. rx_walk_hook_addnode
  4. rx_walk_hook_adddoubles
  5. rx_nod_search
  6. RX_bin_search

   1 /***************************************
   2   $Revision: 1.37 $
   3 
   4   Radix tree (rx).  rx_search.c - functions to search nodes of the tree
   5 
   6   Status: NOT REVUED, TESTED, COMPLETE
   7 
   8   Design and implementation by: Marek Bukowy
   9 
  10   ******************/ /******************
  11   Copyright (c) 1999,2000,2001,2002               RIPE NCC
  12  
  13   All Rights Reserved
  14   
  15   Permission to use, copy, modify, and distribute this software and its
  16   documentation for any purpose and without fee is hereby granted,
  17   provided that the above copyright notice appear in all copies and that
  18   both that copyright notice and this permission notice appear in
  19   supporting documentation, and that the name of the author not be
  20   used in advertising or publicity pertaining to distribution of the
  21   software without specific, written prior permission.
  22   
  23   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  24   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  25   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  26   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  27   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  28   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  29   ***************************************/
  30 
  31 
  32 #include "rip.h"
  33 
  34 /***************************************************************************/
  35 
  36 /*++++++++++++++
  37 Descends the given tree following the last prefix bit to get [past]
  38 the node with the given prefix.
  39 It fills up a stack of COPIES of nodes, including glue nodes.
  40 
  41 Then it also sets the number of elements on the stack: 
  42 set maxdepth to the position where a next one would be written
  43 ( = last + 1, or number of nodes pushed)
  44 
  45    The dmodes:
  46            
  47    RX_STK_QUERY_NOGLUE = (search exact/less spec) stop when 
  48                          * the current prefix length >= newprefix length 
  49                          * the current prefix does not match anymore
  50                          * do not add glue nodes
  51                         
  52    RX_STK_QUERY_ALLNOD = as above, except that the glue and data nodes are
  53                          treated equally (i.e. glue nodes are not skipped)
  54 
  55    RX_STK_CREAT        = descend until the next non-glue node past the one found
  56                          in exact mode (for creation)
  57 
  58 ++++++++++++++*/
  59 
  60 er_ret_t
  61 rx_build_stack(rx_nodcpy_t    stack[], 
     /* [<][>][^][v][top][bottom][index][help] */
  62                int            *maxdepth, 
  63                rx_tree_t      *tree, 
  64                ip_prefix_t    *newpref,
  65                rx_stk_mt      dmode
  66                )
  67 {
  68   register rx_node_t *curnode;
  69   register int link, quit_now=0;
  70   register int tracedet = ER_is_traced( FAC_RX, ASP_RX_STKBLD_DET);
  71   char bbf[IP_PREFSTR_MAX];
  72 
  73   if( ER_is_traced( FAC_RX, ASP_RX_STKBLD_GEN)) {
  74     IP_pref_b2a( newpref , bbf, IP_PREFSTR_MAX);
  75     ER_dbg_va(FAC_RX, ASP_RX_STKBLD_GEN, 
  76             "rx_build_stack: searching for %s in mode %d", bbf, dmode);
  77   }
  78 
  79   *maxdepth = 0;
  80   
  81   if ( tree -> num_nodes == 0) { 
  82     /* The tree was empty. */
  83     return RX_OK;
  84   }
  85   
  86   curnode = tree->top_ptr;
  87   /* this works for RAM, for SQL one would have to call a 'getsqlnode' here*/
  88   
  89   /* OK, there is at least one node. Descend the tree */
  90   /* as long as the correct bit length is not exceeded*/
  91   /* or a glue is being found (take the last non-glue node then) */
  92   /* or you run out of nodes in the direction of descending*/
  93   
  94   do {
  95     /* check at the current node, where the one we look for would fit*/
  96     /* (the second argument of IP_addr_bit_get starts with 0,*/
  97     /* so this effectively looks at the bit next to the last significant bit*/
  98     /* of the current node*/
  99     
 100     link = IP_addr_bit_get( & newpref->ip, curnode->prefix.bits );    
 101     
 102     /* check conditions for leaving the loop    */
 103     if(curnode->child_ptr[link] == NULL) {
 104       /* end of branch. quit after adding the current node to the stack*/
 105       /* (or before - subject to bit test in QUERY mode)*/
 106       quit_now = 1;
 107     }
 108     else {
 109     /* check the node. 
 110        BIG DIFFERENCE between the modes:
 111        in CREAT we don't mind the stack to go too deep, 
 112        in QUERY it can lead to false answers
 113        (e.g. a /24 is found for a /23 query). 
 114 
 115        So this must be "peeled off the stack" later in the search routine,
 116        if both types of stack are to work properly with query searches.
 117     */
 118 
 119 
 120       if( curnode->prefix.bits > newpref->bits ) {
 121         /* deep enough.*/
 122         quit_now = 2;
 123       }
 124 
 125       if(dmode == RX_STK_CREAT && curnode->glue) {
 126         /* mode: creation. */
 127         /* Cancel quitting if glue -- in CREAT mode the stack building */
 128         /* should stop at the next real (non-glue) node.*/
 129         /* ("next" meaning following link #0)*/
 130         quit_now = 0;
 131       }
 132     }
 133     
 134     /* now that the conditions for leaving the loop after the node is
 135        added on the stack, see if we shouldn't leave the loop BEFOREHAND */
 136     
 137     /* In query mode, we should quit as soon as we see a mismatch */
 138 
 139     if(dmode != RX_STK_CREAT
 140        && 0 != IP_addr_cmp(&curnode->prefix.ip, &newpref->ip, 
 141                            curnode->prefix.bits) ) {
 142         /*QUIT NOW! (but add this node)*/
 143       quit_now = 4;
 144     }
 145 
 146     /* push the current node on the stack. RAM only.*/
 147     /* */
 148     /* (unless quit_now is 64 which means do NOT copy the current node.*/
 149     /**/
 150     /* In CREAT and QUERY_ALLNOD modes, push everything. */
 151     /* In QUERY_NOGLUE mode, only non-glues.*/
 152       
 153     if( /* quit_now < 64 &&           disabled as 64 is not in use right now */
 154        (dmode != RX_STK_QUERY_NOGLUE || curnode->glue == 0 )) {
 155         memcpy( & stack[*maxdepth].cpy, curnode, sizeof(rx_node_t));
 156         stack[*maxdepth].srcptr = curnode;
 157         stack[*maxdepth].srckey = SQ_NOKEY;
 158         stack[*maxdepth].tree = tree;
 159         (*maxdepth)++;
 160     }
 161     
 162     /* make debug info.*/
 163    
 164     if( tracedet ) {
 165       IP_pref_b2a( & curnode->prefix , bbf, IP_PREFSTR_MAX );
 166       ER_dbg_va(FAC_RX, ASP_RX_STKBLD_DET,
 167                 "rx_build_stack: %s%d at %s%s (stk len: %d)",
 168                 quit_now ? "stop/" : "link ",  
 169                 quit_now ? quit_now : link,
 170                 bbf, ( curnode->glue ) ? " ++glue++" : "",
 171                 *maxdepth  );
 172     }
 173     
 174     curnode = curnode -> child_ptr[link];
 175 
 176   } while( !quit_now ); 
 177 
 178   return RX_OK;
 179 }
 180 
 181 /***************************************************************************/
 182 /*+++++++++
 183    helper for the nod_search routine: 
 184 
 185    allocate a new node copy struct, copy the struct and add to nodlist
 186 ++++++++++*/
 187 
 188 static
 189 er_ret_t
 190 rx_nod_append( GList **nodlist, rx_nodcpy_t *element) 
     /* [<][>][^][v][top][bottom][index][help] */
 191 {
 192   rx_nodcpy_t *newcpy;
 193   
 194   newcpy = (rx_nodcpy_t *)UT_malloc(sizeof(rx_nodcpy_t));
 195   memcpy(newcpy, element, sizeof(rx_nodcpy_t));        
 196   (*nodlist) = g_list_prepend( *nodlist, newcpy );
 197 
 198   return RX_OK;
 199 }
 200 
 201 
 202 
 203 
 204 /***************************************************************************/
 205 
 206 /*+++++++++++
 207   helper for MORE specific lookup in rx_nod_search 
 208 
 209   adds a node to the list of answers.
 210 +++++++++++*/
 211 
 212 static
 213 er_ret_t
 214 rx_walk_hook_addnode(rx_node_t *node, int level, int nodecounter, 
     /* [<][>][^][v][top][bottom][index][help] */
 215                      void *userptr)
 216 {   
 217   rx_nodcpy_t nodcpy;
 218   hook_addnode_userdat_t *userdat = userptr;
 219   
 220 
 221   /* do not append glue nodes*/
 222   if( node->glue == 1 ) return RX_OK;
 223   
 224   /* in RAM mode, do not copy the node.*/
 225   /*  memcpy( &nodcpy.cpy, node, sizeof(rx_node_t));*/
 226 
 227   /* XXX reset to 0 to avoid warnings from workshop: but it 
 228      slows things down! */
 229   memset( &nodcpy.cpy, 0, sizeof(rx_node_t));
 230 
 231   nodcpy.srcptr = node;
 232   nodcpy.srckey = SQ_NOKEY;
 233   nodcpy.tree = userdat->tree;
 234   
 235   return rx_nod_append( userdat->nodlist, &nodcpy);
 236 }
 237 
 238 
 239 /***************************************************************************/
 240 
 241 /*+++++++++++
 242   helper for DBLS lookup in rx_nod_search 
 243 
 244   adds a node to the list of answers.
 245 +++++++++++*/
 246 
 247 static
 248 er_ret_t
 249 rx_walk_hook_adddoubles(rx_node_t *node, int level, int nodecounter, 
     /* [<][>][^][v][top][bottom][index][help] */
 250                         void *userptr)
 251 {
 252   rx_nodcpy_t nodcpy;
 253   hook_addnode_userdat_t  *userdat = userptr;
 254   int leaves = g_list_length(node->leaves_ptr);
 255   char buf[1024];
 256   
 257   /* do not append glue nodes*/
 258   if( node->glue == 1 ) return RX_OK;
 259 
 260  
 261   /* add only nodes with more than 1 dataleaf*/
 262   if( leaves < 2 ) return RX_OK;
 263 
 264   if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
 265     rx_nod_print(node, buf, 1024);
 266     ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
 267               "rx_walk_hook_adddoubles: %30s, %d leaves", buf, leaves);
 268   }
 269 
 270   /*  memcpy( &nodcpy.cpy, node, sizeof(rx_node_t));*/
 271   nodcpy.srcptr = node;
 272   nodcpy.srckey = SQ_NOKEY;
 273   nodcpy.tree = userdat->tree;
 274   
 275   return rx_nod_append( userdat->nodlist, &nodcpy);
 276 }
 277 
 278 
 279 /***************************************************************************/
 280 er_ret_t
 281 rx_nod_search (
     /* [<][>][^][v][top][bottom][index][help] */
 282                rx_srch_mt  search_mode,
 283                int         par_a,
 284                int         par_b,
 285                /* see rx_asc_search() for explanation */
 286                rx_tree_t  *tree,           /* tree ptr*/
 287                ip_prefix_t  *prefix,          /* binary prefix*/
 288 
 289                rx_nodcpy_t stack[],         /* stack==array of node_copies*/
 290                int         stackcount,      /* number of element on the stack,*/
 291                                             /* can come from a creat stack!*/
 292 
 293                GList       **nodlist,       /* answers go here*/
 294                int         max_count        /* max # of answers*/
 295                )                        
 296      /*
 297         searches the stack for a given prefix, finds *nodes* in the stack 
 298         and appends *copies of the nodes* to the nodlist;
 299 
 300         finds
 301         0 or 1 nodes for exact search
 302         0 or 1 nodes for exless (0 if no less specific node found)
 303         any number (incl. 0) for {more|less}^n-m specific 
 304      
 305        returns errcode.
 306 
 307        
 308      */
 309 {
 310   char buf[1024];
 311   int sps = stackcount-1;       /* stack position.*/
 312   int depthcounter=0;
 313   er_ret_t err=RX_OK;
 314   int i;
 315   hook_addnode_userdat_t datstr;
 316   er_ret_t (*hook_function)();  /* pointer to the walk_hook function*/
 317                                 /* (see MORE spec lookup)*/
 318 
 319   /* structure for carrying data to walk_tree hook functions, used only
 320      in MORE, DBLS and RANG search modes 
 321   */
 322   datstr.nodlist = nodlist;
 323   datstr.tree    = tree;
 324   datstr.prefix  = prefix;
 325     
 326   
 327   if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
 328     IP_pref_b2a( prefix , buf, IP_PREFSTR_MAX);
 329     ER_dbg_va(FAC_RX, ASP_RX_SRCH_GEN,
 330               "rx_nod_search: searching for %s in mode %d (%s)", 
 331               buf, search_mode, RX_text_srch_mode(search_mode) );
 332   }
 333 
 334   /* in non-CREAT modes, glue nodes are skipped anyway. 
 335      (they should normally not be there if the stack was created in
 336      the STK_QUERY mode, but it's possible to use a CREAT stack too).
 337 
 338      It's also possible that the stack is too deep.
 339      So, truncate the stack to the last non-glue node 
 340      of the length <= search term.
 341      otherwise a /24 would be returned for a /23 query.
 342      
 343      For LESS SPECIFIC searches one has to peel off entries
 344      whose prefixes do not contain the search term, 
 345   */
 346 
 347   if( search_mode != RX_SRCH_CREAT ) {
 348     
 349     while( sps >= 0 ) {
 350       char *reason = NULL;
 351 
 352       if( stack[sps].cpy.prefix.bits > prefix->bits ) {            /* too deep*/ 
 353         reason = "2deep";
 354       } 
 355       else if( 0 != IP_addr_cmp(& stack[sps].cpy.prefix.ip, &prefix->ip, 
 356                                 stack[sps].cpy.prefix.bits) ) {   /* mismatch */
 357         reason = "mismatch";
 358       }
 359       else if ( search_mode != RX_SRCH_MORE && search_mode != RX_SRCH_DBLS 
 360                 && search_mode != RX_SRCH_RANG && stack[sps].cpy.glue == 1 ) {                    /* is glue*/
 361         reason = "glue";
 362       } 
 363 #if 0 
 364       /* mhm. it can't be limited here, must be done in RP */
 365       else if ( search_mode == RX_SRCH_LESS && par_a == 1
 366                 && stack[sps].cpy.prefix.bits == prefix->bits ) {  /* too deep*/
 367         reason = "2deep4less";
 368       }
 369 #endif
 370         
 371       else {
 372         
 373         break;  /* stop peeling off */
 374       }
 375       
 376       if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
 377         rx_nod_print( & stack[sps].cpy , buf, IP_PREFSTR_MAX);
 378         ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
 379                   "rx_nod_search: peeling off %d: %s (%s)", sps, buf, reason);
 380       }
 381       sps--;
 382     }
 383   }
 384   
 385   /* nothing left on the stack. Sorry.*/
 386   /* we allow that for more spec search -- this means*/
 387   /* that the search term is a shorter prefix than the one*/
 388   /* in the top node. Possibly it's 0/0 which is valid for more spec search.*/
 389 
 390   if( search_mode != RX_SRCH_MORE && search_mode != RX_SRCH_DBLS 
 391       && sps < 0 ) {       
 392     return RX_OK;
 393   }
 394       
 395   switch(search_mode) {
 396   case RX_SRCH_EXACT:
 397   case RX_SRCH_CREAT:
 398     /* go up the tree (stack) and exit when the proper prefix is found.*/
 399     /* For RX_SRCH_EXACT skip glue nodes, for RX_SRCH_CREAT take all.*/
 400     /* They may contain a valid prefix, so watch out.*/
 401 
 402     while(sps >= 0) {
 403 
 404       if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
 405         rx_nod_print(& stack[sps].cpy, buf, 1024);
 406         ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
 407                   "rx_nod_search: position %d: %s", sps, buf);
 408       }
 409       
 410       if ( search_mode == RX_SRCH_EXACT 
 411            && stack[sps].cpy.glue ) {
 412         die;
 413       }
 414       
 415       if ( memcmp( & stack[sps].cpy.prefix, 
 416                    prefix, 
 417                    sizeof(ip_prefix_t)) == 0 ) {
 418         /* FOUND!!*/
 419         /* add to the nodlist.*/
 420 
 421         if( (err=rx_nod_append( nodlist, & stack[sps])) != RX_OK ) {
 422           return err;
 423         }
 424 
 425         ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET, "rx_nod_search: found!");
 426         break;
 427       }
 428       sps--;
 429     }
 430     break;
 431 
 432   case RX_SRCH_EXLESS:
 433     /* just fetch the last element off the stack (if any). */
 434     /* Must be non-glue for EXLESS.*/
 435 
 436     if( sps >= 0 ) {
 437       rx_nod_append( nodlist, & stack[sps]); 
 438     }
 439 
 440     /* else : nothing found.*/
 441     /* For EXLESS: check if the stack contains only non-glue nodes.*/
 442     /* If it contains a glue, it means it was created in the CREAT mode,*/
 443     /* which renders the above algorithm absolutely useless. Then crash,*/
 444     /* this is a programmer's error.*/
 445 
 446     while( sps >= 0 ) {
 447       if( stack[sps].cpy.glue ) {
 448         die;
 449       }
 450       sps--;
 451     }
 452 
 453     break;
 454 
 455   case RX_SRCH_LESS:
 456     while( sps >= 0 && depthcounter < par_a ) {
 457       if( stack[sps].cpy.glue == 0 ) {
 458         rx_nod_append( nodlist, & stack[sps]); 
 459         depthcounter++;
 460       }
 461       sps--;
 462     }
 463     break;
 464 
 465   case RX_SRCH_MORE:
 466   case RX_SRCH_DBLS:   /* special (debug?) mode : find nodes with multiple*/
 467                        /* data leaves. Much like more specific, except that*/
 468                        /* most nodes will be skipped.*/
 469                        /* The difference is in calling another hook function*/
 470     hook_function = ( search_mode == RX_SRCH_MORE )  
 471       ? rx_walk_hook_addnode
 472       : rx_walk_hook_adddoubles;
 473     
 474     /* the result of a more spec search should NOT contain the object exactly*/
 475     /* matching the query, even if it exists in the database. So two walks are */
 476     /* performed, one for each child (if it exists). */
 477     /* MEMORY IMPLEMENTATION ONLY FOR THE MOMENT*/
 478 
 479     /* start from the top node if the searched prefix is between the 
 480        top node and the first node on the stack (i.e. the first node is
 481        contained within the search term) */
 482     
 483     /* COVERS THE CASE 0.0.0.0/0 */
 484     /* or any other prefix that the tree might be set to represent,*/
 485     /* but there is no actual object for it (not even glue)*/
 486 
 487     if( sps < 0 ) {
 488       if( tree->num_nodes > 0         /* there is any node in the tree */  
 489           && 0 == IP_addr_cmp( & prefix->ip, 
 490                                & stack[0].cpy.prefix.ip,
 491                                prefix->bits) ) {     /* addr match */
 492         rx_walk_tree( tree->top_ptr, hook_function,
 493                       /* RX_WALK_REVERS | */ RX_WALK_SKPGLU, /* skip glue nodes while counting*/
 494                       par_a, /* display this many levels */
 495                       0, 0, &datstr, &err);
 496         if( err != RX_OK ) {
 497           return err;
 498         }
 499       }
 500     } /* if nothing on stack */
 501     else { 
 502 
 503       /* walk from this node if it matches the query prefix and is
 504        long enough (if it is shorter, then it will harvest too many
 505        results
 506       */
 507       if(  prefix->bits <= stack[sps].srcptr->prefix.bits
 508            && 0 == IP_addr_cmp( & stack[sps].srcptr->prefix.ip, 
 509                                 & prefix->ip, 
 510                                 prefix->bits) ) {
 511         rx_walk_tree( stack[sps].srcptr,  hook_function,
 512                       /* RX_WALK_REVERS | */ RX_WALK_SKPGLU, /* skip glue nodes while counting*/
 513                       par_a, /* display up to this max length*/
 514                       0, 0, &datstr, &err);
 515         if( err != RX_OK ) {
 516           return err;
 517         }
 518       }      
 519       else {
 520         /* or walk the child nodes otherwise (still check the address) */
 521         
 522         for( i = 1; i >= 0; i--) {
 523           if( stack[sps].cpy.child_ptr[i] != NULL ) {
 524             if( ER_is_traced( FAC_RX, ASP_RX_SRCH_DET)) {
 525               IP_pref_b2a(& stack[sps].cpy.child_ptr[i]->prefix, buf, 1023);
 526             }
 527             
 528             if( 0 == IP_addr_cmp( & stack[sps].cpy.child_ptr[i]->prefix.ip, 
 529                                   & prefix->ip, 
 530                                   prefix->bits) ) {
 531               
 532               ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
 533                         "rx_nod_search: digging child %d: %s", i, buf);
 534               
 535               rx_walk_tree( stack[sps].cpy.child_ptr[i],  hook_function, 
 536                             /* RX_WALK_REVERS | */ RX_WALK_SKPGLU, /* skip glue nodes while counting*/
 537                             par_a, /* display this many levels */
 538                             0, 0, &datstr, &err);
 539               if( err != RX_OK ) {
 540                 return err;
 541               }
 542           }
 543             else {
 544               ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET,
 545                         "rx_nod_search: prefix mismatch with child %d: %s", 
 546                         i, buf);
 547             }
 548           }
 549         }
 550       } /* if node does not match, dig child nodes */
 551       
 552     }
 553     break;
 554 
 555   case RX_SRCH_RANG:
 556     /* OK, start from the node at the end of the stack (exless match including
 557        glue nodes) then
 558 
 559        
 560        if its prefix length is 
 561          OK -> found! descend from here as long as the prefixes are in range
 562          shorter -> apparently there is even no such glue node. come back down
 563                     one step
 564                    
 565     */
 566     
 567     i = sps;               /* go up the tree (down the stack) */
 568                            /* until too far (one node too much, after >= )*/
 569     while( i >= 0 && stack[i].cpy.prefix.bits >= prefix->bits ) {
 570       i--;
 571     }
 572     
 573     /* look where you are:*/
 574     
 575     if( i < 0 )          /* it was the top object, but its prefix was too long*/
 576       i=0;               /* take the top object as the base*/
 577     else
 578       i++;               /* went one too much, now come back one step*/
 579     
 580     
 581     rx_walk_tree( stack[i].srcptr,  rx_walk_hook_addnode, 
 582                   RX_WALK_PRFLEN, /* skip glue nodes while counting*/
 583                   par_a, /* display up to this max length*/
 584                   0, 0, &datstr, &err);
 585     if( err != RX_OK ) {
 586       return err;
 587     }
 588     
 589     break;    
 590 
 591     /* return RX_NOYETI;*/
 592     /*not implemented*/
 593     /*    die; */
 594   default:
 595     die; /* are you nuts??*/
 596   }
 597 
 598   return err;
 599 
 600 }
 601 
 602 
 603 
 604 /*****************************************************************************/
 605 
 606 /*+++++++++++++
 607   builds a stack for this prefix, finds *nodes* in the stack 
 608   and appends *copies of the data leaves* to the LL of answers;
 609   
 610   sorts by SQL object keys and uniq's the data
 611   
 612   finds:
 613   0 or 1 nodes for exact search
 614   0 or 1 nodes for exless (0 if no less specific node found)
 615   any number (incl. 0) for {more|less}-n specific 
 616   
 617   then copies the nodes/dataleaves to the answer structs and appends them
 618   to the given LL. So, effectively, the number of answers can be
 619   anything from 0 to infinity, because objects may be duplicate 
 620   even at the same node.
 621   
 622   returns errcode.
 623   
 624   algorithm:
 625   
 626   builds stack[MAXBIT (==128)];
 627   
 628   if( more/less-depth && par_a == 0)
 629   
 630   run rx_nod_search, then 
 631   
 632   if(more spec) rx_nod_walk(maxdepth=n, append_to_LL() );
 633   if(less spec) do { append(LL, stack[i]) } while(i-- && n--);
 634   otherwise just set LL
 635   
 636   
 637   The routine provides _at_least_ max_count answers. 
 638   It will *try* to stop after max_count as soon as possible 
 639   - but it's the higher level routine that should do the final cut.
 640 +++++++++++++++*/
 641 
 642 er_ret_t
 643 RX_bin_search (
     /* [<][>][^][v][top][bottom][index][help] */
 644                rx_srch_mt  search_mode,
 645                int         par_a,
 646                int         par_b,
 647                rx_tree_t  *tree,           /* tree ptr*/
 648                ip_prefix_t *prefix,         /* binary prefix*/
 649                GList       **datleaves,    /* data leaves go here*/
 650                int         max_count 
 651                )
 652    
 653 {
 654   rx_nodcpy_t  stack[128];
 655   unsigned k;
 656   int stkcnt, resnum = 0, maxleaves;
 657   GList  *nodlist = NULL, *nitem;
 658   rx_node_t *curnode;
 659   rx_nodcpy_t *curcpy;
 660   rx_datref_t *datref;
 661   rx_stk_mt     dmode;
 662 
 663   /* more specific node search may start from a glue node, */
 664   /* for all others the stack should not contain glues.*/
 665 
 666   dmode = ( search_mode == RX_SRCH_MORE 
 667             || search_mode == RX_SRCH_DBLS
 668             || search_mode == RX_SRCH_RANG ) 
 669     ? RX_STK_QUERY_ALLNOD
 670     : RX_STK_QUERY_NOGLUE;
 671   
 672   rx_build_stack(stack, &stkcnt, tree, prefix, dmode);
 673 
 674   rx_nod_search( search_mode, par_a, par_b, tree, prefix, 
 675                  stack, stkcnt, &nodlist, 1000);
 676   
 677   ER_dbg_va(FAC_RX, ASP_RX_SRCH_DET, "RX_bin_search: processing nodes");
 678 
 679   for( nitem = g_list_first(nodlist);
 680        nitem != NULL;
 681        nitem = g_list_next(nitem)) {    
 682     
 683     resnum++;
 684     curcpy = nitem->data;
 685     
 686     /*
 687       if memory mode includes RAM:
 688       * do not expect copies of nodes in the list received from bin_search.
 689       * iterate through data leaves with g_list_nth_data.
 690       */
 691     
 692     curnode = curcpy->srcptr;
 693     
 694     /*    rx_nod_print( curnode, buf, 1024 );*/
 695     
 696     maxleaves = g_list_length(curnode->leaves_ptr);
 697     /*    fprintf(stderr,"###node %d, %d dataleaves attached:", i, maxleaves);*/
 698 
 699     /* iterate through dataleafs attached to this node*/
 700     for(k=0; k<maxleaves; k++) {
 701       rx_dataleaf_t *leafptr = g_list_nth_data(curnode->leaves_ptr, k);
 702 
 703       /* 
 704          check the conditions to add the leaf:
 705 
 706          XXX never add composed inetnum for exact prefix search
 707          (but do for exact range search...) - must be solved in upper layer.
 708 
 709       */
 710 
 711  
 712       /* add*/
 713       
 714       datref = (rx_datref_t *)UT_calloc(1, sizeof(rx_datref_t));
 715       datref->leafptr = leafptr;
 716       /* srckey and excluded fields are initialised to 0 by calloc */
 717       
 718       *datleaves = g_list_prepend(*datleaves, datref);
 719     }
 720   }
 721 
 722   wr_clear_list( &nodlist );
 723 
 724   ER_dbg_va(FAC_RX, ASP_RX_SRCH_GEN,
 725             "RX_bin_search: found %d nodes", resnum);
 726     
 727   
 728   /* the LL of answers (*datleaves) contains pointers to answer structs, 
 729      that SHOULD BE NORMALIZED HERE (==with no redundant entries)
 730   */
 731 
 732 return RX_OK;
 733 }
 734 

/* [<][>][^][v][top][bottom][index][help] */