]> git.samba.org - tprouty/samba.git/commitdiff
Modified Files:
authorChristopher R. Hertel <crh@samba.org>
Thu, 30 Oct 1997 18:05:56 +0000 (18:05 +0000)
committerChristopher R. Hertel <crh@samba.org>
Thu, 30 Oct 1997 18:05:56 +0000 (18:05 +0000)
        ubiqx/Makefile ubiqx/README.UBI

Added new modules to the Makefile.  Changed the text of the README to
reflect the directory change.

Added Files:
        ubiqx/ubi_AVLtree.c ubiqx/ubi_AVLtree.h
        ubiqx/ubi_BinTree.c ubiqx/ubi_BinTree.h
        ubiqx/ubi_SplayTree.c ubiqx/ubi_SplayTree.h
        ubiqx/ubi_StackQueue.c ubiqx/ubi_StackQueue.h
        ubiqx/ubi_sLinkList.c ubiqx/ubi_sLinkList.h

This is the remainder of the toolkit.  A quick rundown:
  sLinkList  = A simple singly-linked list.
  StackQueue = Implements both a stack and a queue.
  dLinkList  = (Not added 'cause it's already there.)  A doubly-linked list.

  BinTree    = Base level binary tree module.  (No height balancing, just
               the basics.)
  AVLtree    = Descendant type of BinTree.  Implements a height-balanced
               (AVL) binary tree.
  SplayTree  = Descendant type of BinTree.  Implements a splay-balanced
               binary tree.

Renamed Files:
        ubiqx/COPYING.LGPL ==> ubiqx/COPYING.LIB

This matches the naming that GNU suggests.

13 files changed:
source/ubiqx/COPYING.LIB [moved from source/ubiqx/COPYING.LGPL with 100% similarity]
source/ubiqx/Makefile
source/ubiqx/README.UBI
source/ubiqx/ubi_AVLtree.c [new file with mode: 0644]
source/ubiqx/ubi_AVLtree.h [new file with mode: 0644]
source/ubiqx/ubi_BinTree.c [new file with mode: 0644]
source/ubiqx/ubi_BinTree.h [new file with mode: 0644]
source/ubiqx/ubi_SplayTree.c [new file with mode: 0644]
source/ubiqx/ubi_SplayTree.h [new file with mode: 0644]
source/ubiqx/ubi_StackQueue.c [new file with mode: 0644]
source/ubiqx/ubi_StackQueue.h [new file with mode: 0644]
source/ubiqx/ubi_sLinkList.c [new file with mode: 0644]
source/ubiqx/ubi_sLinkList.h [new file with mode: 0644]

index fba055ec965f9e452db9a5eeb7eeabdac490b675..ceba86651e8b13a2902a60af7545eb0e02e7ce82 100644 (file)
@@ -6,8 +6,10 @@
 ###########################################################################
 
 THIS_LIB = libubiqx.a
-THIS_OBJ = ubi_dLinkList.o
-LIB_INCS = ubi_dLinkList.h
+THIS_OBJ = ubi_AVLtree.o ubi_SplayTree.o ubi_BinTree.o \
+           ubi_dLinkList.o ubi_StackQueue.o ubi_sLinkList.o
+LIB_INCS = ubi_AVLtree.h ubi_SplayTree.h ubi_BinTree.h \
+           ubi_dLinkList.h ubi_StackQueue.h ubi_sLinkList.h
 
 export THIS_LIB
 export THIS_OBJ
@@ -17,3 +19,8 @@ include ../Makefile.lib
 
 proto:
        @echo Prototype for $@ are not automatically generated
+
+
+
+
+
index c4a69e40d3fb6fbefbabd42e6286d54146e5f4d1..2c1c0430fb964bd8229ba3c8945c249ae5b42c4d 100644 (file)
@@ -1,14 +1,14 @@
 Thu Oct 16 11:07:18 CDT 1997
 
