This is my library of lists and trees. My hope is to replace all of the
authorChristopher R. Hertel <crh@samba.org>
Thu, 9 Oct 1997 04:09:56 +0000 (04:09 +0000)
committerChristopher R. Hertel <crh@samba.org>
Thu, 9 Oct 1997 04:09:56 +0000 (04:09 +0000)
hard coded linked lists that are currently used in Samba with calls to
these modules.  This should make the code simpler, smaller, and (I hope)
faster.  The tree code, in particular, should speed up processing where
large lists are involved.

Chris -)-----

source/ubi_AVLtree.c [new file with mode: 0644]
source/ubi_AVLtree.h [new file with mode: 0644]
source/ubi_BinTree.c [new file with mode: 0644]
source/ubi_BinTree.h [new file with mode: 0644]
source/ubi_SplayTree.c [new file with mode: 0644]
source/ubi_SplayTree.h [new file with mode: 0644]
source/ubi_dLinkList.c [new file with mode: 0644]
source/ubi_dLinkList.h [new file with mode: 0644]

diff --git a/source/ubi_AVLtree.c b/source/ubi_AVLtree.c
new file mode 100644 (file)
index 0000000..730392a
--- /dev/null
@@ -0,0 +1,699 @@
+/* ========================================================================== **
+ *                              ubi_AVLtree.c
+ *
+ *  Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ *  This module provides an implementation of AVL height balanced binary
+ *  trees.  (Adelson-Velskii, Landis 1962)
+ *
+ *  This file implements the core of the height-balanced (AVL) tree management
+ *  routines.  The header file, ubi_AVLtree.h, contains function prototypes
+ *  for all "exported" functions.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * $Log: ubi_AVLtree.c,v $
+ * Revision 1.1  1997/10/09 04:09:51  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 2.4  1997/07/26 04:36:20  crh
+ * Andrew Leppard, aka "Grazgur", discovered that I still had my brains tied
+ * on backwards with respect to node deletion.  I did some more digging and
+ * discovered that I was not changing the balance values correctly in the
+ * single rotation functions.  Double rotation was working correctly because
+ * the formula for changing the balance values is the same for insertion or
+ * deletion.  Not so for single rotation.
+ *
+ * I have tested the fix by loading the tree with over 44 thousand names,
+ * deleting 2,629 of them (all those in which the second character is 'u')
+ * and then walking the tree recursively to verify that the balance factor of
+ * each node is correct.  Passed.
+ *
+ * Thanks Andrew!
+ *
+ * Also:
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ * + Rewrote the ubi_tr<func> macros because they weren't doing what I'd
+ *   hoped they would do (see the bottom of the header file).  They work now.
+ *
+ * Revision 2.3  1997/06/03 04:41:35  crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.2  1995/10/03 22:16:01  CRH
+ * Ubisized!
+ *
+ * Revision 2.1  95/03/09  23:45:59  CRH
+ * Added the ModuleID static string and function.  These modules are now
+ * self-identifying.
+ * 
+ * Revision 2.0  95/03/05  14:10:51  CRH
+ * This revision of ubi_AVLtree coincides with revision 2.0 of ubi_BinTree,
+ * and so includes all of the changes to that module.  In addition, a bug in
+ * the node deletion process has been fixed.
+ *
+ * After rewriting the Locate() function in ubi_BinTree, I decided that it was
+ * time to overhaul this module.  In the process, I discovered a bug related
+ * to node deletion.  To fix the bug, I wrote function Debalance().  A quick
+ * glance will show that it is very similar to the Rebalance() function.  In
+ * previous versions of this module, I tried to include the functionality of
+ * Debalance() within Rebalance(), with poor results.
+ *
+ * Revision 1.0  93/10/15  22:58:56  CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules.  Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ *       Module        Prefix
+ *     ubi_BinTree     ubi_bt
+ *     ubi_AVLtree     ubi_avl
+ *     ubi_SplayTree   ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot".  Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use.  If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules.  To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr".  The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using.  Just remember to
+ * include the header for that module in your program file.  Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module.  This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees.  CRH
+ *
+ *  V0.0 - May, 1990   -  Written by Christopher R. Hertel (CRH).
+ *
+ *  ========================================================================= **
+ */
+
+#include "ubi_AVLtree.h"            /* Header for THIS module.             */
+#include <stdlib.h>                 /* Standard C definitions, etc.        */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_AVLtree\n\
+\t$Revision: 1.1 $\n\
+\t$Date: 1997/10/09 04:09:51 $\n\
+\t$Author: crh $\n";
+
+/* ========================================================================== **
+ * The next set of functions are the AVL balancing routines.  There are left
+ * and right, single and double rotations.  The rotation routines handle the
+ * rotations and reconnect all tree pointers that might get confused by the
+ * rotations.  A pointer to the new subtree root node is returned.
+ *
+ * Note that L1 and R1 are identical, except that all the RIGHTs and LEFTs
+ * are reversed.  The same is true for L2 and R2.  I'm sure that there is
+ * a clever way to reduce the amount of code by combining these functions,
+ * but it might involve additional overhead, and it would probably be a pain
+ * to read, debug, etc.
+ * -------------------------------------------------------------------------- **
+ */
+
+static ubi_avlNodePtr L1( ubi_avlNodePtr p )
+  /* ------------------------------------------------------------------------ **
+   * Single rotate left.
+   *
+   *  Input:  p - Pointer to the root of a tree (possibly a subtree).
+   *  Output: A pointer to the new root of the same subtree (now that node
+   *          p has been moved).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_avlNodePtr tmp;
+
+  tmp                = p->Link[RIGHT];
+  p->Link[RIGHT]     = tmp->Link[LEFT];
+  tmp->Link[LEFT]    = p;
+
+  tmp->Link[PARENT]  = p->Link[PARENT];
+  tmp->gender        = p->gender;
+  if(tmp->Link[PARENT])
+    (tmp->Link[PARENT])->Link[(tmp->gender)] = tmp;
+  p->Link[PARENT]    = tmp;
+  p->gender          = LEFT;
+  if( p->Link[RIGHT] )
+    {
+    p->Link[RIGHT]->Link[PARENT] = p;
+    (p->Link[RIGHT])->gender     = RIGHT;
+    }
+  p->balance -= Normalize( tmp->balance );
+  (tmp->balance)--;
+  return( tmp );
+  } /* L1 */
+
+static ubi_avlNodePtr R1( ubi_avlNodePtr p )
+  /* ------------------------------------------------------------------------ **
+   * Single rotate right.
+   *
+   *  Input:  p - Pointer to the root of a tree (possibly a subtree).
+   *  Output: A pointer to the new root of the same subtree (now that node
+   *          p has been moved).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_avlNodePtr tmp;
+
+  tmp                = p->Link[LEFT];
+  p->Link[LEFT]      = tmp->Link[RIGHT];
+  tmp->Link[RIGHT]   = p;
+
+  tmp->Link[PARENT]  = p->Link[PARENT];
+  tmp->gender        = p->gender;
+  if(tmp->Link[PARENT])
+    (tmp->Link[PARENT])->Link[(tmp->gender)] = tmp;
+  p->Link[PARENT]    = tmp;
+  p->gender          = RIGHT;
+  if(p->Link[LEFT])
+    {
+    p->Link[LEFT]->Link[PARENT]  = p;
+    p->Link[LEFT]->gender        = LEFT;
+    }
+  p->balance -= Normalize( tmp->balance );
+  (tmp->balance)++;
+  return( tmp );
+  } /* R1 */
+
+static ubi_avlNodePtr L2( ubi_avlNodePtr tree )
+  /* ------------------------------------------------------------------------ **
+   * Double rotate left.
+   *
+   *  Input:  p - Pointer to the root of a tree (possibly a subtree).
+   *  Output: A pointer to the new root of the same subtree (now that node
+   *          p has been moved).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_avlNodePtr tmp, newroot;
+
+  tmp                   = tree->Link[RIGHT];
+  newroot               = tmp->Link[LEFT];
+  tmp->Link[LEFT]       = newroot->Link[RIGHT];
+  newroot->Link[RIGHT]  = tmp;
+  tree->Link[RIGHT]     = newroot->Link[LEFT];
+  newroot->Link[LEFT]   = tree;
+
+  newroot->Link[PARENT] = tree->Link[PARENT];
+  newroot->gender       = tree->gender;
+  tree->Link[PARENT]    = newroot;
+  tree->gender          = LEFT;
+  tmp->Link[PARENT]     = newroot;
+  tmp->gender           = RIGHT;
+
+  if( tree->Link[RIGHT] )
+    {
+    tree->Link[RIGHT]->Link[PARENT] = tree;
+    tree->Link[RIGHT]->gender       = RIGHT;
+    }
+  if( tmp->Link[LEFT] )
+    {
+    tmp->Link[LEFT]->Link[PARENT]   = tmp;
+    tmp->Link[LEFT]->gender         = LEFT;
+    }
+  if(newroot->Link[PARENT])
+    newroot->Link[PARENT]->Link[newroot->gender] = newroot;
+
+  switch( newroot->balance )
+    {
+    case LEFT :
+      tree->balance = EQUAL; tmp->balance = RIGHT; break;
+    case EQUAL:
+      tree->balance = EQUAL; tmp->balance = EQUAL; break;
+    case RIGHT:
+      tree->balance = LEFT;  tmp->balance = EQUAL; break;
+    }
+  newroot->balance = EQUAL;
+  return( newroot );
+  } /* L2 */
+
+static ubi_avlNodePtr R2( ubi_avlNodePtr tree )
+  /* ------------------------------------------------------------------------ **
+   * Double rotate right.
+   *
+   *  Input:  p - Pointer to the root of a tree (possibly a subtree).
+   *  Output: A pointer to the new root of the same subtree (now that node
+   *          p has been moved).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_avlNodePtr tmp, newroot;
+
+  tmp                   = tree->Link[LEFT];
+  newroot               = tmp->Link[RIGHT];
+  tmp->Link[RIGHT]      = newroot->Link[LEFT];
+  newroot->Link[LEFT]   = tmp;
+  tree->Link[LEFT]      = newroot->Link[RIGHT];
+  newroot->Link[RIGHT]  = tree;
+
+  newroot->Link[PARENT] = tree->Link[PARENT];
+  newroot->gender       = tree->gender;
+  tree->Link[PARENT]    = newroot;
+  tree->gender          = RIGHT;
+  tmp->Link[PARENT]     = newroot;
+  tmp->gender           = LEFT;
+
+  if( tree->Link[LEFT] )
+    {
+    tree->Link[LEFT]->Link[PARENT]  = tree;
+    tree->Link[LEFT]->gender        = LEFT;
+    }
+  if( tmp->Link[RIGHT] )
+    {
+    tmp->Link[RIGHT]->Link[PARENT]  = tmp;
+    tmp->Link[RIGHT]->gender        = RIGHT;
+    }
+  if(newroot->Link[PARENT])
+    newroot->Link[PARENT]->Link[newroot->gender] = newroot;
+
+  switch( newroot->balance )
+    {
+    case LEFT  :
+      tree->balance = RIGHT; tmp->balance = EQUAL; break;
+    case EQUAL :
+      tree->balance = EQUAL; tmp->balance = EQUAL; break;
+    case RIGHT :
+      tree->balance = EQUAL; tmp->balance = LEFT;  break;
+    }
+  newroot->balance = EQUAL;
+  return( newroot );
+  } /* R2 */
+
+
+static ubi_avlNodePtr Adjust( ubi_avlNodePtr p, char LorR )
+  /* ------------------------------------------------------------------------ **
+   * Adjust the balance value at node *p.  If necessary, rotate the subtree
+   * rooted at p.
+   *
+   *  Input:  p    -  A pointer to the node to be adjusted.  One of the
+   *                  subtrees of this node has changed height, so the
+   *                  balance value at this node must be adjusted, possibly
+   *                  by rotating the tree at this node.
+   *          LorR -  Indicates the TALLER subtree.
+   *
+   *  Output: A pointer to the (possibly new) root node of the subtree.
+   *
+   *  Notes:  This function may be called after a node has been added *or*
+   *          deleted, so LorR indicates the TALLER subtree.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( p->balance != LorR )
+    p->balance += Normalize(LorR);
+  else
+    {
+    char tallerbal;  /* Balance value of the root of the taller subtree of p. */
+
+    tallerbal = p->Link[LorR]->balance;
+    if( ( EQUAL == tallerbal ) || ( p->balance == tallerbal ) )
+      p = ( (LEFT==LorR) ? R1(p) : L1(p) );   /* single rotation */
+    else
+      p = ( (LEFT==LorR) ? R2(p) : L2(p) );   /* double rotation */
+    }
+  return( p );
+  } /* Adjust */
+
+static ubi_avlNodePtr Rebalance( ubi_avlNodePtr Root,
+                                 ubi_avlNodePtr subtree,
+                                 char           LorR )
+  /* ------------------------------------------------------------------------ **
+   * Rebalance the tree following an insertion.
+   *
+   *  Input:  Root    - A pointer to the root node of the whole tree.
+   *          subtree - A pointer to the node that has just gained a new
+   *                    child.
+   *          LorR    - Gender of the child that has just been gained.
+   *
+   *  Output: A pointer to the (possibly new) root of the AVL tree.
+   *          Rebalancing the tree moves nodes around a bit, so the node
+   *          that *was* the root, may not be the root when we're finished.
+   *
+   *  Notes:  Rebalance() must walk up the tree from where we are (which is
+   *          where the latest change occurred), rebalancing the subtrees
+   *          along the way.  The rebalancing operation can stop if the
+   *          change at the current subtree root won't affect the rest of
+   *          the tree.  In the case of an addition, if a subtree root's
+   *          balance becomes EQUAL, then we know that the height of that
+   *          subtree has not changed, so we can exit.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  while( subtree )
+    {
+    subtree = Adjust( subtree, LorR );
+    if( PARENT == subtree->gender )
+      return( subtree );
+    if( EQUAL == subtree->balance )
+      return( Root );
+    LorR = subtree->gender;
+    subtree = subtree->Link[PARENT];
+    }
+  return( Root );
+  } /* Rebalance */
+
+static ubi_avlNodePtr Debalance( ubi_avlNodePtr Root,
+                                 ubi_avlNodePtr subtree,
+                                 char           LorR )
+  /* ------------------------------------------------------------------------ **
+   * Rebalance the tree following a deletion.
+   *
+   *  Input:  Root    - A pointer to the root node of the whole tree.
+   *          subtree - A pointer to the node who's child has just "left the
+   *                    nest".
+   *          LorR    - Gender of the child that left.
+   *
+   *  Output: A pointer to the (possibly new) root of the AVL tree.
+   *          Rebalancing the tree moves nodes around a bit, so the node
+   *          that *was* the root, may not be the root when we're finished.
+   *
+   *  Notes:  Debalance() is subtly different from Rebalance() (above) in
+   *          two respects.
+   *            * When it calls Adjust(), it passes the *opposite* of LorR.
+   *              This is because LorR, as passed into Debalance() indicates
+   *              the shorter subtree.  As we move up the tree, LorR is
+   *              assigned the gender of the node that we are leaving (i.e.,
+   *              the subtree that we just rebalanced).
+   *            * We know that a subtree has not changed height if the
+   *              balance becomes LEFT or RIGHT.  This is the *opposite* of
+   *              what happens in Rebalance().
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  while( subtree )
+    {
+    subtree = Adjust( subtree, RevWay(LorR) );
+    if( PARENT == subtree->gender )
+      return( subtree );
+    if( EQUAL != subtree->balance )
+      return( Root );
+    LorR = subtree->gender;
+    subtree = subtree->Link[PARENT];
+    }
+  return( Root );
+  } /* Debalance */
+
+
+/* -------------------------------------------------------------------------- **
+ * The next two functions are used for general tree manipulation.  They are
+ * each slightly different from their ubi_BinTree counterparts.
+ * -------------------------------------------------------------------------- **
+ */
+
+static void ReplaceNode( ubi_avlNodePtr *parent,
+                         ubi_avlNodePtr  oldnode,
+                         ubi_avlNodePtr  newnode )
+  /* ------------------------------------------------------------------------ **
+   * Remove node oldnode from the tree, replacing it with node newnode.
+   *
+   * Input:
+   *  parent   - A pointer to he parent pointer of the node to be
+   *             replaced.  <parent> may point to the Link[] field of
+   *             a parent node, or it may indicate the root pointer at
+   *             the top of the tree.
+   *  oldnode  - A pointer to the node that is to be replaced.
+   *  newnode  - A pointer to the node that is to be installed in the
+   *             place of <*oldnode>.
+   *
+   * Notes:    Don't forget to free oldnode.
+   *           The only difference between this function and the ubi_bt
+   *           version is that the node size is sizeof( ubi_avlNode ), not
+   *           sizeof( ubi_btNode ).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  register int i;
+  register int avlNodeSize = sizeof( ubi_avlNode );
+
+  for( i = 0; i < avlNodeSize; i++ )
+    ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+  (*parent) = newnode;
+
+  if(oldnode->Link[LEFT ] )
+    (oldnode->Link[LEFT ])->Link[PARENT] = newnode;
+  if(oldnode->Link[RIGHT] )
+    (oldnode->Link[RIGHT])->Link[PARENT] = newnode;
+  } /* ReplaceNode */
+
+static void SwapNodes( ubi_btRootPtr  RootPtr,
+                       ubi_avlNodePtr Node1,
+                       ubi_avlNodePtr Node2 )
+  /* ------------------------------------------------------------------------ **
+   * This function swaps two nodes in the tree.  Node1 will take the place of
+   * Node2, and Node2 will fill in the space left vacant by Node 1.
+   *
+   * Input:
+   *  RootPtr  - pointer to the tree header structure for this tree.
+   *  Node1    - \
+   *              > These are the two nodes which are to be swapped.
+   *  Node2    - /
+   *
+   * Notes:
+   *  This function does a three step swap, using a dummy node as a place
+   *  holder.  This function is used by ubi_avlRemove().
+   *  The only difference between this function and its ubi_bt counterpart
+   *  is that the nodes are ubi_avlNodes, not ubi_btNodes.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_avlNodePtr *Parent;
+  ubi_avlNode     dummy;
+  ubi_avlNodePtr  dummy_p = &dummy;
+
+  if( Node1->Link[PARENT] )
+    Parent = &((Node1->Link[PARENT])->Link[Node1->gender]);
+  else
+    Parent = (ubi_avlNodePtr *)&(RootPtr->root);
+  ReplaceNode( Parent, Node1, dummy_p );
+
+  if( Node2->Link[PARENT] )
+    Parent = &((Node2->Link[PARENT])->Link[Node2->gender]);
+  else
+    Parent = (ubi_avlNodePtr *)&(RootPtr->root);
+  ReplaceNode( Parent, Node2, Node1 );
+
+  if( dummy_p->Link[PARENT] )
+    Parent = &((dummy_p->Link[PARENT])->Link[dummy_p->gender]);
+  else
+    Parent = (ubi_avlNodePtr *)&(RootPtr->root);
+  ReplaceNode( Parent, dummy_p, Node2 );
+  } /* SwapNodes */
+
+
+/* ========================================================================== **
+ *         Public, exported (ie. not static-ly declared) functions...
+ * -------------------------------------------------------------------------- **
+ */
+
+ubi_avlNodePtr ubi_avlInitNode( ubi_avlNodePtr NodePtr )
+  /* ------------------------------------------------------------------------ **
+   * Initialize a tree node.
+   *
+   *  Input:   NodePtr  - pointer to a ubi_btNode structure to be
+   *                      initialized.
+   *  Output:  a pointer to the initialized ubi_avlNode structure (ie. the
+   *           same as the input pointer).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  (void)ubi_btInitNode( (ubi_btNodePtr)NodePtr );
+  NodePtr->balance = EQUAL;
+  return( NodePtr );
+  } /* ubi_avlInitNode */
+
+ubi_trBool ubi_avlInsert( ubi_btRootPtr   RootPtr,
+                          ubi_avlNodePtr  NewNode,
+                          ubi_btItemPtr   ItemPtr,
+                          ubi_avlNodePtr *OldNode )
+  /* ------------------------------------------------------------------------ **
+   * This function uses a non-recursive algorithm to add a new element to
+   * the tree.
+   *
+   *  Input:   RootPtr  -  a pointer to the ubi_btRoot structure that indicates
+   *                       the root of the tree to which NewNode is to be added.
+   *           NewNode  -  a pointer to an ubi_avlNode structure that is NOT
+   *                       part of any tree.
+   *           ItemPtr  -  A pointer to the sort key that is stored within
+   *                       *NewNode.  ItemPtr MUST point to information stored
+   *                       in *NewNode or an EXACT DUPLICATE.  The key data
+   *                       indicated by ItemPtr is used to place the new node
+   *                       into the tree.
+   *           OldNode  -  a pointer to an ubi_btNodePtr.  When searching
+   *                       the tree, a duplicate node may be found.  If
+   *                       duplicates are allowed, then the new node will
+   *                       be simply placed into the tree.  If duplicates
+   *                       are not allowed, however, then one of two things
+   *                       may happen.
+   *                       1) if overwritting *is not* allowed, this
+   *                          function will return FALSE (indicating that
+   *                          the new node could not be inserted), and
+   *                          *OldNode will point to the duplicate that is
+   *                          still in the tree.
+   *                       2) if overwritting *is* allowed, then this
+   *                          function will swap **OldNode for *NewNode.
+   *                          In this case, *OldNode will point to the node
+   *                          that was removed (thus allowing you to free
+   *                          the node).
+   *                          **  If you are using overwrite mode, ALWAYS  **
+   *                          ** check the return value of this parameter! **
+   *                 Note: You may pass NULL in this parameter, the
+   *                       function knows how to cope.  If you do this,
+   *                       however, there will be no way to return a
+   *                       pointer to an old (ie. replaced) node (which is
+   *                       a problem if you are using overwrite mode).
+   *
+   *  Output:  a boolean value indicating success or failure.  The function
+   *           will return FALSE if the node could not be added to the tree.
+   *           Such failure will only occur if duplicates are not allowed,
+   *           nodes cannot be overwritten, AND a duplicate key was found
+   *           within the tree.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_avlNodePtr OtherP;
+
+  if( !(OldNode) ) OldNode = &OtherP;
+  if( ubi_btInsert( RootPtr,
+                    (ubi_btNodePtr)NewNode,
+                    ItemPtr,
+                    (ubi_btNodePtr *)OldNode ) )
+    {
+    if( (*OldNode) )
+      NewNode->balance = (*OldNode)->balance;
+    else
+      {
+      NewNode->balance = EQUAL;
+      RootPtr->root = (ubi_btNodePtr)Rebalance( (ubi_avlNodePtr)RootPtr->root,
+                                                NewNode->Link[PARENT],
+                                                NewNode->gender );
+      }
+    return( ubi_trTRUE );
+    }
+  return( ubi_trFALSE );      /* Failure: could not replace an existing node. */
+  } /* ubi_avlInsert */
+
+ubi_avlNodePtr ubi_avlRemove( ubi_btRootPtr  RootPtr,
+                              ubi_avlNodePtr DeadNode )
+  /* ------------------------------------------------------------------------ **
+   * This function removes the indicated node from the tree, after which the
+   * tree is rebalanced.
+   *
+   *  Input:  RootPtr  -  A pointer to the header of the tree that contains
+   *                      the node to be removed.
+   *          DeadNode -  A pointer to the node that will be removed.
+   *
+   *  Output: This function returns a pointer to the node that was removed
+   *          from the tree (ie. the same as DeadNode).
+   *
+   *  Note:   The node MUST be in the tree indicated by RootPtr.  If not,
+   *          strange and evil things will happen to your trees.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr p,
+               *parentp;
+
+  /* if the node has both left and right subtrees, then we have to swap
+   * it with another node.
+   */
+  if( (DeadNode->Link[LEFT]) && (DeadNode->Link[RIGHT]) )
+    SwapNodes( RootPtr, DeadNode, ubi_trPrev( DeadNode ) );
+
+  /* The parent of the node to be deleted may be another node, or it may be
+   * the root of the tree.  Since we're not sure, it's best just to have
+   * a pointer to the parent pointer, whatever it is.
+   */
+  if( DeadNode->Link[PARENT] )
+    parentp = (ubi_btNodePtr *)
+              &((DeadNode->Link[PARENT])->Link[(DeadNode->gender)]);
+  else
+    parentp = &( RootPtr->root );
+
+  /* Now link the parent to the only grand-child.  Patch up the gender and
+   * such, and rebalance.
+   */
+  if( EQUAL == DeadNode->balance )
+    (*parentp) = NULL;
+  else
+    {
+    p = (ubi_btNodePtr)(DeadNode->Link[(DeadNode->balance)]);
+    p->Link[PARENT]  = (ubi_btNodePtr)DeadNode->Link[PARENT];
+    p->gender        = DeadNode->gender;
+    (*parentp) = p;
+    }
+  RootPtr->root = (ubi_btNodePtr)Debalance( (ubi_avlNodePtr)RootPtr->root,
+                                            DeadNode->Link[PARENT],
+                                            DeadNode->gender );
+
+  (RootPtr->count)--;
+  return( DeadNode );
+  } /* ubi_avlRemove */
+
+int ubi_avlModuleID( int size, char *list[] )
+  /* ------------------------------------------------------------------------ **
+   * Returns a set of strings that identify the module.
+   *
+   *  Input:  size  - The number of elements in the array <list>.
+   *          list  - An array of pointers of type (char *).  This array
+   *                  should, initially, be empty.  This function will fill
+   *                  in the array with pointers to strings.
+   *  Output: The number of elements of <list> that were used.  If this value
+   *          is less than <size>, the values of the remaining elements are
+   *          not guaranteed.
+   *
+   *  Notes:  Please keep in mind that the pointers returned indicate strings
+   *          stored in static memory.  Don't free() them, don't write over
+   *          them, etc.  Just read them.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( size > 0 )
+    {
+    list[0] = ModuleID;
+    if( size > 1 )
+      return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
+    return( 1 );
+    }
+  return( 0 );
+  } /* ubi_avlModuleID */
+
+/* ============================== The End ============================== */
diff --git a/source/ubi_AVLtree.h b/source/ubi_AVLtree.h
new file mode 100644 (file)
index 0000000..27d84a2
--- /dev/null
@@ -0,0 +1,340 @@
+#ifndef ubi_AVLtree_H
+#define ubi_AVLtree_H
+/* ========================================================================== **
+ *                              ubi_AVLtree.h
+ *
+ *  Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ *  This module provides an implementation of AVL height balanced binary
+ *  trees.  (Adelson-Velskii, Landis 1962)
+ *
+ *  This header file contains the basic AVL structure and pointer typedefs
+ *  as well as the prototypes needed to access the functions in the AVL
+ *  module ubi_AVLtree.  The .c file implements the low-level height balancing
+ *  routines that manage the AVL tree, plus all of the basic primops for
+ *  adding, searching for, and deleting nodes.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ * $Log: ubi_AVLtree.h,v $
+ * Revision 1.1  1997/10/09 04:09:51  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 2.4  1997/07/26 04:36:23  crh
+ * Andrew Leppard, aka "Grazgur", discovered that I still had my brains tied
+ * on backwards with respect to node deletion.  I did some more digging and
+ * discovered that I was not changing the balance values correctly in the
+ * single rotation functions.  Double rotation was working correctly because
+ * the formula for changing the balance values is the same for insertion or
+ * deletion.  Not so for single rotation.
+ *
+ * I have tested the fix by loading the tree with over 44 thousand names,
+ * deleting 2,629 of them (all those in which the second character is 'u')
+ * and then walking the tree recursively to verify that the balance factor of
+ * each node is correct.  Passed.
+ *
+ * Thanks Andrew!
+ *
+ * Also:
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ * + Rewrote the ubi_tr<func> macros because they weren't doing what I'd
+ *   hoped they would do (see the bottom of the header file).  They work now.
+ *
+ * Revision 2.3  1997/06/03 05:22:07  crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.2  1995/10/03 22:15:47  CRH
+ * Ubisized!
+ *
+ * Revision 2.1  95/03/09  23:46:44  CRH
+ * Added the ModuleID static string and function.  These modules are now
+ * self-identifying.
+ * 
+ * Revision 2.0  95/03/05  14:11:22  CRH
+ * This revision of ubi_AVLtree coincides with revision 2.0 of ubi_BinTree,
+ * and so includes all of the changes to that module.  In addition, a bug in
+ * the node deletion process has been fixed.
+ *
+ * After rewriting the Locate() function in ubi_BinTree, I decided that it was
+ * time to overhaul this module.  In the process, I discovered a bug related
+ * to node deletion.  To fix the bug, I wrote function Debalance().  A quick
+ * glance will show that it is very similar to the Rebalance() function.  In
+ * previous versions of this module, I tried to include the functionality of
+ * Debalance() within Rebalance(), with poor results.
+ *
+ * Revision 1.0  93/10/15  22:58:48  CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules.  Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ *       Module        Prefix
+ *     ubi_BinTree     ubi_bt
+ *     ubi_AVLtree     ubi_avl
+ *     ubi_SplayTree   ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot".  Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use.  If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules.  To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr".  The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using.  Just remember to
+ * include the header for that module in your program file.  Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module.  This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees.  CRH
+ *
+ *  V0.0 - May, 1990   -  Written by Christopher R. Hertel (CRH).
+ *
+ *  ========================================================================= **
+ */
+
+#include "ubi_BinTree.h"   /* Base erg binary tree support.       */
+
+/*  ------------------------------------------------------------------------- **
+ *  AVL Tree Node Structure:  This structure defines the basic elements of
+ *       the AVL tree nodes.  In general you *SHOULD NOT PLAY WITH THESE
+ *       FIELDS*!  But, of course, I have to put the structure into this
+ *       header so that you can use the structure as a building block.
+ *
+ *  The fields are as follows:
+ *    Link     -  An array of pointers.  These pointers are manipulated by the
+ *                BT and AVL routines, and indicate the left and right child
+ *                nodes, plus the parent node.  By keeping track of the parent
+ *                pointer, we avoid the need for recursive routines or hand-
+ *                tooled stacks to keep track of our path back to the root.
+ *                The use of these pointers is subject to change without
+ *                notice.
+ *    gender   -  For tree rebalancing purposes, it is necessary that each node
+ *                know whether it is the left or right child of its parent, or
+ *                if it is the root.  This information is stored in this field.
+ *    balance  -  This field is also needed for AVL balancing purposes.  It
+ *                indicates which subtree of the current node is longer, or if
+ *                the subtrees are, in fact, balanced with respect to each
+ *                other.
+ *  ------------------------------------------------------------------------- **
+ */
+
+typedef struct ubi_avlNodeStruct {
+  struct ubi_avlNodeStruct
+         *Link[3];      /* Normal Binary Tree Node type.                      */
+  char    gender;       /* The node is either the RIGHT or LEFT child of its  */
+                        /* parent, or is the root node.                       */
+  char    balance;      /* In an AVL tree, each node is the root of a subtree */
+                        /* that may be balanced, or be one node longer to the */
+                        /* right or left.  This field keeps track of the      */
+                        /* balance value of each node.                        */
+    } ubi_avlNode;  /* Typedef'd name for an avl tree node. */
+
+typedef ubi_avlNode *ubi_avlNodePtr;    /* a Pointer to an AVL node */
+
+/* -------------------------------------------------------------------------- **
+ *  Function prototypes.
+ * -------------------------------------------------------------------------- **
+ */
+
+ubi_avlNodePtr ubi_avlInitNode( ubi_avlNodePtr NodePtr );
+  /* ------------------------------------------------------------------------ **
+   * Initialize a tree node.
+   *
+   *  Input:   NodePtr  - a pointer to a ubi_btNode structure to be
+   *                      initialized.
+   *  Output:  a pointer to the initialized ubi_avlNode structure (ie. the
+   *           same as the input pointer).
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_trBool ubi_avlInsert( ubi_btRootPtr   RootPtr,
+                          ubi_avlNodePtr  NewNode,
+                          ubi_btItemPtr   ItemPtr,
+                          ubi_avlNodePtr *OldNode );
+  /* ------------------------------------------------------------------------ **
+   * This function uses a non-recursive algorithm to add a new element to
+   * the tree.
+   *
+   *  Input:   RootPtr  -  a pointer to the ubi_btRoot structure that indicates
+   *                       the root of the tree to which NewNode is to be added.
+   *           NewNode  -  a pointer to an ubi_avlNode structure that is NOT
+   *                       part of any tree.
+   *           ItemPtr  -  A pointer to the sort key that is stored within
+   *                       *NewNode.  ItemPtr MUST point to information stored
+   *                       in *NewNode or an EXACT DUPLICATE.  The key data
+   *                       indicated by ItemPtr is used to place the new node
+   *                       into the tree.
+   *           OldNode  -  a pointer to an ubi_btNodePtr.  When searching
+   *                       the tree, a duplicate node may be found.  If
+   *                       duplicates are allowed, then the new node will
+   *                       be simply placed into the tree.  If duplicates
+   *                       are not allowed, however, then one of two things
+   *                       may happen.
+   *                       1) if overwritting *is not* allowed, this
+   *                          function will return FALSE (indicating that
+   *                          the new node could not be inserted), and
+   *                          *OldNode will point to the duplicate that is
+   *                          still in the tree.
+   *                       2) if overwritting *is* allowed, then this
+   *                          function will swap **OldNode for *NewNode.
+   *                          In this case, *OldNode will point to the node
+   *                          that was removed (thus allowing you to free
+   *                          the node).
+   *                          **  If you are using overwrite mode, ALWAYS  **
+   *                          ** check the return value of this parameter! **
+   *                 Note: You may pass NULL in this parameter, the
+   *                       function knows how to cope.  If you do this,
+   *                       however, there will be no way to return a
+   *                       pointer to an old (ie. replaced) node (which is
+   *                       a problem if you are using overwrite mode).
+   *
+   *  Output:  a boolean value indicating success or failure.  The function
+   *           will return FALSE if the node could not be added to the tree.
+   *           Such failure will only occur if duplicates are not allowed,
+   *           nodes cannot be overwritten, AND a duplicate key was found
+   *           within the tree.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_avlNodePtr ubi_avlRemove( ubi_btRootPtr  RootPtr,
+                              ubi_avlNodePtr DeadNode );
+  /* ------------------------------------------------------------------------ **
+   * This function removes the indicated node from the tree, after which the
+   * tree is rebalanced.
+   *
+   *  Input:  RootPtr  -  A pointer to the header of the tree that contains
+   *                      the node to be removed.
+   *          DeadNode -  A pointer to the node that will be removed.
+   *
+   *  Output: This function returns a pointer to the node that was removed
+   *          from the tree (ie. the same as DeadNode).
+   *
+   *  Note:   The node MUST be in the tree indicated by RootPtr.  If not,
+   *          strange and evil things will happen to your trees.
+   * ------------------------------------------------------------------------ **
+   */
+
+int ubi_avlModuleID( int size, char *list[] );
+  /* ------------------------------------------------------------------------ **
+   * Returns a set of strings that identify the module.
+   *
+   *  Input:  size  - The number of elements in the array <list>.
+   *          list  - An array of pointers of type (char *).  This array
+   *                  should, initially, be empty.  This function will fill
+   *                  in the array with pointers to strings.
+   *  Output: The number of elements of <list> that were used.  If this value
+   *          is less than <size>, the values of the remaining elements are
+   *          not guaranteed.
+   *
+   *  Notes:  Please keep in mind that the pointers returned indicate strings
+   *          stored in static memory.  Don't free() them, don't write over
+   *          them, etc.  Just read them.
+   * ------------------------------------------------------------------------ **
+   */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_avl... or ubi_bt, use ubi_tr... and select the tree
+ * type by including the appropriate module header.
+ */
+
+#undef ubi_trNode
+#undef ubi_trNodePtr
+#define ubi_trNode    ubi_avlNode
+#define ubi_trNodePtr ubi_avlNodePtr
+
+#undef ubi_trInitNode
+#define ubi_trInitNode( Np ) ubi_avlInitNode( (ubi_avlNodePtr)(Np) )
+
+#undef ubi_trInsert
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+        ubi_avlInsert( (ubi_btRootPtr)(Rp), (ubi_avlNodePtr)(Nn), \
+                       (ubi_btItemPtr)(Ip), (ubi_avlNodePtr *)(On) )
+
+#undef ubi_trRemove
+#define ubi_trRemove( Rp, Dn ) \
+        ubi_avlRemove( (ubi_btRootPtr)(Rp), (ubi_avlNodePtr)(Dn) )
+
+#undef ubi_trLocate
+#define ubi_trLocate( Rp, Ip, Op ) \
+        (ubi_avlNodePtr)ubi_btLocate( (ubi_btRootPtr)(Rp), \
+                                      (ubi_btItemPtr)(Ip), \
+                                      (ubi_trCompOps)(Op) )
+
+#undef ubi_trFind
+#define ubi_trFind( Rp, Ip ) \
+        (ubi_avlNodePtr)ubi_btFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#undef ubi_trNext
+#define ubi_trNext( P ) (ubi_avlNodePtr)ubi_btNext( (ubi_btNodePtr)(P) )
+
+#undef ubi_trPrev
+#define ubi_trPrev( P ) (ubi_avlNodePtr)ubi_btPrev( (ubi_btNodePtr)(P) )
+
+#undef ubi_trFirst
+#define ubi_trFirst( P ) (ubi_avlNodePtr)ubi_btFirst( (ubi_btNodePtr)(P) )
+
+#undef ubi_trLast
+#define ubi_trLast( P ) (ubi_avlNodePtr)ubi_btLast( (ubi_btNodePtr)(P) )
+
+#undef ubi_trFirstOf
+#define ubi_trFirstOf( Rp, Ip, P ) \
+        (ubi_avlNodePtr)ubi_btFirstOf( (ubi_btRootPtr)(Rp), \
+                       (ubi_btItemPtr)(Ip), \
+                       (ubi_btNodePtr)(P) )
+
+#undef ubi_trLastOf
+#define ubi_trLastOf( Rp, Ip, P ) \
+        (ubi_avlNodePtr)ubi_btLastOf( (ubi_btRootPtr)(Rp), \
+                                      (ubi_btItemPtr)(Ip), \
+                                      (ubi_btNodePtr)(P) )
+
+#undef ubi_trLeafNode
+#define ubi_trLeafNode( Nd ) \
+        (ubi_avlNodePtr)ubi_btLeafNode( (ubi_btNodePtr)(Nd) )
+
+#undef ubi_trModuleID
+#define ubi_trModuleID( s, l ) ubi_avlModuleID( s, l )
+
+
+/* =========================== End  ubi_AVLtree.h =========================== */
+#endif /* ubi_AVLtree_H */
diff --git a/source/ubi_BinTree.c b/source/ubi_BinTree.c
new file mode 100644 (file)
index 0000000..e6db1a4
--- /dev/null
@@ -0,0 +1,1042 @@
+/* ========================================================================== **
+ *                              ubi_BinTree.c
+ *
+ *  Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ *  Email:  crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ *  ubi_BinTree manages a simple binary tree.  Nothing fancy here.  No height
+ *  balancing, no restructuring.  Still, a good tool for creating short, low-
+ *  overhead sorted lists of things that need to be found in a hurry.
+ *
+ *  In addition, this module provides a good basis for creating other types
+ *  of binary tree handling modules.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * $Log: ubi_BinTree.c,v $
+ * Revision 1.1  1997/10/09 04:09:52  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 2.4  1997/07/26 04:11:10  crh
+ * + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
+ *   and ubi_trFALSE.
+ * + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
+ * + There used to be something called "ubi_TypeDefs.h".  I got rid of it.
+ * + Added function ubi_btLeafNode().
+ *
+ * Revision 2.3  1997/06/03 05:16:17  crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
+ * Also changed the interface to function InitTree().  See the comments
+ * for this function for more information.
+ *
+ * Revision 2.2  1995/10/03 22:00:07  CRH
+ * Ubisized!
+ * 
+ * Revision 2.1  95/03/09  23:37:10  CRH
+ * Added the ModuleID static string and function.  These modules are now
+ * self-identifying.
+ * 
+ * Revision 2.0  95/02/27  22:00:17  CRH
+ * Revision 2.0 of this program includes the following changes:
+ *
+ *     1)  A fix to a major typo in the RepaceNode() function.
+ *     2)  The addition of the static function Border().
+ *     3)  The addition of the public functions FirstOf() and LastOf(), which
+ *         use Border(). These functions are used with trees that allow
+ *         duplicate keys.
+ *     4)  A complete rewrite of the Locate() function.  Locate() now accepts
+ *         a "comparison" operator.
+ *     5)  Overall enhancements to both code and comments.
+ *
+ * I decided to give this a new major rev number because the interface has
+ * changed.  In particular, there are two new functions, and changes to the
+ * Locate() function.
+ *
+ * Revision 1.0  93/10/15  22:44:59  CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules.  Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ *       Module        Prefix
+ *     ubi_BinTree     ubi_bt
+ *     ubi_AVLtree     ubi_avl
+ *     ubi_SplayTree   ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot".  Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use.  If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules.  To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr".  The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using.  Just remember to
+ * include the header for that module in your program file.  Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module.  This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees.  CRH
+ *
+ *  V0.0 - June, 1991   -  Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_BinTree.h"            /* Header for this module          */
+#include <stdlib.h>                 /* Standard C definitions.         */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_BinTree\n\
+\t$Revision: 1.1 $\n\
+\t$Date: 1997/10/09 04:09:52 $\n\
+\t$Author: crh $\n";
+
+/* ========================================================================== **
+ * Internal (private) functions.
+ */
+
+static ubi_btNodePtr qFind( ubi_btCompFunc cmp,
+                            ubi_btItemPtr  FindMe,
+                   register ubi_btNodePtr  p )
+  /* ------------------------------------------------------------------------ **
+   * This function performs a non-recursive search of a tree for a node
+   * matching a specific key.  It is called "qFind()" because it is
+   * faster that TreeFind (below).
+   *
+   *  Input:
+   *     cmp      -  a pointer to the tree's comparison function.
+   *     FindMe   -  a pointer to the key value for which to search.
+   *     p        -  a pointer to the starting point of the search.  <p>
+   *                 is considered to be the root of a subtree, and only
+   *                 the subtree will be searched.
+   *
+   *  Output:
+   *     A pointer to a node with a key that matches the key indicated by
+   *     FindMe, or NULL if no such node was found.
+   *
+   *  Note:   In a tree that allows duplicates, the pointer returned *might
+   *          not* point to the (sequentially) first occurance of the
+   *          desired key.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  char tmp;
+
+  while( p && (( tmp = AbNormal((*cmp)(FindMe, p)) ) != EQUAL) )
+    p = p->Link[tmp];
+
+  return( p );
+  } /* qFind */
+
+static ubi_btNodePtr TreeFind( ubi_btItemPtr  findme,
+                               ubi_btNodePtr  p,
+                               ubi_btNodePtr *parentp,
+                               char          *gender,
+                               ubi_btCompFunc CmpFunc )
+  /* ------------------------------------------------------------------------ **
+   * TreeFind() searches a tree for a given value (findme).  It will return a
+   * pointer to the target node, if found, or NULL if the target node was not
+   * found.
+   *
+   * TreeFind() also returns, via parameters, a pointer to the parent of the
+   * target node, and a LEFT or RIGHT value indicating which child of the
+   * parent is the target node.  *If the target is not found*, then these
+   * values indicate the place at which the target *should be found*.  This
+   * is useful when inserting a new node into a tree or searching for nodes
+   * "near" the target node.
+   *
+   * The parameters are:
+   *
+   *  findme   -  is a pointer to the key information to be searched for.
+   *  p        -  points to the root of the tree to be searched.
+   *  parentp  -  will return a pointer to a pointer to the !parent! of the
+   *              target node, which can be especially usefull if the target
+   *              was not found.
+   *  gender   -  returns LEFT or RIGHT to indicate which child of *parentp
+   *              was last searched.
+   *  CmpFunc  -  points to the comparison function.
+   *
+   * This function is called by ubi_btLocate() and ubi_btInsert().
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  register ubi_btNodePtr tmp_p = p;
+  ubi_btNodePtr tmp_pp = NULL;
+  char tmp_sex = EQUAL;
+  char tmp_cmp;
+
+  while( tmp_p && (EQUAL != (tmp_cmp = AbNormal((*CmpFunc)(findme, tmp_p)))) )
+    {
+    tmp_pp  = tmp_p;                /* Keep track of previous node. */
+    tmp_sex = tmp_cmp;              /* Keep track of sex of child.  */
+    tmp_p = tmp_p->Link[tmp_cmp];   /* Go to child. */
+    }
+  *parentp = tmp_pp;                /* Return results. */
+  *gender  = tmp_sex;
+  return( tmp_p );
+  } /* TreeFind */
+
+static void ReplaceNode( ubi_btNodePtr *parent,
+                         ubi_btNodePtr  oldnode,
+                         ubi_btNodePtr  newnode )
+  /* ------------------------------------------------------------------ *
+   * Remove node oldnode from the tree, replacing it with node newnode.
+   *
+   * Input:
+   *  parent   - A pointer to he parent pointer of the node to be
+   *             replaced.  <parent> may point to the Link[] field of
+   *             a parent node, or it may indicate the root pointer at
+   *             the top of the tree.
+   *  oldnode  - A pointer to the node that is to be replaced.
+   *  newnode  - A pointer to the node that is to be installed in the
+   *             place of <*oldnode>.
+   *
+   * Notes:    Don't forget to free oldnode.
+   *           Also, this function used to have a really nasty typo
+   *           bug.  "oldnode" and "newnode" were swapped in the line
+   *           that now reads:
+   *     ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+   *           Bleah!
+   * ------------------------------------------------------------------ *
+   */
+  {
+  register int i;
+  register int btNodeSize = sizeof( ubi_btNode );
+
+  for( i = 0; i < btNodeSize; i++ ) /* Copy node internals to new node. */
+    ((unsigned char *)newnode)[i] = ((unsigned char *)oldnode)[i];
+  (*parent) = newnode;              /* Old node's parent points to new child. */
+  /* Now tell the children about their new step-parent. */
+  if( oldnode->Link[LEFT ] ) (oldnode->Link[LEFT ])->Link[PARENT] = newnode;
+  if( oldnode->Link[RIGHT] ) (oldnode->Link[RIGHT])->Link[PARENT] = newnode;
+  } /* ReplaceNode */
+
+static void SwapNodes( ubi_btRootPtr RootPtr,
+                       ubi_btNodePtr Node1,
+                       ubi_btNodePtr Node2 )
+  /* ------------------------------------------------------------------------ **
+   * This function swaps two nodes in the tree.  Node1 will take the place of
+   * Node2, and Node2 will fill in the space left vacant by Node 1.
+   *
+   * Input:
+   *  RootPtr  - pointer to the tree header structure for this tree.
+   *  Node1    - \
+   *              > These are the two nodes which are to be swapped.
+   *  Node2    - /
+   *
+   * Notes:
+   *  This function does a three step swap, using a dummy node as a place
+   *  holder.  This function is used by ubi_btRemove().
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr *Parent;
+  ubi_btNode     dummy;
+  ubi_btNodePtr  dummy_p = &dummy;
+
+  /* Replace Node 1 with the dummy, thus removing Node1 from the tree. */
+  if( Node1->Link[PARENT] )
+    Parent = &((Node1->Link[PARENT])->Link[Node1->gender]);
+  else
+    Parent = &(RootPtr->root);
+  ReplaceNode( Parent, Node1, dummy_p );
+
+  /* Swap Node 1 with Node 2, placing Node 1 back into the tree. */
+  if( Node2->Link[PARENT] )
+    Parent = &((Node2->Link[PARENT])->Link[Node2->gender]);
+  else
+    Parent = &(RootPtr->root);
+  ReplaceNode( Parent, Node2, Node1 );
+
+  /* Swap Node 2 and the dummy, thus placing Node 2 back into the tree. */
+  if( dummy_p->Link[PARENT] )
+    Parent = &((dummy_p->Link[PARENT])->Link[dummy_p->gender]);
+  else
+    Parent = &(RootPtr->root);
+  ReplaceNode( Parent, dummy_p, Node2 );
+  } /* SwapNodes */
+
+/* -------------------------------------------------------------------------- **
+ * These routines allow you to walk through the tree, forwards or backwards.
+ */
+
+static ubi_btNodePtr SubSlide( register ubi_btNodePtr P,
+                               register char  whichway )
+  /* ------------------------------------------------------------------------ **
+   * Slide down the side of a subtree.
+   *
+   * Given a starting node, this function returns a pointer to the LEFT-, or
+   * RIGHT-most descendent, *or* (if whichway is PARENT) to the tree root.
+   *
+   *  Input:  P         - a pointer to a starting place.
+   *          whichway  - the direction (LEFT, RIGHT, or PARENT) in which to
+   *                      travel.
+   *  Output: A pointer to a node that is either the root, or has no
+   *          whichway-th child but is within the subtree of P.  Note that
+   *          the return value may be the same as P.  The return value *will
+   *          be* NULL if P is NULL.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr Q = NULL;
+
+  while( P )
+    {
+    Q = P;
+    P = P->Link[ whichway ];
+    }
+  return( Q );
+  } /* SubSlide */
+
+static ubi_btNodePtr Neighbor( register ubi_btNodePtr P,
+                               register char  whichway )
+  /* ------------------------------------------------------------------------ **
+   * Given starting point p, return the (key order) next or preceeding node
+   * in the tree.
+   *
+   *  Input:  P         - Pointer to our starting place node.
+   *          whichway  - the direction in which to travel to find the
+   *                      neighbor, i.e., the RIGHT neighbor or the LEFT
+   *                      neighbor.
+   *
+   *  Output: A pointer to the neighboring node, or NULL if P was NULL.
+   *
+   *  Notes:  If whichway is PARENT, the results are unpredictable.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( P )
+    {
+    if( P->Link[ whichway ] )
+      return( SubSlide( P->Link[ whichway ], (char)RevWay(whichway) ) );
+    else
+      while( P->Link[ PARENT ] )
+        {
+        if( (P->Link[ PARENT ])->Link[ whichway ] == P )
+          P = P->Link[ PARENT ];
+        else
+          return( P->Link[ PARENT ] );
+        }
+    }
+  return( NULL );
+  } /* Neighbor */
+
+static ubi_btNodePtr Border( ubi_btRootPtr RootPtr,
+                             ubi_btItemPtr FindMe,
+                             ubi_btNodePtr p,
+                             char          whichway )
+  /* ------------------------------------------------------------------------ **
+   * Given starting point p, which has a key value equal to *FindMe, locate
+   * the first (index order) node with the same key value.
+   *
+   * This function is useful in trees that have can have duplicate keys.
+   * For example, consider the following tree:
+   *     Tree                                                      Traversal
+   *       2    If <p> points to the root and <whichway> is RIGHT,     3
+   *      / \    then the return value will be a pointer to the       / \
+   *     2   2    RIGHT child of the root node.  The tree on         2   5
+   *    /   / \    the right shows the order of traversal.          /   / \
+   *   1   2   3                                                   1   4   6
+   *
+   *  Input:  RootPtr   - Pointer to the tree root structure.
+   *          FindMe    - Key value for comparisons.
+   *          p         - Pointer to the starting-point node.
+   *          whichway  - the direction in which to travel to find the
+   *                      neighbor, i.e., the RIGHT neighbor or the LEFT
+   *                      neighbor.
+   *
+   *  Output: A pointer to the first (index, or "traversal", order) node with
+   *          a Key value that matches *FindMe.
+   *
+   *  Notes:  If whichway is PARENT, or if the tree does not allow duplicate
+   *          keys, this function will return <p>.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  register ubi_btNodePtr q;
+
+  /* Exit if there's nothing that can be done. */
+  if( !Dups_OK( RootPtr ) || (PARENT == whichway) )
+    return( p );
+
+  /* First, if needed, move up the tree.  We need to get to the root of the
+   * subtree that contains all of the matching nodes.
+   */
+  q = p->Link[PARENT];
+  while( q && (EQUAL == AbNormal( (*(RootPtr->cmp))(FindMe, q) )) )
+    {
+    p = q;
+    q = p->Link[PARENT];
+    }
+
+  /* Next, move back down in the "whichway" direction. */
+  q = p->Link[whichway];
+  while( q )
+    {
+    if( q = qFind( RootPtr->cmp, FindMe, q ) )
+      {
+      p = q;
+      q = p->Link[whichway];
+      }
+    }
+  return( p );
+  } /* Border */
+
+
+/* ========================================================================== **
+ * Exported utilities.
+ */
+
+long ubi_btSgn( register long x )
+  /* ------------------------------------------------------------------------ **
+   * Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
+   *
+   *  Input:  x - a signed long integer value.
+   *
+   *  Output: the "sign" of x, represented as follows:
+   *            -1 == negative
+   *             0 == zero (no sign)
+   *             1 == positive
+   *
+   * Note: This utility is provided in order to facilitate the conversion
+   *       of C comparison function return values into BinTree direction
+   *       values: {LEFT, PARENT, EQUAL}.  It is INCORPORATED into the
+   *       AbNormal() conversion macro!
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  return( (x)?((x>0)?(1):(-1)):(0) );
+  } /* ubi_btSgn */
+
+ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr )
+  /* ------------------------------------------------------------------------ **
+   * Initialize a tree node.
+   *
+   *  Input:  a pointer to a ubi_btNode structure to be initialized.
+   *  Output: a pointer to the initialized ubi_btNode structure (ie. the
+   *          same as the input pointer).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  NodePtr->Link[ LEFT ]   = NULL;
+  NodePtr->Link[ PARENT ] = NULL;
+  NodePtr->Link[ RIGHT ]  = NULL;
+  NodePtr->gender         = EQUAL;
+  return( NodePtr );
+  } /* ubi_btInitNode */
+
+ubi_btRootPtr ubi_btInitTree( ubi_btRootPtr   RootPtr,
+                              ubi_btCompFunc  CompFunc,
+                              unsigned char   Flags )
+  /* ------------------------------------------------------------------------ **
+   * Initialize the fields of a Tree Root header structure.
+   *
+   *  Input:   RootPtr   - a pointer to an ubi_btRoot structure to be
+   *                       initialized.
+   *           CompFunc  - a pointer to a comparison function that will be used
+   *                       whenever nodes in the tree must be compared against
+   *                       outside values.
+   *           Flags     - One bytes worth of flags.  Flags include
+   *                       ubi_trOVERWRITE and ubi_trDUPKEY.  See the header
+   *                       file for more info.
+   *
+   *  Output:  a pointer to the initialized ubi_btRoot structure (ie. the
+   *           same value as RootPtr).
+   *
+   *  Note:    The interface to this function has changed from that of
+   *           previous versions.  The <Flags> parameter replaces two
+   *           boolean parameters that had the same basic effect.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( RootPtr )
+    {
+    RootPtr->root   = NULL;
+    RootPtr->count  = 0L;
+    RootPtr->cmp    = CompFunc;
+    RootPtr->flags  = (Flags & ubi_trDUPKEY) ? ubi_trDUPKEY : Flags;
+    }                 /* There are only two supported flags, and they are
+                       * mutually exclusive.  ubi_trDUPKEY takes precedence
+                       * over ubi_trOVERWRITE.
+                       */
+  return( RootPtr );
+  } /* ubi_btInitTree */
+
+ubi_trBool ubi_btInsert( ubi_btRootPtr  RootPtr,
+                         ubi_btNodePtr  NewNode,
+                         ubi_btItemPtr  ItemPtr,
+                         ubi_btNodePtr *OldNode )
+  /* ------------------------------------------------------------------------ **
+   * This function uses a non-recursive algorithm to add a new element to the
+   * tree.
+   *
+   *  Input:   RootPtr  -  a pointer to the ubi_btRoot structure that indicates
+   *                       the root of the tree to which NewNode is to be added.
+   *           NewNode  -  a pointer to an ubi_btNode structure that is NOT
+   *                       part of any tree.
+   *           ItemPtr  -  A pointer to the sort key that is stored within
+   *                       *NewNode.  ItemPtr MUST point to information stored
+   *                       in *NewNode or an EXACT DUPLICATE.  The key data
+   *                       indicated by ItemPtr is used to place the new node
+   *                       into the tree.
+   *           OldNode  -  a pointer to an ubi_btNodePtr.  When searching
+   *                       the tree, a duplicate node may be found.  If
+   *                       duplicates are allowed, then the new node will
+   *                       be simply placed into the tree.  If duplicates
+   *                       are not allowed, however, then one of two things
+   *                       may happen.
+   *                       1) if overwritting *is not* allowed, this
+   *                          function will return FALSE (indicating that
+   *                          the new node could not be inserted), and
+   *                          *OldNode will point to the duplicate that is
+   *                          still in the tree.
+   *                       2) if overwritting *is* allowed, then this
+   *                          function will swap **OldNode for *NewNode.
+   *                          In this case, *OldNode will point to the node
+   *                          that was removed (thus allowing you to free
+   *                          the node).
+   *                          **  If you are using overwrite mode, ALWAYS  **
+   *                          ** check the return value of this parameter! **
+   *                 Note: You may pass NULL in this parameter, the
+   *                       function knows how to cope.  If you do this,
+   *                       however, there will be no way to return a
+   *                       pointer to an old (ie. replaced) node (which is
+   *                       a problem if you are using overwrite mode).
+   *
+   *  Output:  a boolean value indicating success or failure.  The function
+   *           will return FALSE if the node could not be added to the tree.
+   *           Such failure will only occur if duplicates are not allowed,
+   *           nodes cannot be overwritten, AND a duplicate key was found
+   *           within the tree.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr OtherP,
+                parent = NULL;
+  char          tmp;
+
+  if( !(OldNode) )       /* If they didn't give us a pointer, supply our own. */
+    OldNode = &OtherP;
+
+  (void)ubi_btInitNode( NewNode );     /* Init the new node's BinTree fields. */
+
+  /* Find a place for the new node. */
+  *OldNode = TreeFind(ItemPtr, (RootPtr->root), &parent, &tmp, (RootPtr->cmp));
+
+  /* Now add the node to the tree... */
+  if (!(*OldNode)) /* The easy one: we have a space for a new node! */
+    {
+    if (!(parent))
+      RootPtr->root = NewNode;
+    else
+      {
+      parent->Link[tmp]     = NewNode;
+      NewNode->Link[PARENT] = parent;
+      NewNode->gender       = tmp;
+      }
+    (RootPtr->count)++;
+    return( ubi_trTRUE );
+    }
+
+  /* If we reach this point, we know that a duplicate node exists.  This
+   * section adds the node to the tree if duplicate keys are allowed.
+   */
+  if( Dups_OK(RootPtr) )    /* Key exists, add duplicate */
+    {
+    ubi_btNodePtr q;
+
+    tmp = RIGHT;
+    q = (*OldNode);
+    *OldNode = NULL;
+    while( q )
+      {
+      parent = q;
+      if( tmp == EQUAL ) tmp = RIGHT;
+      q = q->Link[tmp];
+      if ( q )
+        tmp = AbNormal( (*(RootPtr->cmp))(ItemPtr, q) );
+      }
+    parent->Link[tmp]      = NewNode;
+    NewNode->Link[PARENT]  = parent;
+    NewNode->gender        = tmp;
+    (RootPtr->count)++;
+    return( ubi_trTRUE );
+    }
+
+  /* If we get to *this* point, we know that we are not allowed to have
+   * duplicate nodes, but our node keys match, so... may we replace the
+   * old one?
+   */
+  if( Ovwt_OK(RootPtr) )    /* Key exists, we replace */
+    {
+    if (!(parent))
+      ReplaceNode( &(RootPtr->root), *OldNode, NewNode );
+    else
+      ReplaceNode( &(parent->Link[(*OldNode)->gender]), *OldNode, NewNode );
+    return( ubi_trTRUE );
+    }
+
+  return( ubi_trFALSE );      /* Failure: could not replace an existing node. */
+  } /* ubi_btInsert */
+
+ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
+                            ubi_btNodePtr DeadNode )
+  /* ------------------------------------------------------------------------ **
+   * This function removes the indicated node from the tree.
+   *
+   *  Input:   RootPtr  -  A pointer to the header of the tree that contains
+   *                       the node to be removed.
+   *           DeadNode -  A pointer to the node that will be removed.
+   *
+   *  Output:  This function returns a pointer to the node that was removed
+   *           from the tree (ie. the same as DeadNode).
+   *
+   *  Note:    The node MUST be in the tree indicated by RootPtr.  If not,
+   *           strange and evil things will happen to your trees.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr p,
+               *parentp;
+  char          tmp;
+
+  /* if the node has both left and right subtrees, then we have to swap
+   * it with another node.  The other node we choose will be the Prev()ious
+   * node, which is garunteed to have no RIGHT child.
+   */
+  if( (DeadNode->Link[LEFT]) && (DeadNode->Link[RIGHT]) )
+    SwapNodes( RootPtr, DeadNode, ubi_btPrev( DeadNode ) );
+
+  /* The parent of the node to be deleted may be another node, or it may be
+   * the root of the tree.  Since we're not sure, it's best just to have
+   * a pointer to the parent pointer, whatever it is.
+   */
+  if (DeadNode->Link[PARENT])
+    parentp = &((DeadNode->Link[PARENT])->Link[DeadNode->gender]);
+  else
+    parentp = &( RootPtr->root );
+
+  /* Now link the parent to the only grand-child and patch up the gender. */
+  tmp = ((DeadNode->Link[LEFT])?LEFT:RIGHT);
+
+  p = (DeadNode->Link[tmp]);
+  if( p )
+    {
+    p->Link[PARENT] = DeadNode->Link[PARENT];
+    p->gender       = DeadNode->gender;
+    }
+  (*parentp) = p;
+
+  /* Finished, reduce the node count and return. */
+  (RootPtr->count)--;
+  return( DeadNode );
+  } /* ubi_btRemove */
+
+ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
+                            ubi_btItemPtr FindMe,
+                            ubi_trCompOps CompOp )
+  /* ------------------------------------------------------------------------ **
+   * The purpose of ubi_btLocate() is to find a node or set of nodes given
+   * a target value and a "comparison operator".  The Locate() function is
+   * more flexible and (in the case of trees that may contain dupicate keys)
+   * more precise than the ubi_btFind() function.  The latter is faster,
+   * but it only searches for exact matches and, if the tree contains
+   * duplicates, Find() may return a pointer to any one of the duplicate-
+   * keyed records.
+   *
+   *  Input:
+   *     RootPtr  -  A pointer to the header of the tree to be searched.
+   *     FindMe   -  An ubi_btItemPtr that indicates the key for which to
+   *                 search.
+   *     CompOp   -  One of the following:
+   *                    CompOp     Return a pointer to the node with
+   *                    ------     ---------------------------------
+   *                   ubi_trLT - the last key value that is less
+   *                              than FindMe.
+   *                   ubi_trLE - the first key matching FindMe, or
+   *                              the last key that is less than
+   *                              FindMe.
+   *                   ubi_trEQ - the first key matching FindMe.
+   *                   ubi_trGE - the first key matching FindMe, or the
+   *                              first key greater than FindMe.
+   *                   ubi_trGT - the first key greater than FindMe.
+   *  Output:
+   *     A pointer to the node matching the criteria listed above under
+   *     CompOp, or NULL if no node matched the criteria.
+   *
+   *  Notes:
+   *     In the case of trees with duplicate keys, Locate() will behave as
+   *     follows:
+   *
+   *     Find:  3                       Find: 3
+   *     Keys:  1 2 2 2 3 3 3 3 3 4 4   Keys: 1 1 2 2 2 4 4 5 5 5 6
+   *                  ^ ^         ^                   ^ ^
+   *                 LT EQ        GT                 LE GE
+   *
+   *     That is, when returning a pointer to a node with a key that is LESS
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     LAST matching node.
+   *     When returning a pointer to a node with a key that is GREATER
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     FIRST matching node.
+   *
+   *  See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  register ubi_btNodePtr p;
+  ubi_btNodePtr   parent;
+  char            whichkid;
+
+  /* Start by searching for a matching node. */
+  p = TreeFind( FindMe,
+                RootPtr->root,
+                &parent,
+                &whichkid,
+                RootPtr->cmp );
+
+  if( p )   /* If we have found a match, we can resolve as follows: */
+    {
+    switch( CompOp )
+      {
+      case ubi_trLT:            /* It's just a jump to the left...  */
+        p = Border( RootPtr, FindMe, p, LEFT );
+        return( Neighbor( p, LEFT ) );
+      case ubi_trGT:            /* ...and then a jump to the right. */
+        p = Border( RootPtr, FindMe, p, RIGHT );
+        return( Neighbor( p, RIGHT ) );
+      }
+    p = Border( RootPtr, FindMe, p, LEFT );
+    return( p );
+    }
+
+  /* Else, no match. */
+  if( ubi_trEQ == CompOp )    /* If we were looking for an exact match... */
+    return( NULL );           /* ...forget it.                            */
+
+  /* We can still return a valid result for GT, GE, LE, and LT.
+   * <parent> points to a node with a value that is either just before or
+   * just after the target value.
+   * Remaining possibilities are LT and GT (including LE & GE).
+   */
+  if( (ubi_trLT == CompOp) || (ubi_trLE == CompOp) )
+    return( (LEFT  == whichkid) ? Neighbor( parent, whichkid ) : parent );
+  else
+    return( (RIGHT == whichkid) ? Neighbor( parent, whichkid ) : parent );
+  } /* ubi_btLocate */
+
+ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
+                          ubi_btItemPtr FindMe )
+  /* ------------------------------------------------------------------------ **
+   * This function performs a non-recursive search of a tree for any node
+   * matching a specific key.
+   *
+   *  Input:
+   *     RootPtr  -  a pointer to the header of the tree to be searched.
+   *     FindMe   -  a pointer to the key value for which to search.
+   *
+   *  Output:
+   *     A pointer to a node with a key that matches the key indicated by
+   *     FindMe, or NULL if no such node was found.
+   *
+   *  Note:   In a tree that allows duplicates, the pointer returned *might
+   *          not* point to the (sequentially) first occurance of the
+   *          desired key.  In such a tree, it may be more useful to use
+   *          ubi_btLocate().
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  return( qFind( RootPtr->cmp, FindMe, RootPtr->root ) );
+  } /* ubi_btFind */
+
+ubi_btNodePtr ubi_btNext( ubi_btNodePtr P )
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) Next node in the
+   * tree.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "next" node in the tree, or NULL if P pointed
+   *           to the "last" node in the tree or was NULL.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  return( Neighbor( P, RIGHT ) );
+  } /* ubi_btNext */
+
+ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P )
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) Previous node in
+   * the tree.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "previous" node in the tree, or NULL if P
+   *           pointed to the "first" node in the tree or was NULL.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  return( Neighbor( P, LEFT ) );
+  } /* ubi_btPrev */
+
+ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P )
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) First node in the
+   * subtree of which *P is the root.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "first" node in a subtree that has *P as its
+   *           root.  This function will return NULL only if P is NULL.
+   *  Note:    In general, you will be passing in the value of the root field
+   *           of an ubi_btRoot structure.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  return( SubSlide( P, LEFT ) );
+  } /* ubi_btFirst */
+
+ubi_btNodePtr ubi_btLast( ubi_btNodePtr P )
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) Last node in the
+   * subtree of which *P is the root.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "last" node in a subtree that has *P as its
+   *           root.  This function will return NULL only if P is NULL.
+   *  Note:    In general, you will be passing in the value of the root field
+   *           of an ubi_btRoot structure.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  return( SubSlide( P, RIGHT ) );
+  } /* ubi_btLast */
+
+ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
+                             ubi_btItemPtr MatchMe,
+                             ubi_btNodePtr p )
+  /* ------------------------------------------------------------------------ **
+   * Given a tree that a allows duplicate keys, and a pointer to a node in
+   * the tree, this function will return a pointer to the first (traversal
+   * order) node with the same key value.
+   *
+   *  Input:  RootPtr - A pointer to the root of the tree.
+   *          MatchMe - A pointer to the key value.  This should probably
+   *                    point to the key within node *p.
+   *          p       - A pointer to a node in the tree.
+   *  Output: A pointer to the first node in the set of nodes with keys
+   *          matching <FindMe>.
+   *  Notes:  Node *p MUST be in the set of nodes with keys matching
+   *          <FindMe>.  If not, this function will return NULL.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  /* If our starting point is invalid, return NULL. */
+  if( !p || AbNormal( (*(RootPtr->cmp))( MatchMe, p ) != EQUAL ) )
+    return( NULL );
+  return( Border( RootPtr, MatchMe, p, LEFT ) );
+  } /* ubi_btFirstOf */
+
+ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
+                            ubi_btItemPtr MatchMe,
+                            ubi_btNodePtr p )
+  /* ------------------------------------------------------------------------ **
+   * Given a tree that a allows duplicate keys, and a pointer to a node in
+   * the tree, this function will return a pointer to the last (traversal
+   * order) node with the same key value.
+   *
+   *  Input:  RootPtr - A pointer to the root of the tree.
+   *          MatchMe - A pointer to the key value.  This should probably
+   *                    point to the key within node *p.
+   *          p       - A pointer to a node in the tree.
+   *  Output: A pointer to the last node in the set of nodes with keys
+   *          matching <FindMe>.
+   *  Notes:  Node *p MUST be in the set of nodes with keys matching
+   *          <FindMe>.  If not, this function will return NULL.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  /* If our starting point is invalid, return NULL. */
+  if( !p || AbNormal( (*(RootPtr->cmp))( MatchMe, p ) != EQUAL ) )
+    return( NULL );
+  return( Border( RootPtr, MatchMe, p, RIGHT ) );
+  } /* ubi_btLastOf */
+
+ubi_trBool ubi_btTraverse( ubi_btRootPtr   RootPtr,
+                           ubi_btActionRtn EachNode,
+                           void           *UserData )
+  /* ------------------------------------------------------------------------ **
+   * Traverse a tree in sorted order (non-recursively).  At each node, call
+   * (*EachNode)(), passing a pointer to the current node, and UserData as the
+   * second parameter.
+   *  Input:   RootPtr  -  a pointer to an ubi_btRoot structure that indicates
+   *                       the tree to be traversed.
+   *           EachNode -  a pointer to a function to be called at each node
+   *                       as the node is visited.
+   *           UserData -  a generic pointer that may point to anything that
+   *                       you choose.
+   *  Output:  A boolean value.  FALSE if the tree is empty, otherwise TRUE.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr p;
+
+  if( !(p = ubi_btFirst( RootPtr->root )) ) return( ubi_trFALSE );
+
+  while( p )
+    {
+    EachNode( p, UserData );
+    p = ubi_btNext( p );
+    }
+  return( ubi_trTRUE );
+  } /* ubi_btTraverse */
+
+ubi_trBool ubi_btKillTree( ubi_btRootPtr     RootPtr,
+                           ubi_btKillNodeRtn FreeNode )
+  /* ------------------------------------------------------------------------ **
+   * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+   * structure.  Note that this function will return FALSE if either parameter
+   * is NULL.
+   *
+   *  Input:   RootPtr  -  a pointer to an ubi_btRoot structure that indicates
+   *                       the root of the tree to delete.
+   *           FreeNode -  a function that will be called for each node in the
+   *                       tree to deallocate the memory used by the node.
+   *
+   *  Output:  A boolean value.  FALSE if either input parameter was NULL, else
+   *           TRUE.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr p, q;
+
+  if( !(RootPtr) || !(FreeNode) )
+    return( ubi_trFALSE );
+
+  p = ubi_btFirst( RootPtr->root );
+  while( p )
+    {
+    q = p;
+    while( q->Link[RIGHT] )
+      q = SubSlide( q->Link[RIGHT], LEFT );
+    p = q->Link[PARENT];
+    if( p )
+      p->Link[ ((p->Link[LEFT] == q)?LEFT:RIGHT) ] = NULL;
+    FreeNode((void *)q);
+    }
+
+  (void)ubi_btInitTree( RootPtr,
+                        RootPtr->cmp,
+                        RootPtr->flags );
+  return( ubi_trTRUE );
+  } /* ubi_btKillTree */
+
+ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader )
+  /* ------------------------------------------------------------------------ **
+   * Returns a pointer to a leaf node.
+   *
+   *  Input:  leader  - Pointer to a node at which to start the descent.
+   *
+   *  Output: A pointer to a leaf node selected in a somewhat arbitrary
+   *          manner.
+   *
+   *  Notes:  I wrote this function because I was using splay trees as a
+   *          database cache.  The cache had a maximum size on it, and I
+   *          needed a way of choosing a node to sacrifice if the cache
+   *          became full.  In a splay tree, less recently accessed nodes
+   *          tend toward the bottom of the tree, meaning that leaf nodes
+   *          are good candidates for removal.  (I really can't think of
+   *          any other reason to use this function.)
+   *        + In a simple binary tree or an AVL tree, the most recently
+   *          added nodes tend to be nearer the bottom, making this a *bad*
+   *          way to choose which node to remove from the cache.
+   *        + Randomizing the traversal order is probably a good idea.  You
+   *          can improve the randomization of leaf node selection by passing
+   *          in pointers to nodes other than the root node each time.  A
+   *          pointer to any node in the tree will do.  Of course, if you
+   *          pass a pointer to a leaf node you'll get the same thing back.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr follower = NULL;
+  int           whichway = LEFT;
+
+  while( NULL != leader )
+    {
+    follower = leader;
+    leader   = follower->Link[ whichway ];
+    if( NULL == leader )
+      {
+      whichway = RevWay( whichway );
+      leader   = follower->Link[ whichway ];
+      }
+    }
+
+  return( follower );
+  } /* ubi_btLeafNode */
+
+int ubi_btModuleID( int size, char *list[] )
+  /* ------------------------------------------------------------------------ **
+   * Returns a set of strings that identify the module.
+   *
+   *  Input:  size  - The number of elements in the array <list>.
+   *          list  - An array of pointers of type (char *).  This array
+   *                  should, initially, be empty.  This function will fill
+   *                  in the array with pointers to strings.
+   *  Output: The number of elements of <list> that were used.  If this value
+   *          is less than <size>, the values of the remaining elements are
+   *          not guaranteed.
+   *
+   *  Notes:  Please keep in mind that the pointers returned indicate strings
+   *          stored in static memory.  Don't free() them, don't write over
+   *          them, etc.  Just read them.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( size > 0 )
+    {
+    list[0] = ModuleID;
+    if( size > 1 )
+      list[1] = NULL;
+    return( 1 );
+    }
+  return( 0 );
+  } /* ubi_btModuleID */
+
+
+/* ========================================================================== */
diff --git a/source/ubi_BinTree.h b/source/ubi_BinTree.h
new file mode 100644 (file)
index 0000000..1be8cba
--- /dev/null
@@ -0,0 +1,745 @@
+#ifndef ubi_BinTree_H
+#define ubi_BinTree_H
+/* ========================================================================== **
+ *                              ubi_BinTree.h
+ *
+ *  Copyright (C) 1991-1997 by Christopher R. Hertel
+ *
+ *  Email:  crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ *  ubi_BinTree manages a simple binary tree.  Nothing fancy here.  No height
+ *  balancing, no restructuring.  Still, a good tool for creating short, low-
+ *  overhead sorted lists of things that need to be found in a hurry.
+ *
+ *  In addition, this module provides a good basis for creating other types
+ *  of binary tree handling modules.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * $Log: ubi_BinTree.h,v $
+ * Revision 1.1  1997/10/09 04:09:52  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 2.4  1997/07/26 04:11:14  crh
+ * + Just to be annoying I changed ubi_TRUE and ubi_FALSE to ubi_trTRUE
+ *   and ubi_trFALSE.
+ * + There is now a type ubi_trBool to go with ubi_trTRUE and ubi_trFALSE.
+ * + There used to be something called "ubi_TypeDefs.h".  I got rid of it.
+ * + Added function ubi_btLeafNode().
+ *
+ * Revision 2.3  1997/06/03 05:15:27  crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid conflicts.
+ * Also changed the interface to function InitTree().  See the comments
+ * for this function for more information.
+ *
+ * Revision 2.2  1995/10/03 22:00:40  CRH
+ * Ubisized!
+ * 
+ * Revision 2.1  95/03/09  23:43:46  CRH
+ * Added the ModuleID static string and function.  These modules are now
+ * self-identifying.
+ * 
+ * Revision 2.0  95/02/27  22:00:33  CRH
+ * Revision 2.0 of this program includes the following changes:
+ *
+ *     1)  A fix to a major typo in the RepaceNode() function.
+ *     2)  The addition of the static function Border().
+ *     3)  The addition of the public functions FirstOf() and LastOf(), which
+ *         use Border(). These functions are used with trees that allow
+ *         duplicate keys.
+ *     4)  A complete rewrite of the Locate() function.  Locate() now accepts
+ *         a "comparison" operator.
+ *     5)  Overall enhancements to both code and comments.
+ *
+ * I decided to give this a new major rev number because the interface has
+ * changed.  In particular, there are two new functions, and changes to the
+ * Locate() function.
+ *
+ * Revision 1.0  93/10/15  22:55:04  CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules.  Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ *       Module        Prefix
+ *     ubi_BinTree     ubi_bt
+ *     ubi_AVLtree     ubi_avl
+ *     ubi_SplayTree   ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot".  Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use.  If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules.  To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr".  The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using.  Just remember to
+ * include the header for that module in your program file.  Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module.  This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees.  CRH
+ *
+ *  V0.0 - June, 1991   -  Written by Christopher R. Hertel (CRH).
+ *
+ * ========================================================================== **
+ */
+
+/* -------------------------------------------------------------------------- **
+ * Macros and constants.
+ *
+ *  General purpose:
+ *    ubi_trTRUE  - Boolean TRUE.
+ *    ubi_trFALSE - Boolean FALSE.
+ *
+ *  Flags used in the tree header:
+ *    ubi_trOVERWRITE   - This flag indicates that an existing node may be
+ *                        overwritten by a new node with a matching key.
+ *    ubi_trDUPKEY      - This flag indicates that the tree allows duplicate
+ *                        keys.  If the tree does allow duplicates, the
+ *                        overwrite flag is ignored.
+ *
+ *  Node link array index constants:  (Each node has an array of three
+ *  pointers.  One to the left, one to the right, and one back to the
+ *  parent.)
+ *    LEFT    - Left child pointer.
+ *    PARENT  - Parent pointer.
+ *    RIGHT   - Right child pointer.
+ *    EQUAL   - Synonym for PARENT.
+ *
+ *  ubi_trCompOps:  These values are used in the ubi_trLocate() function.
+ *    ubi_trLT  - request the first instance of the greatest key less than
+ *                the search key.
+ *    ubi_trLE  - request the first instance of the greatest key that is less
+ *                than or equal to the search key.
+ *    ubi_trEQ  - request the first instance of key that is equal to the
+ *                search key.
+ *    ubi_trGE  - request the first instance of a key that is greater than
+ *                or equal to the search key.
+ *    ubi_trGT  - request the first instance of the first key that is greater
+ *                than the search key.
+ * -------------------------------------------------------------------------- **
+ */
+
+#define ubi_trTRUE  0xFF
+#define ubi_trFALSE 0x00
+
+#define ubi_trOVERWRITE 0x01        /* Turn on allow overwrite      */
+#define ubi_trDUPKEY    0x02        /* Turn on allow duplicate keys */
+
+/* Pointer array index constants... */
+#define LEFT   0x00
+#define PARENT 0x01
+#define RIGHT  0x02
+#define EQUAL  PARENT
+
+typedef enum {
+  ubi_trLT = 1,
+  ubi_trLE,
+  ubi_trEQ,
+  ubi_trGE,
+  ubi_trGT
+  } ubi_trCompOps;
+
+/* -------------------------------------------------------------------------- **
+ * These three macros allow simple manipulation of pointer index values (LEFT,
+ * RIGHT, and PARENT).
+ *
+ *    Normalize() -  converts {LEFT, PARENT, RIGHT} into {-1, 0 ,1}.  C
+ *                   uses {negative, zero, positive} values to indicate
+ *                   {less than, equal to, greater than}.
+ *    AbNormal()  -  converts {negative, zero, positive} to {LEFT, PARENT,
+ *                   RIGHT} (opposite of Normalize()).  Note: C comparison
+ *                   functions, such as strcmp(), return {negative, zero,
+ *                   positive} values, which are not necessarily {-1, 0,
+ *                   1}.  This macro uses the the ubi_btSgn() function to
+ *                   compensate.
+ *    RevWay()    -  converts LEFT to RIGHT and RIGHT to LEFT.  PARENT (EQUAL)
+ *                   is left as is.
+ * -------------------------------------------------------------------------- **
+ */
+#define Normalize(W) ((char)((W)-EQUAL))
+#define AbNormal(W) ((char)( EQUAL+((char)ubi_btSgn( (W) )) ))
+#define RevWay(W) ((char)((W)==LEFT?RIGHT:((W)==RIGHT?LEFT:EQUAL)))
+
+/* -------------------------------------------------------------------------- **
+ * These macros allow us to quickly read the values of the OVERWRITE and
+ * DUPlicate KEY bits of the tree root flags field.
+ * -------------------------------------------------------------------------- **
+ */
+#define Dups_OK(A) ((ubi_trDUPKEY & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
+#define Ovwt_OK(A) ((ubi_trOVERWRITE & ((A)->flags))?(ubi_trTRUE):(ubi_trFALSE))
+
+/* -------------------------------------------------------------------------- **
+ * Typedefs...
+ * 
+ * ubi_trBool   - Your typcial true or false...
+ *
+ * Item Pointer:  The ubi_btItemPtr is a generic pointer. It is used to
+ *                indicate a key that is being searched for within the tree.
+ *                Searching occurs whenever the ubi_trFind(), ubi_trLocate(),
+ *                or ubi_trInsert() functions are called.
+ * -------------------------------------------------------------------------- **
+ */
+
+typedef unsigned char ubi_trBool;
+
+typedef void *ubi_btItemPtr;              /* A pointer to data within a node. */
+
+/*  ------------------------------------------------------------------------- **
+ *  Binary Tree Node Structure:  This structure defines the basic elements of
+ *       the tree nodes.  In general you *SHOULD NOT PLAY WITH THESE FIELDS*!
+ *       But, of course, I have to put the structure into this header so that
+ *       you can use it as a building block.
+ *
+ *  The fields are as follows:
+ *    Link     -  an array of pointers.  These pointers are manipulated by
+ *                the BT routines.  The pointers indicate the left and right
+ *                child nodes and the parent node.  By keeping track of the
+ *                parent pointer, we avoid the need for recursive routines or
+ *                hand-tooled stacks to keep track of our path back to the
+ *                root.  The use of these pointers is subject to change without
+ *                notice.
+ *    gender   -  a one-byte field indicating whether the node is the RIGHT or
+ *                LEFT child of its parent.  If the node is the root of the
+ *                tree, gender will be PARENT.
+ *  ------------------------------------------------------------------------- **
+ */
+typedef struct ubi_btNodeStruct {
+  struct ubi_btNodeStruct *Link[ 3 ];
+  char                     gender;
+  } ubi_btNode;
+
+typedef ubi_btNode *ubi_btNodePtr;     /* Pointer to an ubi_btNode structure. */
+
+/*  ------------------------------------------------------------------------- **
+ * The next three typedefs define standard function types used by the binary
+ * tree management routines.  In particular:
+ *
+ *    ubi_btCompFunc    is a pointer to a comparison function.  Comparison
+ *                      functions are passed an ubi_btItemPtr and an
+ *                      ubi_btNodePtr.  They return a value that is (<0), 0,
+ *                      or (>0) to indicate that the Item is (respectively)
+ *                      "less than", "equal to", or "greater than" the Item
+ *                      contained within the node.  (See ubi_btInitTree()).
+ *    ubi_btActionRtn   is a pointer to a function that may be called for each
+ *                      node visited when performing a tree traversal (see
+ *                      ubi_btTraverse()).  The function will be passed two
+ *                      parameters: the first is a pointer to a node in the
+ *                      tree, the second is a generic pointer that may point to
+ *                      anything that you like.
+ *    ubi_btKillNodeRtn is a pointer to a function that will deallocate the
+ *                      memory used by a node (see ubi_btKillTree()).  Since
+ *                      memory management is left up to you, deallocation may
+ *                      mean anything that you want it to mean.  Just remember
+ *                      that the tree *will* be destroyed and that none of the
+ *                      node pointers will be valid any more.
+ *  ------------------------------------------------------------------------- **
+ */
+
+typedef  int (*ubi_btCompFunc)( ubi_btItemPtr, ubi_btNodePtr );
+
+typedef void (*ubi_btActionRtn)( ubi_btNodePtr, void * );
+
+typedef void (*ubi_btKillNodeRtn)( ubi_btNodePtr );
+
+/* -------------------------------------------------------------------------- **
+ * Tree Root Structure: This structure gives us a convenient handle for
+ *                      accessing whole AVL trees.  The fields are:
+ *    root  -  A pointer to the root node of the AVL tree.
+ *    count -  A count of the number of nodes stored in the tree.
+ *    cmp   -  A pointer to the comparison routine to be used when building or
+ *             searching the tree.
+ *    flags -  A set of bit flags.  Two flags are currently defined:
+ *
+ *       ubi_trOVERWRITE -  If set, this flag indicates that a new node should
+ *         (bit 0x01)       overwrite an old node if the two have identical
+ *                          keys (ie., the keys are equal).
+ *       ubi_trDUPKEY    -  If set, this flag indicates that the tree is
+ *         (bit 0x02)       allowed to contain nodes with duplicate keys.
+ *
+ *       NOTE: ubi_trInsert() tests ubi_trDUPKEY before ubi_trOVERWRITE.
+ *
+ * All of these values are set when you initialize the root structure by
+ * calling ubi_trInitTree().
+ * -------------------------------------------------------------------------- **
+ */
+
+typedef struct {
+  ubi_btNodePtr  root;     /* A pointer to the root node of the tree       */
+  unsigned long  count;    /* A count of the number of nodes in the tree   */
+  ubi_btCompFunc cmp;      /* A pointer to the tree's comparison function  */
+  unsigned char  flags;    /* Overwrite Y|N, Duplicate keys Y|N...         */
+  } ubi_btRoot;
+
+typedef ubi_btRoot *ubi_btRootPtr;  /* Pointer to an ubi_btRoot structure. */
+
+
+/* -------------------------------------------------------------------------- **
+ * Function Prototypes.
+ */
+
+long ubi_btSgn( long x );
+  /* ------------------------------------------------------------------------ **
+   * Return the sign of x; {negative,zero,positive} ==> {-1, 0, 1}.
+   *
+   *  Input:  x - a signed long integer value.
+   *
+   *  Output: the "sign" of x, represented as follows:
+   *            -1 == negative
+   *             0 == zero (no sign)
+   *             1 == positive
+   *
+   * Note: This utility is provided in order to facilitate the conversion
+   *       of C comparison function return values into BinTree direction
+   *       values: {LEFT, PARENT, EQUAL}.  It is INCORPORATED into the
+   *       AbNormal() conversion macro!
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btInitNode( ubi_btNodePtr NodePtr );
+  /* ------------------------------------------------------------------------ **
+   * Initialize a tree node.
+   *
+   *  Input:   a pointer to a ubi_btNode structure to be initialized.
+   *  Output:  a pointer to the initialized ubi_btNode structure (ie. the
+   *           same as the input pointer).
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btRootPtr  ubi_btInitTree( ubi_btRootPtr   RootPtr,
+                               ubi_btCompFunc  CompFunc,
+                               unsigned char   Flags );
+  /* ------------------------------------------------------------------------ **
+   * Initialize the fields of a Tree Root header structure.
+   *  
+   *  Input:   RootPtr   - a pointer to an ubi_btRoot structure to be
+   *                       initialized.   
+   *           CompFunc  - a pointer to a comparison function that will be used
+   *                       whenever nodes in the tree must be compared against
+   *                       outside values.
+   *           Flags     - One bytes worth of flags.  Flags include
+   *                       ubi_trOVERWRITE and ubi_trDUPKEY.  See the header
+   *                       file for more info.
+   *
+   *  Output:  a pointer to the initialized ubi_btRoot structure (ie. the
+   *           same value as RootPtr).
+   * 
+   *  Note:    The interface to this function has changed from that of 
+   *           previous versions.  The <Flags> parameter replaces two      
+   *           boolean parameters that had the same basic effect.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_trBool ubi_btInsert( ubi_btRootPtr  RootPtr,
+                         ubi_btNodePtr  NewNode,
+                         ubi_btItemPtr  ItemPtr,
+                         ubi_btNodePtr *OldNode );
+  /* ------------------------------------------------------------------------ **
+   * This function uses a non-recursive algorithm to add a new element to the
+   * tree.
+   *
+   *  Input:   RootPtr  -  a pointer to the ubi_btRoot structure that indicates
+   *                       the root of the tree to which NewNode is to be added.
+   *           NewNode  -  a pointer to an ubi_btNode structure that is NOT
+   *                       part of any tree.
+   *           ItemPtr  -  A pointer to the sort key that is stored within
+   *                       *NewNode.  ItemPtr MUST point to information stored
+   *                       in *NewNode or an EXACT DUPLICATE.  The key data
+   *                       indicated by ItemPtr is used to place the new node
+   *                       into the tree.
+   *           OldNode  -  a pointer to an ubi_btNodePtr.  When searching
+   *                       the tree, a duplicate node may be found.  If
+   *                       duplicates are allowed, then the new node will
+   *                       be simply placed into the tree.  If duplicates
+   *                       are not allowed, however, then one of two things
+   *                       may happen.
+   *                       1) if overwritting *is not* allowed, this
+   *                          function will return FALSE (indicating that
+   *                          the new node could not be inserted), and
+   *                          *OldNode will point to the duplicate that is
+   *                          still in the tree.
+   *                       2) if overwritting *is* allowed, then this
+   *                          function will swap **OldNode for *NewNode.
+   *                          In this case, *OldNode will point to the node
+   *                          that was removed (thus allowing you to free
+   *                          the node).
+   *                          **  If you are using overwrite mode, ALWAYS  **
+   *                          ** check the return value of this parameter! **
+   *                 Note: You may pass NULL in this parameter, the
+   *                       function knows how to cope.  If you do this,
+   *                       however, there will be no way to return a
+   *                       pointer to an old (ie. replaced) node (which is
+   *                       a problem if you are using overwrite mode).
+   *
+   *  Output:  a boolean value indicating success or failure.  The function
+   *           will return FALSE if the node could not be added to the tree.
+   *           Such failure will only occur if duplicates are not allowed,
+   *           nodes cannot be overwritten, AND a duplicate key was found
+   *           within the tree.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btRemove( ubi_btRootPtr RootPtr,
+                            ubi_btNodePtr DeadNode );
+  /* ------------------------------------------------------------------------ **
+   * This function removes the indicated node from the tree.
+   *
+   *  Input:   RootPtr  -  A pointer to the header of the tree that contains
+   *                       the node to be removed.
+   *           DeadNode -  A pointer to the node that will be removed.
+   *
+   *  Output:  This function returns a pointer to the node that was removed
+   *           from the tree (ie. the same as DeadNode).
+   *
+   *  Note:    The node MUST be in the tree indicated by RootPtr.  If not,
+   *           strange and evil things will happen to your trees.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btLocate( ubi_btRootPtr RootPtr,
+                            ubi_btItemPtr FindMe,
+                            ubi_trCompOps CompOp );
+  /* ------------------------------------------------------------------------ **
+   * The purpose of ubi_btLocate() is to find a node or set of nodes given
+   * a target value and a "comparison operator".  The Locate() function is
+   * more flexible and (in the case of trees that may contain dupicate keys)
+   * more precise than the ubi_btFind() function.  The latter is faster,
+   * but it only searches for exact matches and, if the tree contains
+   * duplicates, Find() may return a pointer to any one of the duplicate-
+   * keyed records.
+   *
+   *  Input:
+   *     RootPtr  -  A pointer to the header of the tree to be searched.
+   *     FindMe   -  An ubi_btItemPtr that indicates the key for which to
+   *                 search.
+   *     CompOp   -  One of the following:
+   *                    CompOp     Return a pointer to the node with
+   *                    ------     ---------------------------------
+   *                   ubi_trLT - the last key value that is less
+   *                              than FindMe.
+   *                   ubi_trLE - the first key matching FindMe, or
+   *                              the last key that is less than
+   *                              FindMe.
+   *                   ubi_trEQ - the first key matching FindMe.
+   *                   ubi_trGE - the first key matching FindMe, or the
+   *                              first key greater than FindMe.
+   *                   ubi_trGT - the first key greater than FindMe.
+   *  Output:
+   *     A pointer to the node matching the criteria listed above under
+   *     CompOp, or NULL if no node matched the criteria.
+   *
+   *  Notes:
+   *     In the case of trees with duplicate keys, Locate() will behave as
+   *     follows:
+   *
+   *     Find:  3                       Find: 3
+   *     Keys:  1 2 2 2 3 3 3 3 3 4 4   Keys: 1 1 2 2 2 4 4 5 5 5 6
+   *                  ^ ^         ^                   ^ ^
+   *                 LT EQ        GT                 LE GE
+   *
+   *     That is, when returning a pointer to a node with a key that is LESS
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     LAST matching node.
+   *     When returning a pointer to a node with a key that is GREATER
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     FIRST matching node.
+   *
+   *  See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btFind( ubi_btRootPtr RootPtr,
+                          ubi_btItemPtr FindMe );
+  /* ------------------------------------------------------------------------ **
+   * This function performs a non-recursive search of a tree for any node
+   * matching a specific key.
+   *
+   *  Input:
+   *     RootPtr  -  a pointer to the header of the tree to be searched.
+   *     FindMe   -  a pointer to the key value for which to search.
+   *
+   *  Output:
+   *     A pointer to a node with a key that matches the key indicated by
+   *     FindMe, or NULL if no such node was found.
+   *
+   *  Note:   In a tree that allows duplicates, the pointer returned *might
+   *          not* point to the (sequentially) first occurance of the
+   *          desired key.  In such a tree, it may be more useful to use
+   *          ubi_btLocate().
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btNext( ubi_btNodePtr P );
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) Next node in the
+   * tree.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "next" node in the tree, or NULL if P pointed
+   *           to the "last" node in the tree or was NULL.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btPrev( ubi_btNodePtr P );
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) Previous node in
+   * the tree.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "previous" node in the tree, or NULL if P
+   *           pointed to the "first" node in the tree or was NULL.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btFirst( ubi_btNodePtr P );
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) First node in the
+   * subtree of which *P is the root.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "first" node in a subtree that has *P as its
+   *           root.  This function will return NULL only if P is NULL.
+   *  Note:    In general, you will be passing in the value of the root field
+   *           of an ubi_btRoot structure.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btLast( ubi_btNodePtr P );
+  /* ------------------------------------------------------------------------ **
+   * Given the node indicated by P, find the (sorted order) Last node in the
+   * subtree of which *P is the root.
+   *  Input:   P  -  a pointer to a node that exists in a binary tree.
+   *  Output:  A pointer to the "last" node in a subtree that has *P as its
+   *           root.  This function will return NULL only if P is NULL.
+   *  Note:    In general, you will be passing in the value of the root field
+   *           of an ubi_btRoot structure.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btFirstOf( ubi_btRootPtr RootPtr,
+                             ubi_btItemPtr MatchMe,
+                             ubi_btNodePtr p );
+  /* ------------------------------------------------------------------------ **
+   * Given a tree that a allows duplicate keys, and a pointer to a node in
+   * the tree, this function will return a pointer to the first (traversal
+   * order) node with the same key value.
+   *
+   *  Input:  RootPtr - A pointer to the root of the tree.
+   *          MatchMe - A pointer to the key value.  This should probably
+   *                    point to the key within node *p.
+   *          p       - A pointer to a node in the tree.
+   *  Output: A pointer to the first node in the set of nodes with keys
+   *          matching <FindMe>.
+   *  Notes:  Node *p MUST be in the set of nodes with keys matching
+   *          <FindMe>.  If not, this function will return NULL.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btLastOf( ubi_btRootPtr RootPtr,
+                            ubi_btItemPtr MatchMe,
+                            ubi_btNodePtr p );
+  /* ------------------------------------------------------------------------ **
+   * Given a tree that a allows duplicate keys, and a pointer to a node in
+   * the tree, this function will return a pointer to the last (traversal
+   * order) node with the same key value.
+   *
+   *  Input:  RootPtr - A pointer to the root of the tree.
+   *          MatchMe - A pointer to the key value.  This should probably
+   *                    point to the key within node *p.
+   *          p       - A pointer to a node in the tree.
+   *  Output: A pointer to the last node in the set of nodes with keys
+   *          matching <FindMe>.
+   *  Notes:  Node *p MUST be in the set of nodes with keys matching
+   *          <FindMe>.  If not, this function will return NULL.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_trBool ubi_btTraverse( ubi_btRootPtr   RootPtr,
+                           ubi_btActionRtn EachNode,
+                           void           *UserData );
+  /* ------------------------------------------------------------------------ **
+   * Traverse a tree in sorted order (non-recursively).  At each node, call
+   * (*EachNode)(), passing a pointer to the current node, and UserData as the
+   * second parameter.
+   *  Input:   RootPtr  -  a pointer to an ubi_btRoot structure that indicates
+   *                       the tree to be traversed.
+   *           EachNode -  a pointer to a function to be called at each node
+   *                       as the node is visited.
+   *           UserData -  a generic pointer that may point to anything that
+   *                       you choose.
+   *  Output:  A boolean value.  FALSE if the tree is empty, otherwise TRUE.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_trBool ubi_btKillTree( ubi_btRootPtr     RootPtr,
+                           ubi_btKillNodeRtn FreeNode );
+  /* ------------------------------------------------------------------------ **
+   * Delete an entire tree (non-recursively) and reinitialize the ubi_btRoot
+   * structure.  Note that this function will return FALSE if either parameter
+   * is NULL.
+   *
+   *  Input:   RootPtr  -  a pointer to an ubi_btRoot structure that indicates
+   *                       the root of the tree to delete.
+   *           FreeNode -  a function that will be called for each node in the
+   *                       tree to deallocate the memory used by the node.
+   *
+   *  Output:  A boolean value.  FALSE if either input parameter was NULL, else
+   *           TRUE.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_btLeafNode( ubi_btNodePtr leader );
+  /* ------------------------------------------------------------------------ **
+   * Returns a pointer to a leaf node.
+   *
+   *  Input:  leader  - Pointer to a node at which to start the descent.
+   *
+   *  Output: A pointer to a leaf node selected in a somewhat arbitrary
+   *          manner.
+   *
+   *  Notes:  I wrote this function because I was using splay trees as a
+   *          database cache.  The cache had a maximum size on it, and I
+   *          needed a way of choosing a node to sacrifice if the cache
+   *          became full.  In a splay tree, less recently accessed nodes
+   *          tend toward the bottom of the tree, meaning that leaf nodes
+   *          are good candidates for removal.  (I really can't think of
+   *          any other reason to use this function.)
+   *        + In a simple binary tree or an AVL tree, the most recently
+   *          added nodes tend to be nearer the bottom, making this a *bad*
+   *          way to choose which node to remove from the cache.
+   *        + Randomizing the traversal order is probably a good idea.  You
+   *          can improve the randomization of leaf node selection by passing
+   *          in pointers to nodes other than the root node each time.  A
+   *          pointer to any node in the tree will do.  Of course, if you
+   *          pass a pointer to a leaf node you'll get the same thing back.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+
+int ubi_btModuleID( int size, char *list[] );
+  /* ------------------------------------------------------------------------ **
+   * Returns a set of strings that identify the module.
+   *
+   *  Input:  size  - The number of elements in the array <list>.
+   *          list  - An array of pointers of type (char *).  This array
+   *                  should, initially, be empty.  This function will fill
+   *                  in the array with pointers to strings.
+   *  Output: The number of elements of <list> that were used.  If this value
+   *          is less than <size>, the values of the remaining elements are
+   *          not guaranteed.
+   *
+   *  Notes:  Please keep in mind that the pointers returned indicate strings
+   *          stored in static memory.  Don't free() them, don't write over
+   *          them, etc.  Just read them.
+   * ------------------------------------------------------------------------ **
+   */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
+ * including the appropriate module header.
+ */
+
+#define ubi_trItemPtr ubi_btItemPtr
+
+#define ubi_trNode    ubi_btNode
+#define ubi_trNodePtr ubi_btNodePtr
+
+#define ubi_trRoot    ubi_btRoot
+#define ubi_trRootPtr ubi_btRootPtr
+
+#define ubi_trCompFunc    ubi_btCompFunc
+#define ubi_trActionRtn   ubi_btActionRtn
+#define ubi_trKillNodeRtn ubi_btKillNodeRtn
+
+#define ubi_trSgn( x ) ubi_btSgn( x )
+
+#define ubi_trInitNode( Np ) ubi_btInitNode( (ubi_btNodePtr)(Np) )
+
+#define ubi_trInitTree( Rp, Cf, Fl ) \
+        ubi_btInitTree( (ubi_btRootPtr)(Rp), (ubi_btCompFunc)(Cf), (Fl) )
+
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+        ubi_btInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
+                      (ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
+
+#define ubi_trRemove( Rp, Dn ) \
+        ubi_btRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
+
+#define ubi_trLocate( Rp, Ip, Op ) \
+        ubi_btLocate( (ubi_btRootPtr)(Rp), \
+                      (ubi_btItemPtr)(Ip), \
+                      (ubi_trCompOps)(Op) )
+
+#define ubi_trFind( Rp, Ip ) \
+        ubi_btFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#define ubi_trNext( P ) ubi_btNext( (ubi_btNodePtr)(P) )
+
+#define ubi_trPrev( P ) ubi_btPrev( (ubi_btNodePtr)(P) )
+
+#define ubi_trFirst( P ) ubi_btFirst( (ubi_btNodePtr)(P) )
+
+#define ubi_trLast( P ) ubi_btLast( (ubi_btNodePtr)(P) )
+
+#define ubi_trFirstOf( Rp, Ip, P ) \
+        ubi_btFirstOf( (ubi_btRootPtr)(Rp), \
+                       (ubi_btItemPtr)(Ip), \
+                       (ubi_btNodePtr)(P) )
+
+#define ubi_trLastOf( Rp, Ip, P ) \
+        ubi_btLastOf( (ubi_btRootPtr)(Rp), \
+                      (ubi_btItemPtr)(Ip), \
+                      (ubi_btNodePtr)(P) )
+
+#define ubi_trTraverse( Rp, En, Ud ) \
+        ubi_btTraverse((ubi_btRootPtr)(Rp), (ubi_btActionRtn)(En), (void *)(Ud))
+
+#define ubi_trKillTree( Rp, Fn ) \
+        ubi_btKillTree( (ubi_btRootPtr)(Rp), (ubi_btKillNodeRtn)(Fn) )
+
+#define ubi_trLeafNode( Nd ) \
+        ubi_btLeafNode( (ubi_btNodePtr)(Nd) )
+
+#define ubi_trModuleID( s, l ) ubi_btModuleID( s, l )
+
+/* ========================================================================== */
+#endif /* ubi_BinTree_H */
diff --git a/source/ubi_SplayTree.c b/source/ubi_SplayTree.c
new file mode 100644 (file)
index 0000000..d38e383
--- /dev/null
@@ -0,0 +1,472 @@
+/* ========================================================================== **
+ *                              ubi_SplayTree.c
+ *
+ *  Copyright (C) 1993-1995 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ *  This module implements "splay" trees.  Splay trees are binary trees
+ *  that are rearranged (splayed) whenever a node is accessed.  The
+ *  splaying process *tends* to make the tree bushier (improves balance),
+ *  and the nodes that are accessed most frequently *tend* to be closer to
+ *  the top.
+ *
+ *  References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
+ *              Robert Tarjan.  Journal of the Association for Computing
+ *              Machinery Vol 32, No. 3, July 1985 pp. 652-686
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * $Log: ubi_SplayTree.c,v $
+ * Revision 1.1  1997/10/09 04:09:54  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 2.5  1997/07/26 04:15:42  crh
+ * + Cleaned up a few minor syntax annoyances that gcc discovered for me.
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ *
+ * Revision 2.4  1997/06/03 04:42:21  crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.3  1995/10/03 22:19:07  CRH
+ * Ubisized!
+ * Also, added the function ubi_sptSplay().
+ *
+ * Revision 2.1  95/03/09  23:54:42  CRH
+ * Added the ModuleID static string and function.  These modules are now
+ * self-identifying.
+ * 
+ * Revision 2.0  95/02/27  22:34:46  CRH
+ * This module was updated to match the interface changes made to the
+ * ubi_BinTree module.  In particular, the interface to the Locate() function
+ * has changed.  See ubi_BinTree for more information on changes and new
+ * functions.
+ *
+ * The revision number was also upped to match ubi_BinTree.
+ *
+ * Revision 1.1  93/10/18  20:35:16  CRH
+ * I removed the hard-coded logical device names from the include file
+ * specifications.  CRH
+ *
+ * Revision 1.0  93/10/15  23:00:15  CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules.  Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ *       Module        Prefix
+ *     ubi_BinTree     ubi_bt
+ *     ubi_AVLtree     ubi_avl
+ *     ubi_SplayTree   ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot".  Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use.  If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules.  To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr".  The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using.  Just remember to
+ * include the header for that module in your program file.  Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module.  This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees.  CRH
+ *
+ * Revision 0.1  93/04/25  22:03:32  CRH
+ * Simply changed the <exec/types.h> #include reference the .c file to
+ * use <stdlib.h> instead.  The latter is portable, the former is not.
+ *
+ * Revision 0.0  93/04/21  23:05:52  CRH
+ * Initial version, written by Christopher R. Hertel.
+ * This module implements Splay Trees using the ubi_BinTree module as a basis.
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h>        /* Defines NULL for us.                */
+#include "ubi_SplayTree.h" /* Header for THIS module.             */
+
+/* ========================================================================== **
+ * Static data.
+ */
+
+static char ModuleID[] = "ubi_SplayTree\n\
+\t$Revision: 1.1 $\n\
+\t$Date: 1997/10/09 04:09:54 $\n\
+\t$Author: crh $\n";
+
+
+/* ========================================================================== **
+ * Private functions...
+ */
+
+static void Rotate( ubi_btNodePtr p )
+  /* ------------------------------------------------------------------------ **
+   * This function performs a single rotation, moving node *p up one level
+   * in the tree.
+   *
+   *  Input:    p - a pointer to an ubi_btNode in a tree.
+   *
+   *  Output:   None.
+   *
+   *  Notes:    This implements a single rotation in either direction (left
+   *            or right).  This is the basic building block of all splay
+   *            tree rotations.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr parentp;
+  ubi_btNodePtr tmp;
+  char          way;
+  char          revway;
+
+  parentp = p->Link[PARENT];    /* Find parent. */
+
+  if( parentp )                 /* If no parent, then we're already the root. */
+    {
+    way     = p->gender;
+    revway  = RevWay(way);
+    tmp     = p->Link[revway];
+
+    parentp->Link[way]  = tmp;
+    if( tmp )
+      {
+      tmp->Link[PARENT] = parentp;
+      tmp->gender       = way;
+      }
+
+    tmp                 = parentp->Link[PARENT];
+    p->Link[PARENT]     = tmp;
+    p->gender           = parentp->gender;
+    if( tmp )
+      tmp->Link[p->gender] = p;
+
+    parentp->Link[PARENT] = p;
+    parentp->gender       = revway;
+    p->Link[revway]       = parentp;
+    }
+  } /* Rotate */
+
+static ubi_btNodePtr Splay( ubi_btNodePtr SplayWithMe )
+  /* ------------------------------------------------------------------------ **
+   * Move the node indicated by SplayWithMe to the root of the tree by
+   * splaying the tree.
+   *
+   *  Input:  SplayWithMe - A pointer to an ubi_btNode within a tree.
+   *
+   *  Output: A pointer to the root of the splay tree (i.e., the same as
+   *          SplayWithMe).
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr parent;
+
+  while( (parent = SplayWithMe->Link[PARENT]) )
+    {
+    if( parent->gender == SplayWithMe->gender )       /* Zig-Zig */
+      Rotate( parent );
+    else
+      {
+      if( EQUAL != parent->gender )                   /* Zig-Zag */
+        Rotate( SplayWithMe );
+      }
+    Rotate( SplayWithMe );                            /* Zig */
+    } /* while */
+  return( SplayWithMe );
+  } /* Splay */
+
+/* ========================================================================== **
+ * Exported utilities.
+ */
+
+ubi_trBool ubi_sptInsert( ubi_btRootPtr  RootPtr,
+                          ubi_btNodePtr  NewNode,
+                          ubi_btItemPtr  ItemPtr,
+                          ubi_btNodePtr *OldNode )
+  /* ------------------------------------------------------------------------ **
+   * This function uses a non-recursive algorithm to add a new element to the
+   * splay tree.
+   *
+   *  Input:   RootPtr  -  a pointer to the ubi_btRoot structure that indicates
+   *                       the root of the tree to which NewNode is to be added.
+   *           NewNode  -  a pointer to an ubi_btNode structure that is NOT
+   *                       part of any tree.
+   *           ItemPtr  -  A pointer to the sort key that is stored within
+   *                       *NewNode.  ItemPtr MUST point to information stored
+   *                       in *NewNode or an EXACT DUPLICATE.  The key data
+   *                       indicated by ItemPtr is used to place the new node
+   *                       into the tree.
+   *           OldNode  -  a pointer to an ubi_btNodePtr.  When searching
+   *                       the tree, a duplicate node may be found.  If
+   *                       duplicates are allowed, then the new node will
+   *                       be simply placed into the tree.  If duplicates
+   *                       are not allowed, however, then one of two things
+   *                       may happen.
+   *                       1) if overwritting *is not* allowed, this
+   *                          function will return FALSE (indicating that
+   *                          the new node could not be inserted), and
+   *                          *OldNode will point to the duplicate that is
+   *                          still in the tree.
+   *                       2) if overwritting *is* allowed, then this
+   *                          function will swap **OldNode for *NewNode.
+   *                          In this case, *OldNode will point to the node
+   *                          that was removed (thus allowing you to free
+   *                          the node).
+   *                          **  If you are using overwrite mode, ALWAYS  **
+   *                          ** check the return value of this parameter! **
+   *                 Note: You may pass NULL in this parameter, the
+   *                       function knows how to cope.  If you do this,
+   *                       however, there will be no way to return a
+   *                       pointer to an old (ie. replaced) node (which is
+   *                       a problem if you are using overwrite mode).
+   *
+   *  Output:  a boolean value indicating success or failure.  The function
+   *           will return FALSE if the node could not be added to the tree.
+   *           Such failure will only occur if duplicates are not allowed,
+   *           nodes cannot be overwritten, AND a duplicate key was found
+   *           within the tree.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr OtherP;
+
+  if( !(OldNode) )
+    OldNode = &OtherP;
+
+  if( ubi_btInsert( RootPtr, NewNode, ItemPtr, OldNode ) )
+    {
+    RootPtr->root = Splay( NewNode );
+    return( ubi_trTRUE );
+    }
+
+  /* Splay the unreplacable, duplicate keyed, unique, old node. */
+  RootPtr->root = Splay( (*OldNode) );
+  return( ubi_trFALSE );
+  } /* ubi_sptInsert */
+
+ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode )
+  /* ------------------------------------------------------------------------ **
+   * This function removes the indicated node from the tree.
+   *
+   *  Input:   RootPtr  -  A pointer to the header of the tree that contains
+   *                       the node to be removed.
+   *           DeadNode -  A pointer to the node that will be removed.
+   *
+   *  Output:  This function returns a pointer to the node that was removed
+   *           from the tree (ie. the same as DeadNode).
+   *
+   *  Note:    The node MUST be in the tree indicated by RootPtr.  If not,
+   *           strange and evil things will happen to your trees.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr p;
+
+  (void)Splay( DeadNode );                  /* Move dead node to root.        */
+  if( (p = DeadNode->Link[LEFT]) )          /* If left subtree exists...      */
+    {
+    ubi_btNodePtr q = DeadNode->Link[RIGHT];
+
+    p->Link[PARENT] = NULL;                 /* Left subtree node becomes root.*/
+    p->gender       = PARENT;
+    p               = ubi_btLast( p );      /* Find rightmost left tree node..*/
+    p->Link[RIGHT]  = q;                    /* ...attach right tree.          */
+    if( q )
+      q->Link[PARENT] = p;
+    RootPtr->root   = Splay( p );           /* Resplay at p.                  */
+    }
+  else
+    {
+    if( (p = DeadNode->Link[RIGHT]) )       /* No left, but right subtree...  */
+      {                                     /* ...exists...                   */
+      p->Link[PARENT] = NULL;               /* Right subtree root becomes...  */
+      p->gender       = PARENT;             /* ...overall tree root.          */
+      RootPtr->root   = p;
+      }
+    else
+      RootPtr->root = NULL;                 /* No subtrees => empty tree.     */
+    }
+
+  (RootPtr->count)--;                       /* Decrement node count.          */
+  return( DeadNode );                       /* Return pointer to pruned node. */
+  } /* ubi_sptRemove */
+
+ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
+                             ubi_btItemPtr FindMe,
+                             ubi_trCompOps CompOp )
+  /* ------------------------------------------------------------------------ **
+   * The purpose of ubi_btLocate() is to find a node or set of nodes given
+   * a target value and a "comparison operator".  The Locate() function is
+   * more flexible and (in the case of trees that may contain dupicate keys)
+   * more precise than the ubi_btFind() function.  The latter is faster,
+   * but it only searches for exact matches and, if the tree contains
+   * duplicates, Find() may return a pointer to any one of the duplicate-
+   * keyed records.
+   *
+   *  Input:
+   *     RootPtr  -  A pointer to the header of the tree to be searched.
+   *     FindMe   -  An ubi_btItemPtr that indicates the key for which to
+   *                 search.
+   *     CompOp   -  One of the following:
+   *                    CompOp     Return a pointer to the node with
+   *                    ------     ---------------------------------
+   *                   ubi_trLT - the last key value that is less
+   *                              than FindMe.
+   *                   ubi_trLE - the first key matching FindMe, or
+   *                              the last key that is less than
+   *                              FindMe.
+   *                   ubi_trEQ - the first key matching FindMe.
+   *                   ubi_trGE - the first key matching FindMe, or the
+   *                              first key greater than FindMe.
+   *                   ubi_trGT - the first key greater than FindMe.
+   *  Output:
+   *     A pointer to the node matching the criteria listed above under
+   *     CompOp, or NULL if no node matched the criteria.
+   *
+   *  Notes:
+   *     In the case of trees with duplicate keys, Locate() will behave as
+   *     follows:
+   *
+   *     Find:  3                       Find: 3
+   *     Keys:  1 2 2 2 3 3 3 3 3 4 4   Keys: 1 1 2 2 2 4 4 5 5 5 6
+   *                  ^ ^         ^                   ^ ^
+   *                 LT EQ        GT                 LE GE
+   *
+   *     That is, when returning a pointer to a node with a key that is LESS
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     LAST matching node.
+   *     When returning a pointer to a node with a key that is GREATER
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     FIRST matching node.
+   *
+   *  See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr p;
+
+  p = ubi_btLocate( RootPtr, FindMe, CompOp );
+  if( p )
+    RootPtr->root = Splay( p );
+  return( p );
+  } /* ubi_sptLocate */
+
+ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
+                           ubi_btItemPtr FindMe )
+  /* ------------------------------------------------------------------------ **
+   * This function performs a non-recursive search of a tree for any node
+   * matching a specific key.
+   *
+   *  Input:
+   *     RootPtr  -  a pointer to the header of the tree to be searched.
+   *     FindMe   -  a pointer to the key value for which to search.
+   *
+   *  Output:
+   *     A pointer to a node with a key that matches the key indicated by
+   *     FindMe, or NULL if no such node was found.
+   *
+   *  Note:   In a tree that allows duplicates, the pointer returned *might
+   *          not* point to the (sequentially) first occurance of the
+   *          desired key.  In such a tree, it may be more useful to use
+   *          ubi_sptLocate().
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_btNodePtr p;
+
+  p = ubi_btFind( RootPtr, FindMe );
+  if( p )
+    RootPtr->root = Splay( p );
+  return( p );
+  } /* ubi_sptFind */
+
+void ubi_sptSplay( ubi_btRootPtr RootPtr,
+                   ubi_btNodePtr SplayMe )
+  /* ------------------------------------------------------------------------ **
+   *  This function allows you to splay the tree at a given node, thus moving
+   *  the node to the top of the tree.
+   *
+   *  Input:
+   *     RootPtr  -  a pointer to the header of the tree to be splayed.
+   *     SplayMe  -  a pointer to a node within the tree.  This will become
+   *                 the new root node.
+   *  Output: None.
+   *
+   *  Notes:  This is an uncharacteristic function for this group of modules
+   *          in that it provides access to the internal balancing routines,
+   *          which would normally be hidden.
+   *          Splaying the tree will not damage it (assuming that I've done
+   *          *my* job), but there is overhead involved.  I don't recommend
+   *          that you use this function unless you understand the underlying
+   *          Splay Tree principles involved.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  RootPtr->root = Splay( SplayMe );
+  } /* ubi_sptSplay */
+
+int ubi_sptModuleID( int size, char *list[] )
+  /* ------------------------------------------------------------------------ **
+   * Returns a set of strings that identify the module.
+   *
+   *  Input:  size  - The number of elements in the array <list>.
+   *          list  - An array of pointers of type (char *).  This array
+   *                  should, initially, be empty.  This function will fill
+   *                  in the array with pointers to strings.
+   *  Output: The number of elements of <list> that were used.  If this value
+   *          is less than <size>, the values of the remaining elements are
+   *          not guaranteed.
+   *
+   *  Notes:  Please keep in mind that the pointers returned indicate strings
+   *          stored in static memory.  Don't free() them, don't write over
+   *          them, etc.  Just read them.
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( size > 0 )
+    {
+    list[0] = ModuleID;
+    if( size > 1 )
+      return( 1 + ubi_btModuleID( --size, &(list[1]) ) );
+    return( 1 );
+    }
+  return( 0 );
+  } /* ubi_sptModuleID */
+
+/* ================================ The End ================================= */
diff --git a/source/ubi_SplayTree.h b/source/ubi_SplayTree.h
new file mode 100644 (file)
index 0000000..6a17a19
--- /dev/null
@@ -0,0 +1,339 @@
+#ifndef ubi_SplayTree_H
+#define ubi_SplayTree_H
+/* ========================================================================== **
+ *                              ubi_SplayTree.h
+ *
+ *  Copyright (C) 1993,1995 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *
+ *  This module implements "splay" trees.  Splay trees are binary trees
+ *  that are rearranged (splayed) whenever a node is accessed.  The
+ *  splaying process *tends* to make the tree bushier (improves balance),
+ *  and the nodes that are accessed most frequently *tend* to be closer to
+ *  the top.
+ *
+ *  References: "Self-Adjusting Binary Search Trees", by Daniel Sleator and
+ *              Robert Tarjan.  Journal of the Association for Computing
+ *              Machinery Vol 32, No. 3, July 1985 pp. 652-686
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * $Log: ubi_SplayTree.h,v $
+ * Revision 1.1  1997/10/09 04:09:55  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 2.5  1997/07/26 04:15:46  crh
+ * + Cleaned up a few minor syntax annoyances that gcc discovered for me.
+ * + Changed ubi_TRUE and ubi_FALSE to ubi_trTRUE and ubi_trFALSE.
+ *
+ * Revision 2.4  1997/06/03 05:22:56  crh
+ * Changed TRUE and FALSE to ubi_TRUE and ubi_FALSE to avoid causing
+ * problems.
+ *
+ * Revision 2.3  1995/10/03 22:19:37  CRH
+ * Ubisized!
+ * Also, added the function ubi_sptSplay().
+ *
+ * Revision 2.1  95/03/09  23:55:04  CRH
+ * Added the ModuleID static string and function.  These modules are now
+ * self-identifying.
+ * 
+ * Revision 2.0  95/02/27  22:34:55  CRH
+ * This module was updated to match the interface changes made to the
+ * ubi_BinTree module.  In particular, the interface to the Locate() function
+ * has changed.  See ubi_BinTree for more information on changes and new
+ * functions.
+ *
+ * The revision number was also upped to match ubi_BinTree.
+ *
+ *
+ * Revision 1.0  93/10/15  22:59:36  CRH
+ * With this revision, I have added a set of #define's that provide a single,
+ * standard API to all existing tree modules.  Until now, each of the three
+ * existing modules had a different function and typedef prefix, as follows:
+ *
+ *       Module        Prefix
+ *     ubi_BinTree     ubi_bt
+ *     ubi_AVLtree     ubi_avl
+ *     ubi_SplayTree   ubi_spt
+ *
+ * To further complicate matters, only those portions of the base module
+ * (ubi_BinTree) that were superceeded in the new module had the new names.
+ * For example, if you were using ubi_AVLtree, the AVL node structure was
+ * named "ubi_avlNode", but the root structure was still "ubi_btRoot".  Using
+ * SplayTree, the locate function was called "ubi_sptLocate", but the next
+ * and previous functions remained "ubi_btNext" and "ubi_btPrev".
+ *
+ * This was not too terrible if you were familiar with the modules and knew
+ * exactly which tree model you wanted to use.  If you wanted to be able to
+ * change modules (for speed comparisons, etc), things could get messy very
+ * quickly.
+ *
+ * So, I have added a set of defined names that get redefined in any of the
+ * descendant modules.  To use this standardized interface in your code,
+ * simply replace all occurances of "ubi_bt", "ubi_avl", and "ubi_spt" with
+ * "ubi_tr".  The "ubi_tr" names will resolve to the correct function or
+ * datatype names for the module that you are using.  Just remember to
+ * include the header for that module in your program file.  Because these
+ * names are handled by the preprocessor, there is no added run-time
+ * overhead.
+ *
+ * Note that the original names do still exist, and can be used if you wish
+ * to write code directly to a specific module.  This should probably only be
+ * done if you are planning to implement a new descendant type, such as
+ * red/black trees.  CRH
+ *
+ * Revision 0.0  93/04/21  23:07:13  CRH
+ * Initial version, written by Christopher R. Hertel.
+ * This module implements Splay Trees using the ubi_BinTree module as a basis.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_BinTree.h" /* Base binary tree functions, types, etc.  */
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_trBool ubi_sptInsert( ubi_btRootPtr  RootPtr,
+                          ubi_btNodePtr  NewNode,
+                          ubi_btItemPtr  ItemPtr,
+                          ubi_btNodePtr *OldNode );
+  /* ------------------------------------------------------------------------ **
+   * This function uses a non-recursive algorithm to add a new element to the
+   * splay tree.
+   *
+   *  Input:   RootPtr  -  a pointer to the ubi_btRoot structure that indicates
+   *                       the root of the tree to which NewNode is to be added.
+   *           NewNode  -  a pointer to an ubi_btNode structure that is NOT
+   *                       part of any tree.
+   *           ItemPtr  -  A pointer to the sort key that is stored within
+   *                       *NewNode.  ItemPtr MUST point to information stored
+   *                       in *NewNode or an EXACT DUPLICATE.  The key data
+   *                       indicated by ItemPtr is used to place the new node
+   *                       into the tree.
+   *           OldNode  -  a pointer to an ubi_btNodePtr.  When searching
+   *                       the tree, a duplicate node may be found.  If
+   *                       duplicates are allowed, then the new node will
+   *                       be simply placed into the tree.  If duplicates
+   *                       are not allowed, however, then one of two things
+   *                       may happen.
+   *                       1) if overwritting *is not* allowed, this
+   *                          function will return FALSE (indicating that
+   *                          the new node could not be inserted), and
+   *                          *OldNode will point to the duplicate that is
+   *                          still in the tree.
+   *                       2) if overwritting *is* allowed, then this
+   *                          function will swap **OldNode for *NewNode.
+   *                          In this case, *OldNode will point to the node
+   *                          that was removed (thus allowing you to free
+   *                          the node).
+   *                          **  If you are using overwrite mode, ALWAYS  **
+   *                          ** check the return value of this parameter! **
+   *                 Note: You may pass NULL in this parameter, the
+   *                       function knows how to cope.  If you do this,
+   *                       however, there will be no way to return a
+   *                       pointer to an old (ie. replaced) node (which is
+   *                       a problem if you are using overwrite mode).
+   *
+   *  Output:  a boolean value indicating success or failure.  The function
+   *           will return FALSE if the node could not be added to the tree.
+   *           Such failure will only occur if duplicates are not allowed,
+   *           nodes cannot be overwritten, AND a duplicate key was found
+   *           within the tree.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_sptRemove( ubi_btRootPtr RootPtr, ubi_btNodePtr DeadNode );
+  /* ------------------------------------------------------------------------ **
+   * This function removes the indicated node from the tree.
+   *
+   *  Input:   RootPtr  -  A pointer to the header of the tree that contains
+   *                       the node to be removed.
+   *           DeadNode -  A pointer to the node that will be removed.
+   *
+   *  Output:  This function returns a pointer to the node that was removed
+   *           from the tree (ie. the same as DeadNode).
+   *
+   *  Note:    The node MUST be in the tree indicated by RootPtr.  If not,
+   *           strange and evil things will happen to your trees.
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_sptLocate( ubi_btRootPtr RootPtr,
+                             ubi_btItemPtr FindMe,
+                             ubi_trCompOps CompOp );
+  /* ------------------------------------------------------------------------ **
+   * The purpose of ubi_btLocate() is to find a node or set of nodes given
+   * a target value and a "comparison operator".  The Locate() function is
+   * more flexible and (in the case of trees that may contain dupicate keys)
+   * more precise than the ubi_btFind() function.  The latter is faster,
+   * but it only searches for exact matches and, if the tree contains
+   * duplicates, Find() may return a pointer to any one of the duplicate-
+   * keyed records.
+   *
+   *  Input:
+   *     RootPtr  -  A pointer to the header of the tree to be searched.
+   *     FindMe   -  An ubi_btItemPtr that indicates the key for which to
+   *                 search.
+   *     CompOp   -  One of the following:
+   *                    CompOp     Return a pointer to the node with
+   *                    ------     ---------------------------------
+   *                   ubi_trLT - the last key value that is less
+   *                              than FindMe.
+   *                   ubi_trLE - the first key matching FindMe, or
+   *                              the last key that is less than
+   *                              FindMe.
+   *                   ubi_trEQ - the first key matching FindMe.
+   *                   ubi_trGE - the first key matching FindMe, or the
+   *                              first key greater than FindMe.
+   *                   ubi_trGT - the first key greater than FindMe.
+   *  Output:
+   *     A pointer to the node matching the criteria listed above under
+   *     CompOp, or NULL if no node matched the criteria.
+   *
+   *  Notes:
+   *     In the case of trees with duplicate keys, Locate() will behave as
+   *     follows:
+   *
+   *     Find:  3                       Find: 3
+   *     Keys:  1 2 2 2 3 3 3 3 3 4 4   Keys: 1 1 2 2 2 4 4 5 5 5 6
+   *                  ^ ^         ^                   ^ ^
+   *                 LT EQ        GT                 LE GE
+   *
+   *     That is, when returning a pointer to a node with a key that is LESS
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     LAST matching node.
+   *     When returning a pointer to a node with a key that is GREATER
+   *     THAN the target key (FindMe), Locate() will return a pointer to the
+   *     FIRST matching node.
+   *
+   *  See Also: ubi_btFind(), ubi_btFirstOf(), ubi_btLastOf().
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_btNodePtr ubi_sptFind( ubi_btRootPtr RootPtr,
+                           ubi_btItemPtr FindMe );
+  /* ------------------------------------------------------------------------ **
+   * This function performs a non-recursive search of a tree for any node
+   * matching a specific key.
+   *
+   *  Input:
+   *     RootPtr  -  a pointer to the header of the tree to be searched.
+   *     FindMe   -  a pointer to the key value for which to search.
+   *
+   *  Output:
+   *     A pointer to a node with a key that matches the key indicated by
+   *     FindMe, or NULL if no such node was found.
+   *
+   *  Note:   In a tree that allows duplicates, the pointer returned *might
+   *          not* point to the (sequentially) first occurance of the
+   *          desired key.  In such a tree, it may be more useful to use
+   *          ubi_sptLocate().
+   * ------------------------------------------------------------------------ **
+   */
+
+void ubi_sptSplay( ubi_btRootPtr RootPtr,
+                   ubi_btNodePtr SplayMe );
+  /* ------------------------------------------------------------------------ **
+   *  This function allows you to splay the tree at a given node, thus moving
+   *  the node to the top of the tree.
+   *
+   *  Input:
+   *     RootPtr  -  a pointer to the header of the tree to be splayed.
+   *     SplayMe  -  a pointer to a node within the tree.  This will become
+   *                 the new root node.
+   *  Output: None.
+   *
+   *  Notes:  This is an uncharacteristic function for this group of modules
+   *          in that it provides access to the internal balancing routines,
+   *          which would normally be hidden.
+   *          Splaying the tree will not damage it (assuming that I've done
+   *          *my* job), but there is overhead involved.  I don't recommend
+   *          that you use this function unless you understand the underlying
+   *          Splay Tree principles involved.
+   * ------------------------------------------------------------------------ **
+   */
+
+int ubi_sptModuleID( int size, char *list[] );
+  /* ------------------------------------------------------------------------ **
+   * Returns a set of strings that identify the module.
+   *
+   *  Input:  size  - The number of elements in the array <list>.
+   *          list  - An array of pointers of type (char *).  This array
+   *                  should, initially, be empty.  This function will fill
+   *                  in the array with pointers to strings.
+   *  Output: The number of elements of <list> that were used.  If this value
+   *          is less than <size>, the values of the remaining elements are
+   *          not guaranteed.
+   *
+   *  Notes:  Please keep in mind that the pointers returned indicate strings
+   *          stored in static memory.  Don't free() them, don't write over
+   *          them, etc.  Just read them.
+   * ------------------------------------------------------------------------ **
+   */
+
+/* -------------------------------------------------------------------------- **
+ * Masquarade...
+ *
+ * This set of defines allows you to write programs that will use any of the
+ * implemented binary tree modules (currently BinTree, AVLtree, and SplayTree).
+ * Instead of using ubi_bt..., use ubi_tr..., and select the tree type by
+ * including the appropriate module header.
+ */
+
+#undef ubi_trInsert
+#undef ubi_trRemove
+#undef ubi_trLocate
+#undef ubi_trFind
+#undef ubi_trModuleID
+
+#define ubi_trInsert( Rp, Nn, Ip, On ) \
+        ubi_sptInsert( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Nn), \
+                       (ubi_btItemPtr)(Ip), (ubi_btNodePtr *)(On) )
+
+#define ubi_trRemove( Rp, Dn ) \
+        ubi_sptRemove( (ubi_btRootPtr)(Rp), (ubi_btNodePtr)(Dn) )
+
+#define ubi_trLocate( Rp, Ip, Op ) \
+        ubi_sptLocate( (ubi_btRootPtr)(Rp), \
+                       (ubi_btItemPtr)(Ip), \
+                       (ubi_trCompOps)(Op) )
+
+#define ubi_trFind( Rp, Ip ) \
+        ubi_sptFind( (ubi_btRootPtr)(Rp), (ubi_btItemPtr)(Ip) )
+
+#define ubi_trModuleID( s, l ) ubi_sptModuleID( s, l )
+
+/* ================================ The End ================================= */
+#endif /* ubi_SplayTree_H */
+
+
+
+
+
diff --git a/source/ubi_dLinkList.c b/source/ubi_dLinkList.c
new file mode 100644 (file)
index 0000000..9c9ef3a
--- /dev/null
@@ -0,0 +1,152 @@
+/* ========================================================================== **
+ *                              ubi_dLinkList.c
+ *
+ *  Copyright (C) 1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *  This module implements simple doubly-linked lists.
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * $Log: ubi_dLinkList.c,v $
+ * Revision 1.1  1997/10/09 04:09:55  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 0.2  1997/10/08 03:07:21  crh
+ * Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
+ * macro, which was passing the wrong value for <After> to Insert().
+ *
+ * Revision 0.1  1997/10/07 04:34:07  crh
+ * Initial Revision.
+ *
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_dLinkList.h"
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr )
+  /* ------------------------------------------------------------------------ **
+   * Initialize a doubly-linked list header.
+   *
+   *  Input:  ListPtr - A pointer to the list structure that is to be
+   *                    initialized for use.
+   *
+   *  Output: A pointer to the initialized list header (i.e., same as
+   *          <ListPtr>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ListPtr->Head  = NULL;
+  ListPtr->Tail  = NULL;
+  ListPtr->count = 0;
+  return( ListPtr );
+  } /* ubi_dlInitList */
+
+ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
+                            ubi_dlNodePtr New,
+                            ubi_dlNodePtr After )
+  /* ------------------------------------------------------------------------ **
+   * Insert a new node into the list.
+   *
+   *  Input:  ListPtr - A pointer to the list into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the new node.
+   *          After   - NULL, or a pointer to a node that is already in the
+   *                    list.
+   *                    If NULL, then <New> will be added at the head of the
+   *                    list, else it will be added following <After>.
+   * 
+   *  Output: A pointer to the node that was inserted into the list (i.e.,
+   *          the same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( NULL == After )
+    {
+    New->Next           = ListPtr->Head;
+    New->Prev           = NULL;
+    if( NULL != ListPtr->Head )
+      ListPtr->Head->Prev = New;
+    else
+      ListPtr->Tail       = New;
+    ListPtr->Head       = New;
+    }
+  else
+    {
+    New->Next         = After->Next;
+    New->Prev         = After;
+    if( NULL != After->Next )
+      After->Next->Prev = New;
+    else
+      ListPtr->Tail       = New;
+    After->Next       = New;
+    }
+
+  ++(ListPtr->count);
+
+  return( New );
+  } /* ubi_dlInsert */
+
+ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old )
+  /* ------------------------------------------------------------------------ **
+   * Remove a node from the list.
+   *
+   *  Input:  ListPtr - A pointer to the list from which <Old> is to be
+   *                    removed.
+   *          Old     - A pointer to the node that is to be removed from the
+   *                    list.
+   *
+   *  Output: A pointer to the node that was removed (i.e., <Old>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( NULL != Old )
+    {
+    if( Old->Next )
+      Old->Next->Prev = Old->Prev;
+    else
+      ListPtr->Tail = Old->Prev;
+
+    if( Old->Prev )
+      Old->Prev->Next = Old->Next;
+    else
+      ListPtr->Head = Old->Next;
+
+    --(ListPtr->count);
+    }
+
+  return( Old );
+  } /* ubi_dlRemove */
+
+
+/* ================================ The End ================================= */
diff --git a/source/ubi_dLinkList.h b/source/ubi_dLinkList.h
new file mode 100644 (file)
index 0000000..8aafd99
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef ubi_dLinkList_H
+#define ubi_dLinkList_H
+/* ========================================================================== **
+ *                              ubi_dLinkList.h
+ *
+ *  Copyright (C) 1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *  This module implements simple doubly-linked lists.
+ * -------------------------------------------------------------------------- **
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * $Log: ubi_dLinkList.h,v $
+ * Revision 1.1  1997/10/09 04:09:56  crh
+ * This is my library of lists and trees.  My hope is to replace all of the
+ * hard coded linked lists that are currently used in Samba with calls to
+ * these modules.  This should make the code simpler, smaller, and (I hope)
+ * faster.  The tree code, in particular, should speed up processing where
+ * large lists are involved.
+ *
+ * Chris -)-----
+ *
+ * Revision 0.2  1997/10/08 03:08:16  crh
+ * Fixed a few forgotten link-ups in Insert(), and fixed the AddHead()
+ * macro, which was passing the wrong value for <After> to Insert().
+ *
+ * Revision 0.1  1997/10/07 04:34:38  crh
+ * Initial Revision.
+ *
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h>
+
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ *  ubi_dlNode    - This is the basic node structure.
+ *  ubi_dlNodePtr - Pointer to a node.
+ *  ubi_dlList    - This is the list header structure.
+ *  ubi_dlListPtr - Pointer to a List (i.e., a list header structure).
+ *
+ */
+
+typedef struct ubi_dlListNode
+  {
+  struct ubi_dlListNode *Next;
+  struct ubi_dlListNode *Prev;
+  } ubi_dlNode;
+
+typedef ubi_dlNode *ubi_dlNodePtr;
+
+typedef struct
+  {
+  ubi_dlNodePtr Head;
+  ubi_dlNodePtr Tail;
+  unsigned long count;
+  } ubi_dlList;
+
+typedef ubi_dlList *ubi_dlListPtr;
+
+/* ========================================================================== **
+ * Macros...
+ * 
+ *  ubi_dlAddHead - Add a new node at the head of the list.
+ *  ubi_dlAddTail - Add a new node at the tail of the list.
+ *  ubi_dlRemHead - Remove the node at the head of the list, if any.
+ *  ubi_dlRemTail - Remove the node at the tail of the list, if any.
+ *  ubi_dlFirst   - Return a pointer to the first node in the list, if any.
+ *  ubi_dlLast    - Return a pointer to the last node in the list, if any.
+ *  ubi_dlNext    - Given a node, return a pointer to the next node.
+ *  ubi_dlPrev    - Given a node, return a pointer to the previous node.
+ */
+
+#define ubi_dlAddHead( L, N ) ubi_dlInsert( (L), (N), NULL )
+
+#define ubi_dlAddTail( L, N ) ubi_dlInsert( (L), (N), ((L)->Tail) )
+
+#define ubi_dlRemHead( L ) ubi_dlRemove( (L), ((L)->Head) )
+
+#define ubi_dlRemTail( L ) ubi_dlRemove( (L), ((L)->Tail) )
+
+#define ubi_dlFirst( L ) ((L)->Head)
+
+#define ubi_dlLast( L )  ((L)->Tail)
+
+#define ubi_dlNext( N )  ((N)->Next)
+
+#define ubi_dlPrev( N )  ((N)->Prev)
+
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_dlListPtr ubi_dlInitList( ubi_dlListPtr ListPtr );
+  /* ------------------------------------------------------------------------ **
+   * Initialize a doubly-linked list header.
+   *
+   *  Input:  ListPtr - A pointer to the list structure that is to be
+   *                    initialized for use.
+   *
+   *  Output: A pointer to the initialized list header (i.e., same as
+   *          <ListPtr>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_dlNodePtr ubi_dlInsert( ubi_dlListPtr ListPtr,
+                            ubi_dlNodePtr New,
+                            ubi_dlNodePtr After );
+  /* ------------------------------------------------------------------------ **
+   * Insert a new node into the list.
+   *
+   *  Input:  ListPtr - A pointer to the list into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the new node.
+   *          After   - NULL, or a pointer to a node that is already in the
+   *                    list.
+   *                    If NULL, then <New> will be added at the head of the
+   *                    list, else it will be added following <After>.
+   * 
+   *  Output: A pointer to the node that was inserted into the list (i.e.,
+   *          the same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_dlNodePtr ubi_dlRemove( ubi_dlListPtr ListPtr, ubi_dlNodePtr Old );
+  /* ------------------------------------------------------------------------ **
+   * Remove a node from the list.
+   *
+   *  Input:  ListPtr - A pointer to the list from which <Old> is to be
+   *                    removed.
+   *          Old     - A pointer to the node that is to be removed from the
+   *                    list.
+   *
+   *  Output: A pointer to the node that was removed (i.e., <Old>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+
+/* ================================ The End ================================= */
+#endif /* ubi_dLinkList_H */