00001 /* ========================================================================== ** 00002 * ubi_BinTree.c 00003 * 00004 * Copyright (C) 1991-1998 by Christopher R. Hertel 00005 * 00006 * Email: crh@ubiqx.mn.org 00007 * -------------------------------------------------------------------------- ** 00008 * 00009 * This module implements a simple binary tree. 00010 * 00011 * -------------------------------------------------------------------------- ** 00012 * 00013 * This library is free software; you can redistribute it and/or 00014 * modify it under the terms of the GNU Library General Public 00015 * License as published by the Free Software Foundation; either 00016 * version 2 of the License, or (at your option) any later version. 00017 * 00018 * This library is distributed in the hope that it will be useful, 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00021 * Library General Public License for more details. 00022 * 00023 * You should have received a copy of the GNU Library General Public 00024 * License along with this library; if not, write to the Free 00025 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00026 * 00027 * -------------------------------------------------------------------------- ** 00028 * 00029 * $Log: ubi_BinTree.c,v $ 00030 * Revision 1.2 2005/07/18 21:54:26 crojo 00031 * *** empty log message *** 00032 * 00033 * Revision 1.1 2004/01/14 20:27:14 dwarren 00034 * XSB Prolog Profiling as command line option -p 00035 * 00036 * Revision 4.10 2000/06/06 20:38:40 crh 00037 * In the ReplaceNode() function, the old node header was being copied 00038 * to the new node header using a byte-by-byte copy. This was causing 00039 * the 'insure' software testing program to report a memory leak. The 00040 * fix was to do a simple assignement: *newnode = *oldnode; 00041 * This quieted the (errant) memory leak reports and is probably a bit 00042 * faster than the bytewise copy. 00043 * 00044 * Revision 4.9 2000/01/08 23:24:30 crh 00045 * Clarified a variety of if( pointer ) lines, replacing them with 00046 * if( NULL != pointer ). This is more correct, and I have heard 00047 * of at least one (obscure?) system out there that uses a non-zero 00048 * value for NULL. 00049 * Also, speed improvement in Neighbor(). It was comparing pointers 00050 * when it could have compared two gender values. The pointer 00051 * comparison was somewhat indirect (does pointer equal the pointer 00052 * of the parent of the node pointed to by pointer). Urq. 00053 * 00054 * Revision 4.8 1999/09/22 03:40:30 crh 00055 * Modified ubi_btTraverse() and ubi_btKillTree(). They now return an 00056 * unsigned long indicating the number of nodes processed. The change 00057 * is subtle. An empty tree formerly returned False, and now returns 00058 * zero. 00059 * 00060 * Revision 4.7 1998/10/21 06:14:42 crh 00061 * Fixed bugs in FirstOf() and LastOf() reported by Massimo Campostrini. 00062 * See function comments. 00063 * 00064 * Revision 4.6 1998/07/25 17:02:10 crh 00065 * Added the ubi_trNewTree() macro. 00066 * 00067 * Revision 4.5 1998/06/04 21:29:27 crh 00068 * Upper-cased defined constants (eg UBI_BINTREE_H) in some header files. 00069 * This is more "standard", and is what people expect. Weird, eh? 00070 * 00071 * Revision 4.4 1998/06/03 17:42:46 crh 00072 * Further fiddling with sys_include.h. It's now in ubi_BinTree.h which is 00073 * included by all of the binary tree files. 00074 * 00075 * Reminder: Some of the ubi_tr* macros in ubi_BinTree.h are redefined in 00076 * ubi_AVLtree.h and ubi_SplayTree.h. This allows easy swapping 00077 * of tree types by simply changing a header. Unfortunately, the 00078 * macro redefinitions in ubi_AVLtree.h and ubi_SplayTree.h will 00079 * conflict if used together. You must either choose a single tree 00080 * type, or use the underlying function calls directly. Compare 00081 * the two header files for more information. 00082 * 00083 * Revision 4.3 1998/06/02 01:28:43 crh 00084 * Changed ubi_null.h to sys_include.h to make it more generic. 00085 * 00086 * Revision 4.2 1998/05/20 04:32:36 crh 00087 * The C file now includes ubi_null.h. See ubi_null.h for more info. 00088 * Also, the balance and gender fields of the node were declared as 00089 * signed char. As I understand it, at least one SunOS or Solaris 00090 * compiler doesn't like "signed char". The declarations were 00091 * wrong anyway, so I changed them to simple "char". 00092 * 00093 * Revision 4.1 1998/03/31 06:11:57 crh 00094 * Thomas Aglassinger sent E'mail pointing out errors in the 00095 * dereferencing of function pointers, and a missing typecast. 00096 * Thanks, Thomas! 00097 * 00098 * Revision 4.0 1998/03/10 03:19:22 crh 00099 * Added the AVL field 'balance' to the ubi_btNode structure. This means 00100 * that all BinTree modules now use the same basic node structure, which 00101 * greatly simplifies the AVL module. 00102 * Decided that this was a big enough change to justify a new major revision 00103 * number. 3.0 was an error, so we're at 4.0. 00104 * 00105 * Revision 2.6 1998/01/24 06:27:46 crh 00106 * Added ubi_trCount() macro. 00107 * 00108 * Revision 2.5 1997/12/23 03:56:29 crh 00109 * In this version, all constants & macros defined in the header file have 00110 * the ubi_tr prefix. Also cleaned up anything that gcc complained about 00111 * when run with '-pedantic -fsyntax-only -Wall'. 00112 * 00113 * Revision 2.4 1997/07/26 04:11:10 crh 00114 * + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE 00115 * and ubi_trFALSE. 00116 * + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE. 00117 * + There used to be something called "ubi_TypeDefs.h". I got rid of it. 00118 * + Added function ubi_btLeafNode(). 00119 * 00120 * Revision 2.3 1997/06/03 05:16:17 crh 00121 * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts. 00122 * Also changed the interface to function InitTree(). See the comments 00123 * for this function for more information. 00124 * 00125 * Revision 2.2 1995/10/03 22:00:07 CRH 00126 * Ubisized! 00127 * 00128 * Revision 2.1 95/03/09 23:37:10 CRH 00129 * Added the ModuleID static string and function. These modules are now 00130 * self-identifying. 00131 * 00132 * Revision 2.0 95/02/27 22:00:17 CRH 00133 * Revision 2.0 of this program includes the following changes: 00134 * 00135 * 1) A fix to a major typo in the RepaceNode() function. 00136 * 2) The addition of the static function Border(). 00137 * 3) The addition of the public functions FirstOf() and LastOf(), which 00138 * use Border(). These functions are used with trees that allow 00139 * duplicate keys. 00140 * 4) A complete rewrite of the Locate() function. Locate() now accepts 00141 * a "comparison" operator. 00142 * 5) Overall enhancements to both code and comments. 00143 * 00144 * I decided to give this a new major rev number because the interface has 00145 * changed. In particular, there are two new functions, and changes to the 00146 * Locate() function. 00147 * 00148 * Revision 1.0 93/10/15 22:44:59 CRH 00149 * With this revision, I have added a set of #define's that provide a single, 00150 * standard API to all existing tree modules. Until now, each of the three 00151 * existing modules had a different function and typedef prefix, as follows: 00152 * 00153 * Module Prefix 00154 * ubi_BinTree ubi_bt 00155 * ubi_AVLtree ubi_avl 00156 * ubi_SplayTree ubi_spt 00157 * 00158 * To further complicate matters, only those portions of the base module 00159 * (ubi_BinTree) that were superceeded in the new module had the new names. 00160 * For example, if you were using ubi_SplayTree, the locate function was 00161 * called "ubi_sptLocate", but the next and previous functions remained 00162 * "ubi_btNext" and "ubi_btPrev". 00163 * 00164 * This was not too terrible if you were familiar with the modules and knew 00165 * exactly which tree model you wanted to use. If you wanted to be able to 00166 * change modules (for speed comparisons, etc), things could get messy very 00167 * quickly. 00168 * 00169 * So, I have added a set of defined names that get redefined in any of the 00170 * descendant modules. To use this standardized interface in your code, 00171 * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with 00172 * "ubi_tr". The "ubi_tr" names will resolve to the correct function or 00173 * datatype names for the module that you are using. Just remember to 00174 * include the header for that module in your program file. Because these 00175 * names are handled by the preprocessor, there is no added run-time 00176 * overhead. 00177 * 00178 * Note that the original names do still exist, and can be used if you wish 00179 * to write code directly to a specific module. This should probably only be 00180 * done if you are planning to implement a new descendant type, such as 00181 * red/black trees. CRH 00182 * 00183 * V0.0 - June, 1991 - Written by Christopher R. Hertel (CRH). 00184 * 00185 * ========================================================================== ** 00186 */ 00187 00188 #include "ubi_BinTree.h" /* Header for this module. */ 00189 00190 /* ========================================================================== ** 00191 * Static data. 00192 */ 00193 00194 static char ModuleID[] = "ubi_BinTree\n\ 00195 \t$Revision: 1.2 $\n\ 00196 \t$Date: 2005/07/18 21:54:26 $\n\ 00197 \t$Author: crojo $\n"; 00198 00199 /* ========================================================================== ** 00200 * Internal (private) functions. 00201 */ 00202 00203 static ubi_btNodePtr qFind( ubi_btCompFunc cmp, 00204 ubi_btItemPtr FindMe, 00205 register ubi_btNodePtr p ) 00206 /* ------------------------------------------------------------------------ ** 00207 * This function performs a non-recursive search of a tree for a node 00208 * matching a specific key. It is called "qFind()" because it is 00209 * faster that TreeFind (below). 00210 * 00211 * Input: 00212 * cmp - a pointer to the tree's comparison function. 00213 * FindMe - a pointer to the key value for which to search. 00214 * p - a pointer to the starting point of the search. <p> 00215 * is considered to be the root of a subtree, and only 00216 * the subtree will be searched. 00217 * 00218 * Output: 00219 * A pointer to a node with a key that matches the key indicated by 00220 * FindMe, or NULL if no such node was found. 00221 * 00222 * Note: In a tree that allows duplicates, the pointer returned *might 00223 * not* point to the (sequentially) first occurance of the 00224 * desired key. 00225 * ------------------------------------------------------------------------ ** 00226 */ 00227 { 00228 int tmp; 00229 00230 while( (NULL != p) 00231 && ((tmp = ubi_trAbNormal( (*cmp)(FindMe, p) )) != ubi_trEQUAL) ) 00232 p = p->Link[tmp]; 00233 00234 return( p ); 00235 } /* qFind */ 00236 00237 static ubi_btNodePtr TreeFind( ubi_btItemPtr findme, 00238 ubi_btNodePtr p, 00239 ubi_btNodePtr *parentp, 00240 char *gender, 00241 ubi_btCompFunc CmpFunc ) 00242 /* ------------------------------------------------------------------------ ** 00243 * TreeFind() searches a tree for a given value (findme). It will return a 00244 * pointer to the target node, if found, or NULL if the target node was not 00245 * found. 00246 * 00247 * TreeFind() also returns, via parameters, a pointer to the parent of the 00248 * target node, and a LEFT or RIGHT value indicating which child of the 00249 * parent is the target node. *If the target is not found*, then these 00250 * values indicate the place at which the target *should be found*. This 00251 * is useful when inserting a new node into a tree or searching for nodes 00252 * "near" the target node. 00253 * 00254 * The parameters are: 00255 * 00256 * findme - is a pointer to the key information to be searched for. 00257 * p - points to the root of the tree to be searched. 00258 * parentp - will return a pointer to a pointer to the !parent! of the 00259 * target node, which can be especially usefull if the target 00260 * was not found. 00261 * gender - returns LEFT or RIGHT to indicate which child of *parentp 00262 * was last searched. 00263 * CmpFunc - points to the comparison function. 00264 * 00265 * This function is called by ubi_btLocate() and ubi_btInsert(). 00266 * ------------------------------------------------------------------------ ** 00267 */ 00268 { 00269 register ubi_btNodePtr tmp_p = p; 00270 ubi_btNodePtr tmp_pp = NULL; 00271 char tmp_gender = ubi_trEQUAL; 00272 int tmp_cmp; 00273 00274 while( (NULL != tmp_p) 00275 && (ubi_trEQUAL != (tmp_cmp = ubi_trAbNormal((*CmpFunc)(findme, tmp_p)))) ) 00276 { 00277 tmp_pp = tmp_p; /* Keep track of previous node. */ 00278 tmp_gender = (char)tmp_cmp; /* Keep track of sex of child. */ 00279 tmp_p = tmp_p->Link[tmp_cmp]; /* Go to child. */ 00280 } 00281 *parentp = tmp_pp; /* Return results. */ 00282 *gender = tmp_gender; 00283 return( tmp_p ); 00284 } /* TreeFind */ 00285 00286 static void ReplaceNode( ubi_btNodePtr *parent, 00287 ubi_btNodePtr oldnode, 00288 ubi_btNodePtr newnode ) 00289 /* ------------------------------------------------------------------------ ** 00290 * Remove node oldnode from the tree, replacing it with node newnode. 00291 * 00292 * Input: 00293 * parent - A pointer to he parent pointer of the node to be 00294 * replaced. <parent> may point to the Link[] field of 00295 * a parent node, or it may indicate the root pointer at 00296 * the top of the tree. 00297 * oldnode - A pointer to the node that is to be replaced. 00298 * newnode - A pointer to the node that is to be installed in the 00299 * place of <*oldnode>. 00300 * 00301 * Notes: Don't forget to free oldnode. 00302 * Also, this function used to have a really nasty typo 00303 * bug. "oldnode" and "newnode" were swapped in the line 00304 * that now reads: 00305 * ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i]; 00306 * Bleah! 00307 * ------------------------------------------------------------------------ ** 00308 */ 00309 { 00310 *newnode = *oldnode; /* Copy node internals to new node. */ 00311 00312 (*parent) = newnode; /* Old node's parent points to new child. */ 00313 /* Now tell the children about their new step-parent. */ 00314 if( oldnode->Link[ubi_trLEFT] ) 00315 (oldnode->Link[ubi_trLEFT])->Link[ubi_trPARENT] = newnode; 00316 if( oldnode->Link[ubi_trRIGHT] ) 00317 (oldnode->Link[ubi_trRIGHT])->Link[ubi_trPARENT] = newnode; 00318 } /* ReplaceNode */ 00319 00320 static void SwapNodes( ubi_btRootPtr RootPtr, 00321 ubi_btNodePtr Node1, 00322 ubi_btNodePtr Node2 ) 00323 /* ------------------------------------------------------------------------ ** 00324 * This function swaps two nodes in the tree. Node1 will take the place of 00325 * Node2, and Node2 will fill in the space left vacant by Node 1. 00326 * 00327 * Input: 00328 * RootPtr - pointer to the tree header structure for this tree. 00329 * Node1 - \ 00330 * > These are the two nodes which are to be swapped. 00331 * Node2 - / 00332 * 00333 * Notes: 00334 * This function does a three step swap, using a dummy node as a place 00335 * holder. This function is used by ubi_btRemove(). 00336 * ------------------------------------------------------------------------ ** 00337 */ 00338 { 00339 ubi_btNodePtr *Parent; 00340 ubi_btNode dummy; 00341 ubi_btNodePtr dummy_p = &dummy; 00342 00343 /* Replace Node 1 with the dummy, thus removing Node1 from the tree. */ 00344 if( NULL != Node1->Link[ubi_trPARENT] ) 00345 Parent = &((Node1->Link[ubi_trPARENT])->Link[(int)(Node1->gender)]); 00346 else 00347 Parent = &(RootPtr->root); 00348 ReplaceNode( Parent, Node1, dummy_p ); 00349 00350 /* Swap Node 1 with Node 2, placing Node 1 back into the tree. */ 00351 if( NULL != Node2->Link[ubi_trPARENT] ) 00352 Parent = &((Node2->Link[ubi_trPARENT])->Link[(int)(Node2->gender)]); 00353 else 00354 Parent = &(RootPtr->root); 00355 ReplaceNode( Parent, Node2, Node1 ); 00356 00357 /* Swap Node 2 and the dummy, thus placing Node 2 back into the tree. */ 00358 if( NULL != dummy_p->Link[ubi_trPARENT] ) 00359 Parent = &((dummy_p->Link[ubi_trPARENT])->Link[(int)(dummy_p->gender)]); 00360 else 00361 Parent = &(RootPtr->root); 00362 ReplaceNode( Parent, dummy_p, Node2 ); 00363 } /* SwapNodes */ 00364 00365 /* -------------------------------------------------------------------------- ** 00366 * These routines allow you to walk through the tree, forwards or backwards. 00367 */ 00368 00369 static ubi_btNodePtr SubSlide( register ubi_btNodePtr P, 00370 register int whichway ) 00371 /* ------------------------------------------------------------------------ ** 00372 * Slide down the side of a subtree. 00373 * 00374 * Given a starting node, this function returns a pointer to the LEFT-, or 00375 * RIGHT-most descendent, *or* (if whichway is PARENT) to the tree root. 00376 * 00377 * Input: P - a pointer to a starting place. 00378 * whichway - the direction (LEFT, RIGHT, or PARENT) in which to 00379 * travel. 00380 * Output: A pointer to a node that is either the root, or has no 00381 * whichway-th child but is within the subtree of P. Note that 00382 * the return value may be the same as P. The return value *will 00383 * be* NULL if P is NULL. 00384 * ------------------------------------------------------------------------ ** 00385 */ 00386 { 00387 00388 if( NULL != P ) 00389 while( NULL != P->Link[ whichway ] ) 00390 P = P->Link[ whichway ]; 00391 return( P ); 00392 } /* SubSlide */ 00393 00394 static ubi_btNodePtr Neighbor( register ubi_btNodePtr P, 00395 register int whichway ) 00396 /* ------------------------------------------------------------------------ ** 00397 * Given starting point p, return the (key order) next or preceeding node 00398 * in the tree. 00399 * 00400 * Input: P - Pointer to our starting place node. 00401 * whichway - the direction in which to travel to find the 00402 * neighbor, i.e., the RIGHT neighbor or the LEFT 00403 * neighbor. 00404 * 00405 * Output: A pointer to the neighboring node, or NULL if P was NULL. 00406 * 00407 * Notes: If whichway is PARENT, the results are unpredictable. 00408 * ------------------------------------------------------------------------ ** 00409 */ 00410 { 00411 if( P ) 00412 { 00413 if( NULL != P->Link[ whichway ] ) 00414 return( SubSlide( P->Link[ whichway ], (char)ubi_trRevWay(whichway) ) ); 00415 else 00416 while( NULL != P->Link[ ubi_trPARENT ] ) 00417 { 00418 if( whichway == P->gender ) 00419 P = P->Link[ ubi_trPARENT ]; 00420 else 00421 return( P->Link[ ubi_trPARENT ] ); 00422 } 00423 } 00424 return( NULL ); 00425 } /* Neighbor */ 00426 00427 static ubi_btNodePtr Border( ubi_btRootPtr RootPtr, 00428 ubi_btItemPtr FindMe, 00429 ubi_btNodePtr p, 00430 int whichway ) 00431 /* ------------------------------------------------------------------------ ** 00432 * Given starting point p, which has a key value equal to *FindMe, locate 00433 * the first (index order) node with the same key value. 00434 * 00435 * This function is useful in trees that have can have duplicate keys. 00436 * For example, consider the following tree: 00437 * Tree Traversal 00438 * 2 If <p> points to the root and <whichway> is RIGHT, 3 00439 * / \ then the return value will be a pointer to the / \ 00440 * 2 2 RIGHT child of the root node. The tree on 2 5 00441 * / / \ the right shows the order of traversal. / / \ 00442 * 1 2 3 1 4 6 00443 * 00444 * Input: RootPtr - Pointer to the tree root structure. 00445 * FindMe - Key value for comparisons. 00446 * p - Pointer to the starting-point node. 00447 * whichway - the direction in which to travel to find the 00448 * neighbor, i.e., the RIGHT neighbor or the LEFT 00449 * neighbor. 00450 * 00451 * Output: A pointer to the first (index, or "traversal", order) node with 00452 * a Key value that matches *FindMe. 00453 * 00454 * Notes: If whichway is PARENT, or if the tree does not allow duplicate 00455 * keys, this function will return <p>. 00456 * ------------------------------------------------------------------------ ** 00457 */ 00458 { 00459 register ubi_btNodePtr q; 00460 00461 /* Exit if there's nothing that can be done. */ 00462 if( !ubi_trDups_OK( RootPtr ) || (ubi_trPARENT == whichway) ) 00463 return( p ); 00464 00465 /* First, if needed, move up the tree. We need to get to the root of the 00466 * subtree that contains all of the matching nodes. 00467 */ 00468 q = p->Link[ubi_trPARENT]; 00469 while( (NULL != q) 00470 && (ubi_trEQUAL == ubi_trAbNormal( (*(RootPtr->cmp))(FindMe, q) )) ) 00471 { 00472 p = q; 00473 q = p->Link[ubi_trPARENT]; 00474 } 00475 00476 /* Next, move back down in the "whichway" direction. */ 00477 q = p->Link[whichway]; 00478 while( NULL != q ) 00479 { 00480 q = qFind( RootPtr->cmp, FindMe, q ); 00481 if( q ) 00482 { 00483 p = q; 00484 q = p->Link[whichway]; 00485 } 00486 } 00487 return( p ); 00488 } /* Border */ 00489 00490 00491 /* ========================================================================== ** 00492 * Exported utilities. 00493 */ 00494 00495 long ubi_btSgn( register long x ) 00496 /* ------------------------------------------------------------------------ ** 00497 * Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}. 00498 * 00499 * Input: x - a signed long integer value. 00500 * 00501 * Output: the "sign" of x, represented as follows: 00502 * -1 == negative 00503 * 0 == zero (no sign) 00504 * 1 == positive 00505 * 00506 * Note: This utility is provided in order to facilitate the conversion 00507 * of C comparison function return values into BinTree direction 00508 * values: {LEFT, PARENT, EQUAL}. It is INCORPORATED into the 00509 * ubi_trAbNormal() conversion macro! 00510 * 00511 * ------------------------------------------------------------------------ ** 00512 */ 00513 { 00514 return( (x)?((x>0)?(1):(-1)):(0) ); 00515 } /* ubi_btSgn */ 00516 00517 ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr LocalNodePtr ) 00518 /* ------------------------------------------------------------------------ ** 00519 * Initialize a tree node. 00520 * 00521 * Input: a pointer to a ubi_btNode structure to be initialized. 00522 * Output: a pointer to the initialized ubi_btNode structure (ie. the 00523 * same as the input pointer). 00524 * ------------------------------------------------------------------------ ** 00525 */ 00526 { 00527 LocalNodePtr->Link[ ubi_trLEFT ] = NULL; 00528 LocalNodePtr->Link[ ubi_trPARENT ] = NULL; 00529 LocalNodePtr->Link[ ubi_trRIGHT ] = NULL; 00530 LocalNodePtr->gender = ubi_trEQUAL; 00531 LocalNodePtr->balance = ubi_trEQUAL; 00532 return( LocalNodePtr ); 00533 } /* ubi_btInitNode */ 00534 00535 ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr RootPtr, 00536 ubi_btCompFunc CompFunc, 00537 char Flags ) 00538 /* ------------------------------------------------------------------------ ** 00539 * Initialize the fields of a Tree Root header structure. 00540 * 00541 * Input: RootPtr - a pointer to an ubi_btRoot structure to be 00542 * initialized. 00543 * CompFunc - a pointer to a comparison function that will be used 00544 * whenever nodes in the tree must be compared against 00545 * outside values. 00546 * Flags - One bytes worth of flags. Flags include 00547 * ubi_trOVERWRITE and ubi_trDUPKEY. See the header 00548 * file for more info. 00549 * 00550 * Output: a pointer to the initialized ubi_btRoot structure (ie. the 00551 * same value as RootPtr). 00552 * 00553 * Note: The interface to this function has changed from that of 00554 * previous versions. The <Flags> parameter replaces two 00555 * boolean parameters that had the same basic effect. 00556 * 00557 * ------------------------------------------------------------------------ ** 00558 */ 00559 { 00560 if( RootPtr ) 00561 { 00562 RootPtr->root = NULL; 00563 RootPtr->count = 0L; 00564 RootPtr->cmp = CompFunc; 00565 RootPtr->flags = (Flags & ubi_trDUPKEY) ? ubi_trDUPKEY : Flags; 00566 } /* There are only two supported flags, and they are 00567 * mutually exclusive. ubi_trDUPKEY takes precedence 00568 * over ubi_trOVERWRITE. 00569 */ 00570 return( RootPtr ); 00571 } /* ubi_btInitTree */ 00572 00573 ubi_trBool ubi_btInsert( ubi_btRootPtr RootPtr, 00574 ubi_btNodePtr NewNode, 00575 ubi_btItemPtr ItemPtr, 00576 ubi_btNodePtr *OldNode ) 00577 /* ------------------------------------------------------------------------ ** 00578 * This function uses a non-recursive algorithm to add a new element to the 00579 * tree. 00580 * 00581 * Input: RootPtr - a pointer to the ubi_btRoot structure that indicates 00582 * the root of the tree to which NewNode is to be added. 00583 * NewNode - a pointer to an ubi_btNode structure that is NOT 00584 * part of any tree. 00585 * ItemPtr - A pointer to the sort key that is stored within 00586 * *NewNode. ItemPtr MUST point to information stored 00587 * in *NewNode or an EXACT DUPLICATE. The key data 00588 * indicated by ItemPtr is used to place the new node 00589 * into the tree. 00590 * OldNode - a pointer to an ubi_btNodePtr. When searching 00591 * the tree, a duplicate node may be found. If 00592 * duplicates are allowed, then the new node will 00593 * be simply placed into the tree. If duplicates 00594 * are not allowed, however, then one of two things 00595 * may happen. 00596 * 1) if overwritting *is not* allowed, this 00597 * function will return FALSE (indicating that 00598 * the new node could not be inserted), and 00599 * *OldNode will point to the duplicate that is 00600 * still in the tree. 00601 * 2) if overwritting *is* allowed, then this 00602 * function will swap **OldNode for *NewNode. 00603 * In this case, *OldNode will point to the node 00604 * that was removed (thus allowing you to free 00605 * the node). 00606 * ** If you are using overwrite mode, ALWAYS ** 00607 * ** check the return value of this parameter! ** 00608 * Note: You may pass NULL in this parameter, the 00609 * function knows how to cope. If you do this, 00610 * however, there will be no way to return a 00611 * pointer to an old (ie. replaced) node (which is 00612 * a problem if you are using overwrite mode). 00613 * 00614 * Output: a boolean value indicating success or failure. The function 00615 * will return FALSE if the node could not be added to the tree. 00616 * Such failure will only occur if duplicates are not allowed, 00617 * nodes cannot be overwritten, AND a duplicate key was found 00618 * within the tree. 00619 * ------------------------------------------------------------------------ ** 00620 */ 00621 { 00622 ubi_btNodePtr OtherP, 00623 parent = NULL; 00624 char tmp; 00625 00626 if( NULL == OldNode ) /* If they didn't give us a pointer, supply our own. */ 00627 OldNode = &OtherP; 00628 00629 (void)ubi_btInitNode( NewNode ); /* Init the new node's BinTree fields. */ 00630 00631 /* Find a place for the new node. */ 00632 *OldNode = TreeFind(ItemPtr, (RootPtr->root), &parent, &tmp, (RootPtr->cmp)); 00633 00634 /* Now add the node to the tree... */ 00635 if( NULL == (*OldNode) ) /* The easy one: we have a space for a new node! */ 00636 { 00637 if( NULL == parent ) 00638 RootPtr->root = NewNode; 00639 else 00640 { 00641 parent->Link[(int)tmp] = NewNode; 00642 NewNode->Link[ubi_trPARENT] = parent; 00643 NewNode->gender = tmp; 00644 } 00645 (RootPtr->count)++; 00646 return( ubi_trTRUE ); 00647 } 00648 00649 /* If we reach this point, we know that a duplicate node exists. This 00650 * section adds the node to the tree if duplicate keys are allowed. 00651 */ 00652 if( ubi_trDups_OK(RootPtr) ) /* Key exists, add duplicate */ 00653 { 00654 ubi_btNodePtr q; 00655 00656 tmp = ubi_trRIGHT; 00657 q = (*OldNode); 00658 *OldNode = NULL; 00659 while( NULL != q ) 00660 { 00661 parent = q; 00662 if( tmp == ubi_trEQUAL ) 00663 tmp = ubi_trRIGHT; 00664 q = q->Link[(int)tmp]; 00665 if ( q ) 00666 tmp = ubi_trAbNormal( (*(RootPtr->cmp))(ItemPtr, q) ); 00667 } 00668 parent->Link[(int)tmp] = NewNode; 00669 NewNode->Link[ubi_trPARENT] = parent; 00670 NewNode->gender = tmp; 00671 (RootPtr->count)++; 00672 return( ubi_trTRUE ); 00673 } 00674 00675 /* If we get to *this* point, we know that we are not allowed to have 00676 * duplicate nodes, but our node keys match, so... may we replace the 00677 * old one? 00678 */ 00679 if( ubi_trOvwt_OK(RootPtr) ) /* Key exists, we replace */ 00680 { 00681 if( NULL == parent ) 00682 ReplaceNode( &(RootPtr->root), *OldNode, NewNode ); 00683 else 00684 ReplaceNode( &(parent->Link[(int)((*OldNode)->gender)]), 00685 *OldNode, NewNode ); 00686 return( ubi_trTRUE ); 00687 } 00688 00689 return( ubi_trFALSE ); /* Failure: could not replace an existing node. */ 00690 } /* ubi_btInsert */ 00691 00692 ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr, 00693 ubi_btNodePtr DeadNode ) 00694 /* ------------------------------------------------------------------------ ** 00695 * This function removes the indicated node from the tree. 00696 * 00697 * Input: RootPtr - A pointer to the header of the tree that contains 00698 * the node to be removed. 00699 * DeadNode - A pointer to the node that will be removed. 00700 * 00701 * Output: This function returns a pointer to the node that was removed 00702 * from the tree (ie. the same as DeadNode). 00703 * 00704 * Note: The node MUST be in the tree indicated by RootPtr. If not, 00705 * strange and evil things will happen to your trees. 00706 * ------------------------------------------------------------------------ ** 00707 */ 00708 { 00709 ubi_btNodePtr p, 00710 *parentp; 00711 int tmp; 00712 00713 /* if the node has both left and right subtrees, then we have to swap 00714 * it with another node. The other node we choose will be the Prev()ious 00715 * node, which is garunteed to have no RIGHT child. 00716 */ 00717 if( (NULL != DeadNode->Link[ubi_trLEFT]) 00718 && (NULL != DeadNode->Link[ubi_trRIGHT]) ) 00719 SwapNodes( RootPtr, DeadNode, ubi_btPrev( DeadNode ) ); 00720 00721 /* The parent of the node to be deleted may be another node, or it may be 00722 * the root of the tree. Since we're not sure, it's best just to have 00723 * a pointer to the parent pointer, whatever it is. 00724 */ 00725 if( NULL == DeadNode->Link[ubi_trPARENT] ) 00726 parentp = &( RootPtr->root ); 00727 else 00728 parentp = &((DeadNode->Link[ubi_trPARENT])->Link[(int)(DeadNode->gender)]); 00729 00730 /* Now link the parent to the only grand-child and patch up the gender. */ 00731 tmp = ((DeadNode->Link[ubi_trLEFT])?ubi_trLEFT:ubi_trRIGHT); 00732 00733 p = (DeadNode->Link[tmp]); 00734 if( NULL != p ) 00735 { 00736 p->Link[ubi_trPARENT] = DeadNode->Link[ubi_trPARENT]; 00737 p->gender = DeadNode->gender; 00738 } 00739 (*parentp) = p; 00740 00741 /* Finished, reduce the node count and return. */ 00742 (RootPtr->count)--; 00743 return( DeadNode ); 00744 } /* ubi_btRemove */ 00745 00746 ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr, 00747 ubi_btItemPtr FindMe, 00748 ubi_trCompOps CompOp ) 00749 /* ------------------------------------------------------------------------ ** 00750 * The purpose of ubi_btLocate() is to find a node or set of nodes given 00751 * a target value and a "comparison operator". The Locate() function is 00752 * more flexible and (in the case of trees that may contain dupicate keys) 00753 * more precise than the ubi_btFind() function. The latter is faster, 00754 * but it only searches for exact matches and, if the tree contains 00755 * duplicates, Find() may return a pointer to any one of the duplicate- 00756 * keyed records. 00757 * 00758 * Input: 00759 * RootPtr - A pointer to the header of the tree to be searched. 00760 * FindMe - An ubi_btItemPtr that indicates the key for which to 00761 * search. 00762 * CompOp - One of the following: 00763 * CompOp Return a pointer to the node with 00764 * ------ --------------------------------- 00765 * ubi_trLT - the last key value that is less 00766 * than FindMe. 00767 * ubi_trLE - the first key matching FindMe, or 00768 * the last key that is less than 00769 * FindMe. 00770 * ubi_trEQ - the first key matching FindMe. 00771 * ubi_trGE - the first key matching FindMe, or the 00772 * first key greater than FindMe. 00773 * ubi_trGT - the first key greater than FindMe. 00774 * Output: 00775 * A pointer to the node matching the criteria listed above under 00776 * CompOp, or NULL if no node matched the criteria. 00777 * 00778 * Notes: 00779 * In the case of trees with duplicate keys, Locate() will behave as 00780 * follows: 00781 * 00782 * Find: 3 Find: 3 00783 * Keys: 1 2 2 2 3 3 3 3 3 4 4 Keys: 1 1 2 2 2 4 4 5 5 5 6 00784 * ^ ^ ^ ^ ^ 00785 * LT EQ GT LE GE 00786 * 00787 * That is, when returning a pointer to a node with a key that is LESS 00788 * THAN the target key (FindMe), Locate() will return a pointer to the 00789 * LAST matching node. 00790 * When returning a pointer to a node with a key that is GREATER 00791 * THAN the target key (FindMe), Locate() will return a pointer to the 00792 * FIRST matching node. 00793 * 00794 * See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf(). 00795 * ------------------------------------------------------------------------ ** 00796 */ 00797 { 00798 register ubi_btNodePtr p; 00799 ubi_btNodePtr parent; 00800 char whichkid; 00801 00802 /* Start by searching for a matching node. */ 00803 p = TreeFind( FindMe, 00804 RootPtr->root, 00805 &parent, 00806 &whichkid, 00807 RootPtr->cmp ); 00808 00809 if( NULL != p ) /* If we have found a match, we can resolve as follows: */ 00810 { 00811 switch( CompOp ) 00812 { 00813 case ubi_trLT: /* It's just a jump to the left... */ 00814 p = Border( RootPtr, FindMe, p, ubi_trLEFT ); 00815 return( Neighbor( p, ubi_trLEFT ) ); 00816 case ubi_trGT: /* ...and then a jump to the right. */ 00817 p = Border( RootPtr, FindMe, p, ubi_trRIGHT ); 00818 return( Neighbor( p, ubi_trRIGHT ) ); 00819 default: 00820 p = Border( RootPtr, FindMe, p, ubi_trLEFT ); 00821 return( p ); 00822 } 00823 } 00824 00825 /* Else, no match. */ 00826 if( ubi_trEQ == CompOp ) /* If we were looking for an exact match... */ 00827 return( NULL ); /* ...forget it. */ 00828 00829 /* We can still return a valid result for GT, GE, LE, and LT. 00830 * <parent> points to a node with a value that is either just before or 00831 * just after the target value. 00832 * Remaining possibilities are LT and GT (including LE & GE). 00833 */ 00834 if( (ubi_trLT == CompOp) || (ubi_trLE == CompOp) ) 00835 return( (ubi_trLEFT == whichkid) ? Neighbor( parent, whichkid ) : parent ); 00836 else 00837 return( (ubi_trRIGHT == whichkid) ? Neighbor( parent, whichkid ) : parent ); 00838 } /* ubi_btLocate */ 00839 00840 ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr, 00841 ubi_btItemPtr FindMe ) 00842 /* ------------------------------------------------------------------------ ** 00843 * This function performs a non-recursive search of a tree for any node 00844 * matching a specific key. 00845 * 00846 * Input: 00847 * RootPtr - a pointer to the header of the tree to be searched. 00848 * FindMe - a pointer to the key value for which to search. 00849 * 00850 * Output: 00851 * A pointer to a node with a key that matches the key indicated by 00852 * FindMe, or NULL if no such node was found. 00853 * 00854 * Note: In a tree that allows duplicates, the pointer returned *might 00855 * not* point to the (sequentially) first occurance of the 00856 * desired key. In such a tree, it may be more useful to use 00857 * ubi_btLocate(). 00858 * ------------------------------------------------------------------------ ** 00859 */ 00860 { 00861 return( qFind( RootPtr->cmp, FindMe, RootPtr->root ) ); 00862 } /* ubi_btFind */ 00863 00864 ubi_btNodePtr ubi_btNext( ubi_btNodePtr P ) 00865 /* ------------------------------------------------------------------------ ** 00866 * Given the node indicated by P, find the (sorted order) Next node in the 00867 * tree. 00868 * Input: P - a pointer to a node that exists in a binary tree. 00869 * Output: A pointer to the "next" node in the tree, or NULL if P pointed 00870 * to the "last" node in the tree or was NULL. 00871 * ------------------------------------------------------------------------ ** 00872 */ 00873 { 00874 return( Neighbor( P, ubi_trRIGHT ) ); 00875 } /* ubi_btNext */ 00876 00877 ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P ) 00878 /* ------------------------------------------------------------------------ ** 00879 * Given the node indicated by P, find the (sorted order) Previous node in 00880 * the tree. 00881 * Input: P - a pointer to a node that exists in a binary tree. 00882 * Output: A pointer to the "previous" node in the tree, or NULL if P 00883 * pointed to the "first" node in the tree or was NULL. 00884 * ------------------------------------------------------------------------ ** 00885 */ 00886 { 00887 return( Neighbor( P, ubi_trLEFT ) ); 00888 } /* ubi_btPrev */ 00889 00890 ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P ) 00891 /* ------------------------------------------------------------------------ ** 00892 * Given the node indicated by P, find the (sorted order) First node in the 00893 * subtree of which *P is the root. 00894 * Input: P - a pointer to a node that exists in a binary tree. 00895 * Output: A pointer to the "first" node in a subtree that has *P as its 00896 * root. This function will return NULL only if P is NULL. 00897 * Note: In general, you will be passing in the value of the root field 00898 * of an ubi_btRoot structure. 00899 * ------------------------------------------------------------------------ ** 00900 */ 00901 { 00902 return( SubSlide( P, ubi_trLEFT ) ); 00903 } /* ubi_btFirst */ 00904 00905 ubi_btNodePtr ubi_btLast( ubi_btNodePtr P ) 00906 /* ------------------------------------------------------------------------ ** 00907 * Given the node indicated by P, find the (sorted order) Last node in the 00908 * subtree of which *P is the root. 00909 * Input: P - a pointer to a node that exists in a binary tree. 00910 * Output: A pointer to the "last" node in a subtree that has *P as its 00911 * root. This function will return NULL only if P is NULL. 00912 * Note: In general, you will be passing in the value of the root field 00913 * of an ubi_btRoot structure. 00914 * ------------------------------------------------------------------------ ** 00915 */ 00916 { 00917 return( SubSlide( P, ubi_trRIGHT ) ); 00918 } /* ubi_btLast */ 00919 00920 ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr, 00921 ubi_btItemPtr MatchMe, 00922 ubi_btNodePtr p ) 00923 /* ------------------------------------------------------------------------ ** 00924 * Given a tree that a allows duplicate keys, and a pointer to a node in 00925 * the tree, this function will return a pointer to the first (traversal 00926 * order) node with the same key value. 00927 * 00928 * Input: RootPtr - A pointer to the root of the tree. 00929 * MatchMe - A pointer to the key value. This should probably 00930 * point to the key within node *p. 00931 * p - A pointer to a node in the tree. 00932 * Output: A pointer to the first node in the set of nodes with keys 00933 * matching <FindMe>. 00934 * Notes: Node *p MUST be in the set of nodes with keys matching 00935 * <FindMe>. If not, this function will return NULL. 00936 * 00937 * 4.7: Bug found & fixed by Massimo Campostrini, 00938 * Istituto Nazionale di Fisica Nucleare, Sezione di Pisa. 00939 * 00940 * ------------------------------------------------------------------------ ** 00941 */ 00942 { 00943 /* If our starting point is invalid, return NULL. */ 00944 if( (NULL == p) 00945 || (ubi_trEQUAL != ubi_trAbNormal( (*(RootPtr->cmp))( MatchMe, p ) )) ) 00946 return( NULL ); 00947 return( Border( RootPtr, MatchMe, p, ubi_trLEFT ) ); 00948 } /* ubi_btFirstOf */ 00949 00950 ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr, 00951 ubi_btItemPtr MatchMe, 00952 ubi_btNodePtr p ) 00953 /* ------------------------------------------------------------------------ ** 00954 * Given a tree that a allows duplicate keys, and a pointer to a node in 00955 * the tree, this function will return a pointer to the last (traversal 00956 * order) node with the same key value. 00957 * 00958 * Input: RootPtr - A pointer to the root of the tree. 00959 * MatchMe - A pointer to the key value. This should probably 00960 * point to the key within node *p. 00961 * p - A pointer to a node in the tree. 00962 * Output: A pointer to the last node in the set of nodes with keys 00963 * matching <FindMe>. 00964 * Notes: Node *p MUST be in the set of nodes with keys matching 00965 * <FindMe>. If not, this function will return NULL. 00966 * 00967 * 4.7: Bug found & fixed by Massimo Campostrini, 00968 * Istituto Nazionale di Fisica Nucleare, Sezione di Pisa. 00969 * 00970 * ------------------------------------------------------------------------ ** 00971 */ 00972 { 00973 /* If our starting point is invalid, return NULL. */ 00974 if( (NULL != p) 00975 || (ubi_trEQUAL != ubi_trAbNormal( (*(RootPtr->cmp))( MatchMe, p ) )) ) 00976 return( NULL ); 00977 return( Border( RootPtr, MatchMe, p, ubi_trRIGHT ) ); 00978 } /* ubi_btLastOf */ 00979 00980 unsigned long ubi_btTraverse( ubi_btRootPtr RootPtr, 00981 ubi_btActionRtn EachNode, 00982 void *UserData ) 00983 /* ------------------------------------------------------------------------ ** 00984 * Traverse a tree in sorted order (non-recursively). At each node, call 00985 * (*EachNode)(), passing a pointer to the current node, and UserData as the 00986 * second parameter. 00987 * 00988 * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates 00989 * the tree to be traversed. 00990 * EachNode - a pointer to a function to be called at each node 00991 * as the node is visited. 00992 * UserData - a generic pointer that may point to anything that 00993 * you choose. 00994 * 00995 * Output: A count of the number of nodes visited. This will be zero 00996 * if the tree is empty. 00997 * 00998 * ------------------------------------------------------------------------ ** 00999 */ 01000 { 01001 ubi_btNodePtr p = ubi_btFirst( RootPtr->root ); 01002 unsigned long count = 0; 01003 01004 while( NULL != p ) 01005 { 01006 (*EachNode)( p, UserData ); 01007 count++; 01008 p = ubi_btNext( p ); 01009 } 01010 return( count ); 01011 } /* ubi_btTraverse */ 01012 01013 unsigned long ubi_btKillTree( ubi_btRootPtr RootPtr, 01014 ubi_btKillNodeRtn FreeNode ) 01015 /* ------------------------------------------------------------------------ ** 01016 * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot 01017 * structure. Return a count of the number of nodes deleted. 01018 * 01019 * Input: RootPtr - a pointer to an ubi_btRoot structure that indicates 01020 * the root of the tree to delete. 01021 * FreeNode - a function that will be called for each node in the 01022 * tree to deallocate the memory used by the node. 01023 * 01024 * Output: The number of nodes removed from the tree. 01025 * A value of 0 will be returned if: 01026 * - The tree actually contains 0 entries. 01027 * - the value of <RootPtr> is NULL, in which case the tree is 01028 * assumed to be empty 01029 * - the value of <FreeNode> is NULL, in which case entries 01030 * cannot be removed, so 0 is returned. *Make sure that you 01031 * provide a valid value for <FreeNode>*. 01032 * In all other cases, you should get a positive value equal to 01033 * the value of RootPtr->count upon entry. 01034 * 01035 * ------------------------------------------------------------------------ ** 01036 */ 01037 { 01038 ubi_btNodePtr p, q; 01039 unsigned long count = 0; 01040 01041 if( (NULL == RootPtr) || (NULL == FreeNode) ) 01042 return( 0 ); 01043 01044 p = ubi_btFirst( RootPtr->root ); 01045 while( NULL != p ) 01046 { 01047 q = p; 01048 while( q->Link[ubi_trRIGHT] ) 01049 q = SubSlide( q->Link[ubi_trRIGHT], ubi_trLEFT ); 01050 p = q->Link[ubi_trPARENT]; 01051 if( NULL != p ) 01052 p->Link[ ((p->Link[ubi_trLEFT] == q)?ubi_trLEFT:ubi_trRIGHT) ] = NULL; 01053 (*FreeNode)((void *)q); 01054 count++; 01055 } 01056 01057 /* overkill... */ 01058 (void)ubi_btInitTree( RootPtr, 01059 RootPtr->cmp, 01060 RootPtr->flags ); 01061 return( count ); 01062 } /* ubi_btKillTree */ 01063 01064 ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader ) 01065 /* ------------------------------------------------------------------------ ** 01066 * Returns a pointer to a leaf node. 01067 * 01068 * Input: leader - Pointer to a node at which to start the descent. 01069 * 01070 * Output: A pointer to a leaf node selected in a somewhat arbitrary 01071 * manner. 01072 * 01073 * Notes: I wrote this function because I was using splay trees as a 01074 * database cache. The cache had a maximum size on it, and I 01075 * needed a way of choosing a node to sacrifice if the cache 01076 * became full. In a splay tree, less recently accessed nodes 01077 * tend toward the bottom of the tree, meaning that leaf nodes 01078 * are good candidates for removal. (I really can't think of 01079 * any other reason to use this function.) 01080 * + In a simple binary tree or an AVL tree, the most recently 01081 * added nodes tend to be nearer the bottom, making this a *bad* 01082 * way to choose which node to remove from the cache. 01083 * + Randomizing the traversal order is probably a good idea. You 01084 * can improve the randomization of leaf node selection by passing 01085 * in pointers to nodes other than the root node each time. A 01086 * pointer to any node in the tree will do. Of course, if you 01087 * pass a pointer to a leaf node you'll get the same thing back. 01088 * 01089 * ------------------------------------------------------------------------ ** 01090 */ 01091 { 01092 ubi_btNodePtr follower = NULL; 01093 int whichway = ubi_trLEFT; 01094 01095 while( NULL != leader ) 01096 { 01097 follower = leader; 01098 leader = follower->Link[ whichway ]; 01099 if( NULL == leader ) 01100 { 01101 whichway = ubi_trRevWay( whichway ); 01102 leader = follower->Link[ whichway ]; 01103 } 01104 } 01105 01106 return( follower ); 01107 } /* ubi_btLeafNode */ 01108 01109 int ubi_btModuleID( int size, char *list[] ) 01110 /* ------------------------------------------------------------------------ ** 01111 * Returns a set of strings that identify the module. 01112 * 01113 * Input: size - The number of elements in the array <list>. 01114 * list - An array of pointers of type (char *). This array 01115 * should, initially, be empty. This function will fill 01116 * in the array with pointers to strings. 01117 * Output: The number of elements of <list> that were used. If this value 01118 * is less than <size>, the values of the remaining elements are 01119 * not guaranteed. 01120 * 01121 * Notes: Please keep in mind that the pointers returned indicate strings 01122 * stored in static memory. Don't free() them, don't write over 01123 * them, etc. Just read them. 01124 * ------------------------------------------------------------------------ ** 01125 */ 01126 { 01127 if( size > 0 ) 01128 { 01129 list[0] = ModuleID; 01130 if( size > 1 ) 01131 list[1] = NULL; 01132 return( 1 ); 01133 } 01134 return( 0 ); 01135 } /* ubi_btModuleID */ 01136 01137 01138 /* ========================================================================== */