-Files in the source directory which begin with the prefix "ubi_" are
-licensed under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE
-(LGPL).  A copy of the LGPL should also be included in this directory
-under the name COPYING.LGPL.  If this file is not present, you can
-obtain a copy of the LGPL by writing to the Free Software Foundation,
+Files in the samba/source/ubiqx directory which begin with the prefix
+"ubi_" are licensed under the terms of the GNU LIBRARY GENERAL PUBLIC
+LICENSE (LGPL).  A copy of the LGPL should also be included in this
+directory under the name COPYING.LIB.  If this file is not present, you
+can obtain a copy of the LGPL by writing to the Free Software Foundation,
 Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-See http://www.interads.co.uk/~crh/ubiqx/ for additional available
-modules.
+See http://www.interads.co.uk/~crh/ubiqx/ for more info and additional
+available modules. 
 
 Chris Hertel
 Samba Team
diff --git a/source/ubiqx/ubi_AVLtree.c b/source/ubiqx/ubi_AVLtree.c
new file mode 100644 (file)
index 0000000..29ecc74
--- /dev/null
@@ -0,0 +1,689 @@
+/* ========================================================================== **
+ *                              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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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\
+\tRevision: 2.4\n\
+\tDate: 1997/07/26 04:36:20\n\
+\tAuthor: 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/ubiqx/ubi_AVLtree.h b/source/ubiqx/ubi_AVLtree.h
new file mode 100644 (file)
index 0000000..b86f24a
--- /dev/null
@@ -0,0 +1,331 @@
+#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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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/ubiqx/ubi_BinTree.c b/source/ubiqx/ubi_BinTree.c
new file mode 100644 (file)
index 0000000..68e819a
--- /dev/null
@@ -0,0 +1,1032 @@
+/* ========================================================================== **
+ *                              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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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\
+\tRevision: 2.4\n\
+\tDate: 1997/07/26 04:11:10\n\
+\tAuthor: 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/ubiqx/ubi_BinTree.h b/source/ubiqx/ubi_BinTree.h
new file mode 100644 (file)
index 0000000..ee51298
--- /dev/null
@@ -0,0 +1,735 @@
+#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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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/ubiqx/ubi_SplayTree.c b/source/ubiqx/ubi_SplayTree.c
new file mode 100644 (file)
index 0000000..88be2ba
--- /dev/null
@@ -0,0 +1,462 @@
+/* ========================================================================== **
+ *                              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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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\
+\tRevision: 2.5\n\
+\tDate: 1997/07/26 04:15:42\n\
+\tAuthor: 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/ubiqx/ubi_SplayTree.h b/source/ubiqx/ubi_SplayTree.h
new file mode 100644 (file)
index 0000000..7585d53
--- /dev/null
@@ -0,0 +1,329 @@
+#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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * 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/ubiqx/ubi_StackQueue.c b/source/ubiqx/ubi_StackQueue.c
new file mode 100644 (file)
index 0000000..19e4f78
--- /dev/null
@@ -0,0 +1,149 @@
+/* ========================================================================== **
+ *                              ubi_StackQueue.c
+ *
+ *  Copyright (C) 1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *  This module implements simple queues and stacks using a singly linked
+ *  list.
+ * -------------------------------------------------------------------------- **
+ *
+ *  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.
+ *
+ * -------------------------------------------------------------------------- **
+ *  This module uses a singly-linked list to implement both a queue and a
+ *  stack.  For a queue, entries are added at the tail and removed from the
+ *  head of the list.  For a stack, the entries are entered and removed from
+ *  the head of the list. A traversal of the list will always start at the
+ *  head of the list and proceed toward the tail.  This is all mind-numbingly
+ *  simple, but I'm surprised by the number of programs out there which
+ *  re-implement this a dozen or so times.
+ *
+ *  Note:  When the list header is initialized, the Tail pointer is set to
+ *         point to the Head pointer.  This simplifies the InsTail function
+ *         at little or no cost to InsHead or Remove.  The one problem is
+ *         that you can't initialize a stack or queue headerby simply zeroing
+ *         it out.  One sure way to initialize the header is to call
+ *         ubi_sqInit().  Another option would be something like this:
+ *
+ *         static ubi_sqList MyList = { NULL, (ubi_sqNodePtr)&MyList, 0 };
+ *
+ *         See ubi_sqInit() and the ubi_sqList structure for more info.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.1  1997/10/24 02:47:52  crh
+ * Initial revision.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_StackQueue.h"
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_sqListPtr ubi_sqInit( ubi_sqListPtr ListPtr )
+  /* ------------------------------------------------------------------------ **
+   * Initialize a stack & queue header.
+   *
+   *  Input:  ListPtr - A pointer to the list header 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  = (ubi_sqNodePtr)ListPtr;
+  ListPtr->count = 0;
+  return( ListPtr );
+  } /* ubi_sqInit */
+
+ubi_sqNodePtr ubi_sqInsHead( ubi_sqListPtr ListPtr, ubi_sqNodePtr New )
+  /* ------------------------------------------------------------------------ **
+   * Insert a new node at the head of the list (push).
+   *
+   *  Input:  ListPtr - A pointer to the stack into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the node that is to be pushed onto the
+   *                    stack.
+   *
+   *  Output: A pointer to the node that was added to the list (i.e., same
+   *          same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  if( NULL == ListPtr->Head )   /* If list is empty, must change tail ptr. */
+    ListPtr->Tail = New;
+  New->Next     = ListPtr->Head;
+  ListPtr->Head = New;
+  ++(ListPtr->count);
+  return( New );
+  } /* ubi_sqInsHead */
+
+ubi_sqNodePtr ubi_sqInsTail( ubi_sqListPtr ListPtr, ubi_sqNodePtr New )
+  /* ------------------------------------------------------------------------ **
+   * Add a new node to the tail of the list (enqueue).
+   *
+   *  Input:  ListPtr - A pointer to the queue into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the node that is to be enqueued.
+   *
+   *  Output: A pointer to the node that was inserted into the queue (i.e.,
+   *          the same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ListPtr->Tail->Next = New;
+  ListPtr->Tail       = New;
+  New->Next           = NULL;
+  ++(ListPtr->count);
+  return( New );
+  } /* ubi_sqInsTail */
+
+ubi_sqNodePtr ubi_sqRemove( ubi_sqListPtr ListPtr )
+  /* ------------------------------------------------------------------------ **
+   * Remove the frontmost entry from the queue, or topmost entry from the
+   * stack.
+   *
+   *  Input:  ListPtr - A pointer to the list from which the node is to be
+   *                     removed.
+   *
+   *  Output: A pointer to the node that was removed.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_sqNodePtr Old = ListPtr->Head;
+
+  if( NULL != Old )
+    {
+    if( NULL == Old->Next )
+      ListPtr->Tail = (ubi_sqNodePtr)ListPtr;
+    ListPtr->Head = Old->Next;
+    --(ListPtr->count);
+    }
+  return( Old );
+  } /* ubi_sqRemove */
+
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_StackQueue.h b/source/ubiqx/ubi_StackQueue.h
new file mode 100644 (file)
index 0000000..69fe7be
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef ubi_StackQueue_H
+#define ubi_StackQueue_H
+/* ========================================================================== **
+ *                              ubi_StackQueue.h
+ *
+ *  Copyright (C) 1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *  This module implements simple queues and stacks using a singly linked
+ *  list.
+ * -------------------------------------------------------------------------- **
+ *
+ *  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.
+ *
+ * -------------------------------------------------------------------------- **
+ *  This module uses a singly-linked list to implement both a queue and a
+ *  stack.  For a queue, entries are added at the tail and removed from the
+ *  head of the list.  For a stack, the entries are entered and removed from
+ *  the head of the list. A traversal of the list will always start at the
+ *  head of the list and proceed toward the tail.  This is all mind-numbingly
+ *  simple, but I'm surprised by the number of programs out there which
+ *  re-implement this a dozen or so times.
+ *
+ *  Note:  When the list header is initialized, the Tail pointer is set to
+ *         point to the Head pointer.  This simplifies the InsTail function
+ *         at little or no cost to InsHead or Remove.  The one problem is
+ *         that you can't initialize a stack or queue headerby simply zeroing
+ *         it out.  One sure way to initialize the header is to call
+ *         ubi_sqInit().  Another option would be something like this:
+ *
+ *         static ubi_sqList MyList = { NULL, (ubi_sqNodePtr)&MyList, 0 };
+ *
+ *         See ubi_sqInit() and the ubi_sqList structure for more info.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.1  1997/10/24 02:48:23  crh
+ * Initial revision.
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h>
+
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ *  ubi_sqNode      - This is the basic node structure.
+ *  ubi_sqNodePtr   - Pointer to a node.
+ *  ubi_sqList      - This is the stack & queue header structure.
+ *  ubi_sqListPtr   - Pointer to a stack & queue header.
+ *
+ */
+
+typedef struct ubi_sqListNode
+  {
+  struct ubi_sqListNode *Next;
+  } ubi_sqNode;
+
+typedef ubi_sqNode *ubi_sqNodePtr;
+
+typedef struct
+  {
+  ubi_sqNodePtr Head;
+  ubi_sqNodePtr Tail;
+  unsigned long count;
+  } ubi_sqList;
+
+typedef ubi_sqList *ubi_sqListPtr;
+
+/* ========================================================================== **
+ * Macros...
+ * 
+ *  ubi_sqEnqueue - Add a new node at the tail of a queue.
+ *  ubi_sqDequeue - Remove a node from the head of the queue.
+ *  ubi_sqPush    - Add a new node at the head of the queue.
+ *  ubi_sqPop     - Remove a node from the head of the queue (same as Dequeue). 
+ *  ubi_sqFirst   - Return a pointer to the frontmost node in the queue.
+ *  ubi_sqNext    - Given a node, return a pointer to the next node.
+ *  ubi_sqLast    - Return a pointer to the last (valid) node in the queue.
+ *
+ *  Note that all of these provide type casting of the parameters.  The
+ *  Enqueue/Dequeue macros are nothing more than nice front-ends to the
+ *  Insert and Remove operations.
+ *
+ */
+
+#define ubi_sqEnqueue( L, N ) \
+        ubi_sqInsTail( (ubi_sqListPtr)(L), (ubi_sqNodePtr)(N) )
+
+#define ubi_sqDequeue( L ) ubi_sqRemove( (ubi_sqListPtr)(L) )
+
+#define ubi_sqPush( L, N ) \
+        ubi_sqInsHead( (ubi_sqListPtr)(L), (ubi_sqNodePtr)(N) )
+
+#define ubi_sqPop ubi_sqDequeue
+
+#define ubi_sqFirst( L ) (((ubi_sqListPtr)(L))->Head)
+
+#define ubi_sqNext( N )  (((ubi_sqNodePtr)(N))->Next)
+
+#define ubi_sqLast( L )  \
+    ( (((ubi_sqListPtr)(L))->Head) ? (((ubi_sqListPtr)(L))->Tail) : NULL )
+
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_sqListPtr ubi_sqInit( ubi_sqListPtr ListPtr );
+  /* ------------------------------------------------------------------------ **
+   * Initialize a stack & queue header.
+   *
+   *  Input:  ListPtr - A pointer to the list header that is to be
+   *                    initialized for use.
+   *
+   *  Output: A pointer to the initialized list header (i.e., same as
+   *          <ListPtr>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_sqNodePtr ubi_sqInsHead( ubi_sqListPtr ListPtr, ubi_sqNodePtr New );
+  /* ------------------------------------------------------------------------ **
+   * Insert a new node at the head of the list (push).
+   *
+   *  Input:  ListPtr - A pointer to the stack into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the node that is to be pushed onto the
+   *                    stack.
+   *
+   *  Output: A pointer to the node that was added to the list (i.e., same
+   *          same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_sqNodePtr ubi_sqInsTail( ubi_sqListPtr ListPtr, ubi_sqNodePtr New );
+  /* ------------------------------------------------------------------------ **
+   * Add a new node to the tail of the list (enqueue).
+   *
+   *  Input:  ListPtr - A pointer to the queue into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the node that is to be enqueued.
+   *
+   *  Output: A pointer to the node that was inserted into the queue (i.e.,
+   *          the same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_sqNodePtr ubi_sqRemove( ubi_sqListPtr ListPtr );
+  /* ------------------------------------------------------------------------ **
+   * Remove the frontmost entry from the queue, or topmost entry from the
+   * stack.
+   *
+   *  Input:  ListPtr - A pointer to the list from which the node is to be
+   *                     removed.
+   *
+   *  Output: A pointer to the node that was removed.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+/* ================================ The End ================================= */
+#endif /* ubi_StackQueue_H */
diff --git a/source/ubiqx/ubi_sLinkList.c b/source/ubiqx/ubi_sLinkList.c
new file mode 100644 (file)
index 0000000..5414d5f
--- /dev/null
@@ -0,0 +1,112 @@
+/* ========================================================================== **
+ *                              ubi_sLinkList.c
+ *
+ *  Copyright (C) 1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *  This module implements a really simple singly-linked list.
+ * -------------------------------------------------------------------------- **
+ *
+ *  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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.2  1997/10/21 03:35:18  crh
+ * Added parameter <After> in function Insert().  Made necessary changes
+ * to macro AddHead() and added macro AddHere().
+ *
+ * Revision 0.1  1997/10/16 02:53:45  crh
+ * Initial Revision.
+ *
+ * ========================================================================== **
+ */
+
+#include "ubi_sLinkList.h"
+
+/* ========================================================================== **
+ * Functions...
+ */
+
+ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr )
+  /* ------------------------------------------------------------------------ **
+   * Initialize a singly-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->count = 0;
+  return( ListPtr );
+  } /* ubi_slInitList */
+
+ubi_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
+                            ubi_slNodePtr New,
+                            ubi_slNodePtr After )
+  /* ------------------------------------------------------------------------ **
+   * Insert a new node at the head of the list.
+   *
+   *  Input:  ListPtr - A pointer to the list into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the node that is to be added to the list.
+   *          After   - Pointer to a list in a node after which the new node
+   *                    will be inserted.  If NULL, then the new node will
+   *                    be added at the head of the list.
+   *
+   *  Output: A pointer to the node that was inserted into the list (i.e.,
+   *          the same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_slNodePtr *PredPtr;
+
+  PredPtr = ( NULL == After ) ? &(ListPtr->Head) : &(After->Next);
+  New->Next = *PredPtr;
+  *PredPtr  = New;
+  ++(ListPtr->count);
+  return( New );
+  } /* ubi_slInsert */
+
+ubi_slNodePtr ubi_slRemove( ubi_slListPtr ListPtr )
+  /* ------------------------------------------------------------------------ **
+   * Remove a node from the head of the list.
+   *
+   *  Input:  ListPtr - A pointer to the list from which the node is to be
+   *                    removed.
+   *
+   *  Output: A pointer to the node that was removed.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+  {
+  ubi_slNodePtr Old = ListPtr->Head;
+
+  if( NULL != Old )
+    {
+    ListPtr->Head = Old->Next;
+    --(ListPtr->count);
+    }
+  return( Old );
+  } /* ubi_slRemove */
+
+
+/* ================================ The End ================================= */
diff --git a/source/ubiqx/ubi_sLinkList.h b/source/ubiqx/ubi_sLinkList.h
new file mode 100644 (file)
index 0000000..7d546f0
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef ubi_sLinkList_H
+#define ubi_sLinkList_H
+/* ========================================================================== **
+ *                              ubi_sLinkList.h
+ *
+ *  Copyright (C) 1997 by Christopher R. Hertel
+ *
+ *  Email: crh@ubiqx.mn.org
+ * -------------------------------------------------------------------------- **
+ *  This module implements a really simple singly-linked list.
+ * -------------------------------------------------------------------------- **
+ *
+ *  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.
+ *
+ * -------------------------------------------------------------------------- **
+ *
+ * Revision 0.2  1997/10/21 03:36:14  crh
+ * Added parameter <After> in function Insert().  Made necessary changes
+ * to macro AddHead() and added macro AddHere().
+ *
+ * Revision 0.1  1997/10/16 02:54:08  crh
+ * Initial Revision.
+ *
+ * ========================================================================== **
+ */
+
+#include <stdlib.h>
+
+
+/* ========================================================================== **
+ * Typedefs...
+ *
+ *  ubi_slNode    - This is the basic node structure.
+ *  ubi_slNodePtr - Pointer to a node.
+ *  ubi_slList    - This is the list header structure.
+ *  ubi_slListPtr - Pointer to a List (i.e., a list header structure).
+ *
+ */
+
+typedef struct ubi_slListNode
+  {
+  struct ubi_slListNode *Next;
+  } ubi_slNode;
+
+typedef ubi_slNode *ubi_slNodePtr;
+
+typedef struct
+  {
+  ubi_slNodePtr Head;
+  unsigned long count;
+  } ubi_slList;
+
+typedef ubi_slList *ubi_slListPtr;
+
+/* ========================================================================== **
+ * Macros...
+ * 
+ *  ubi_slAddHead - Add a new node at the head of the list.
+ *  ubi_slRemHead - Remove the node at the head of the list, if any.
+ *  ubi_slFirst   - Return a pointer to the first node in the list, if any.
+ *  ubi_slNext    - Given a node, return a pointer to the next node.
+ *
+ *  Note that all of these provide type casting of the parameters.  The
+ *  Add and Rem macros are nothing more than nice front-ends to the
+ *  Insert and Remove operations.
+ *
+ */
+
+#define ubi_slAddHead( L, N ) \
+        ubi_slInsert( (ubi_slListPtr)(L), (ubi_slNodePtr)(N), NULL )
+
+#define ubi_slAddHere( L, N, P ) \
+        ubi_slInsert( (ubi_slListPtr)(L), \
+                      (ubi_slNodePtr)(N), \
+                      (ubi_slNodePtr)(P) )
+
+#define ubi_slRemHead( L ) ubi_slRemove( (ubi_slListPtr)(L) )
+
+#define ubi_slFirst( L ) (((ubi_slListPtr)(L))->Head)
+
+#define ubi_slNext( N )  (((ubi_slNodePtr)(N))->Next)
+
+
+/* ========================================================================== **
+ * Function prototypes...
+ */
+
+ubi_slListPtr ubi_slInitList( ubi_slListPtr ListPtr );
+  /* ------------------------------------------------------------------------ **
+   * Initialize a singly-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_slNodePtr ubi_slInsert( ubi_slListPtr ListPtr,
+                            ubi_slNodePtr New,
+                            ubi_slNodePtr After );
+  /* ------------------------------------------------------------------------ **
+   * Insert a new node at the head of the list.
+   *
+   *  Input:  ListPtr - A pointer to the list into which the node is to
+   *                    be inserted.
+   *          New     - Pointer to the node that is to be added to the list.
+   *          After   - Pointer to a list in a node after which the new node
+   *                    will be inserted.  If NULL, then the new node will
+   *                    be added at the head of the list.
+   *
+   *  Output: A pointer to the node that was inserted into the list (i.e.,
+   *          the same as <New>).
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+ubi_slNodePtr ubi_slRemove( ubi_slListPtr ListPtr );
+  /* ------------------------------------------------------------------------ **
+   * Remove a node from the head of the list.
+   *
+   *  Input:  ListPtr - A pointer to the list from which the node is to be
+   *                    removed.
+   *
+   *  Output: A pointer to the node that was removed.
+   *
+   * ------------------------------------------------------------------------ **
+   */
+
+/* ================================ The End ================================= */
+#endif /* ubi_sLinkList_H */