Index: /trunk/configure
===================================================================
--- /trunk/configure	(revision 1269)
+++ /trunk/configure	(revision 1270)
@@ -14950,5 +14950,5 @@
 
 
-ac_config_files="$ac_config_files Makefile packages/Makefile src/Makefile src/core/Makefile src/core2/Makefile src/objects/Makefile gui/Makefile gui/apps/Makefile gui/apps/about gui/apps/rappture gui/apps/rappture-csh.env gui/apps/rappture.env gui/apps/rerun gui/apps/simsim gui/apps/xmldiff gui/pkgIndex.tcl gui/scripts/Makefile lang/Makefile lang/perl/Makefile lang/perl/Makefile.PL lang/python/Makefile lang/python/setup.py lang/matlab/Makefile lang/octave/Makefile lang/octave/RpOctaveInterface.h lang/ruby/Makefile lang/ruby/build.rb lang/tcl/Makefile lang/tcl/pkgIndex.tcl lang/tcl/src/Makefile lang/tcl/scripts/Makefile lang/tcl/tests/Makefile lib/Makefile examples/3D/Makefile examples/Makefile examples/app-fermi/2.0/Makefile examples/app-fermi/Makefile examples/app-fermi/cee/Makefile examples/app-fermi/fortran/Makefile examples/app-fermi/matlab/Makefile examples/app-fermi/matlab/compiled/Makefile examples/app-fermi/matlab/uncompiled/Makefile examples/app-fermi/octave/Makefile examples/app-fermi/perl/Makefile examples/app-fermi/python/Makefile examples/app-fermi/ruby/Makefile examples/app-fermi/tcl/Makefile examples/app-fermi/wrapper/Makefile examples/app-fermi/wrapper/cee/Makefile examples/app-fermi/wrapper/python/Makefile examples/app-fermi/wrapper/tcl/Makefile examples/c-example/Makefile examples/canvas/Makefile examples/demo.bash examples/graph/Makefile examples/objects/Makefile examples/objects/dxWriter/Makefile examples/objects/floatBuffer/Makefile examples/zoo/Makefile examples/zoo/binary/Makefile examples/zoo/boolean/Makefile examples/zoo/choice/Makefile examples/zoo/cloud/Makefile examples/zoo/cloud/matlab/Makefile examples/zoo/curve/Makefile examples/zoo/enable/Makefile examples/zoo/field/Makefile examples/zoo/group/Makefile examples/zoo/image/Makefile examples/zoo/image/docs/Makefile examples/zoo/image/examples/Makefile examples/zoo/integer/Makefile examples/zoo/integer2/Makefile examples/zoo/loader/Makefile examples/zoo/loader/examples/Makefile examples/zoo/loadrun/Makefile examples/zoo/log/Makefile examples/zoo/note/Makefile examples/zoo/note/docs/Makefile examples/zoo/number/Makefile examples/zoo/number2/Makefile examples/zoo/phase/Makefile examples/zoo/sequence/Makefile examples/zoo/sequence/examples/Makefile examples/zoo/string/Makefile examples/zoo/structure/Makefile examples/zoo/structure/examples/Makefile examples/zoo/table/Makefile examples/zoo/unirect2d/Makefile test/Makefile test/src/Makefile"
+ac_config_files="$ac_config_files Makefile packages/Makefile src/Makefile src/core/Makefile src/core2/Makefile src/objects/Makefile src/objects/RpHash.h gui/Makefile gui/apps/Makefile gui/apps/about gui/apps/rappture gui/apps/rappture-csh.env gui/apps/rappture.env gui/apps/rerun gui/apps/simsim gui/apps/xmldiff gui/pkgIndex.tcl gui/scripts/Makefile lang/Makefile lang/perl/Makefile lang/perl/Makefile.PL lang/python/Makefile lang/python/setup.py lang/matlab/Makefile lang/octave/Makefile lang/octave/RpOctaveInterface.h lang/ruby/Makefile lang/ruby/build.rb lang/tcl/Makefile lang/tcl/pkgIndex.tcl lang/tcl/src/Makefile lang/tcl/scripts/Makefile lang/tcl/tests/Makefile lib/Makefile examples/3D/Makefile examples/Makefile examples/app-fermi/2.0/Makefile examples/app-fermi/Makefile examples/app-fermi/cee/Makefile examples/app-fermi/fortran/Makefile examples/app-fermi/matlab/Makefile examples/app-fermi/matlab/compiled/Makefile examples/app-fermi/matlab/uncompiled/Makefile examples/app-fermi/octave/Makefile examples/app-fermi/perl/Makefile examples/app-fermi/python/Makefile examples/app-fermi/ruby/Makefile examples/app-fermi/tcl/Makefile examples/app-fermi/wrapper/Makefile examples/app-fermi/wrapper/cee/Makefile examples/app-fermi/wrapper/python/Makefile examples/app-fermi/wrapper/tcl/Makefile examples/c-example/Makefile examples/canvas/Makefile examples/demo.bash examples/graph/Makefile examples/objects/Makefile examples/objects/dxWriter/Makefile examples/objects/floatBuffer/Makefile examples/zoo/Makefile examples/zoo/binary/Makefile examples/zoo/boolean/Makefile examples/zoo/choice/Makefile examples/zoo/cloud/Makefile examples/zoo/cloud/matlab/Makefile examples/zoo/curve/Makefile examples/zoo/enable/Makefile examples/zoo/field/Makefile examples/zoo/group/Makefile examples/zoo/image/Makefile examples/zoo/image/docs/Makefile examples/zoo/image/examples/Makefile examples/zoo/integer/Makefile examples/zoo/integer2/Makefile examples/zoo/loader/Makefile examples/zoo/loader/examples/Makefile examples/zoo/loadrun/Makefile examples/zoo/log/Makefile examples/zoo/note/Makefile examples/zoo/note/docs/Makefile examples/zoo/number/Makefile examples/zoo/number2/Makefile examples/zoo/phase/Makefile examples/zoo/sequence/Makefile examples/zoo/sequence/examples/Makefile examples/zoo/string/Makefile examples/zoo/structure/Makefile examples/zoo/structure/examples/Makefile examples/zoo/table/Makefile examples/zoo/unirect2d/Makefile test/Makefile test/src/Makefile"
 
 cat >confcache <<\_ACEOF
@@ -15527,4 +15527,5 @@
     "src/core2/Makefile") CONFIG_FILES="$CONFIG_FILES src/core2/Makefile" ;;
     "src/objects/Makefile") CONFIG_FILES="$CONFIG_FILES src/objects/Makefile" ;;
+    "src/objects/RpHash.h") CONFIG_FILES="$CONFIG_FILES src/objects/RpHash.h" ;;
     "gui/Makefile") CONFIG_FILES="$CONFIG_FILES gui/Makefile" ;;
     "gui/apps/Makefile") CONFIG_FILES="$CONFIG_FILES gui/apps/Makefile" ;;
Index: /trunk/configure.in
===================================================================
--- /trunk/configure.in	(revision 1269)
+++ /trunk/configure.in	(revision 1270)
@@ -1,3 +1,4 @@
-AC_INIT([Rappture], [1.1], [rappture@nanohub.org])
+AC_INIT([Rappture],[1.1],[rappture@nanohub.org])
+dnl AC_CONFIG_HEADER(src/core/RpConfig.h)
 AC_CONFIG_AUX_DIR(cf)
 
@@ -35,10 +36,10 @@
 AC_PROG_F77([g77 gfortran f77 fort77 f90 xlf xlf90 fl32])
 
-AC_LANG_C
+AC_LANG([C])
 
 AC_HEADER_STDC
 AC_CHECK_FUNC(atol,,AC_MSG_ERROR(oops! no atol ?!?))
 
-AC_LANG_CPLUSPLUS
+AC_LANG([C++])
 
 AC_CHECK_LIB(m, main,,AC_MSG_ERROR(librappture requires libm))
@@ -94,5 +95,5 @@
 done
 if test "x${make_command}" = "x" ; then
-  AC_ERROR([Requires GNU make. You can specify a version with \$MAKE])
+  AC_MSG_ERROR([Requires GNU make. You can specify a version with \$MAKE])
 fi
 AC_SUBST(MAKE, ${make_command})
@@ -483,5 +484,5 @@
 
 dnl read Makefile.in and write Makefile
-AC_OUTPUT( [
+AC_CONFIG_FILES([
     Makefile
     packages/Makefile
@@ -490,4 +491,5 @@
     src/core2/Makefile
     src/objects/Makefile
+    src/objects/RpHash.h
     gui/Makefile
     gui/apps/Makefile
@@ -576,2 +578,3 @@
     test/src/Makefile
 ])
+AC_OUTPUT
Index: /trunk/src/core/Makefile.in
===================================================================
--- /trunk/src/core/Makefile.in	(revision 1269)
+++ /trunk/src/core/Makefile.in	(revision 1270)
@@ -1,6 +1,6 @@
 
 bindir          = @bindir@
-datadir		= @datadir@
-datarootdir	= @datarootdir@
+datadir         = @datadir@
+datarootdir     = @datarootdir@
 exec_prefix     = @exec_prefix@
 includedir      = @includedir@
@@ -8,9 +8,9 @@
 mandir          = @mandir@
 prefix          = @prefix@
-srcdir		= @srcdir@
-incdir		= $(prefix)/include
+srcdir          = @srcdir@
+incdir          = $(prefix)/include
 
-INSTALL		= @INSTALL@
-MKDIR_P		= @MKDIR_P@
+INSTALL         = @INSTALL@
+MKDIR_P         = @MKDIR_P@
 
 CXX             = @CXX@
@@ -19,5 +19,5 @@
 # We need to link with g++ on MacOS 10.4
 CC              = $(CXX)
-CCC		= @CC@
+CCC             = @CC@
 CFLAGS_DEBUG    = @CFLAGS_DEBUG@ -Wall
 CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@
@@ -31,18 +31,20 @@
 CFLAGS          = @CFLAGS@
 
-CC_SWITCHES	= $(CFLAGS) $(CFLAGS_DEBUG) $(INCLUDES) $(DEFINES)
-CXX_SWITCHES	= $(CFLAGS) $(CFLAGS_DEBUG) $(INCLUDES) $(DEFINES)
+CC_SWITCHES     = $(CFLAGS) $(CFLAGS_DEBUG) $(INCLUDES) $(DEFINES)
+CXX_SWITCHES    = $(CFLAGS) $(CFLAGS_DEBUG) $(INCLUDES) $(DEFINES)
 
-INCLUDES	= -I$(srcdir) \
-		  -I$(includedir)
+INCLUDES        = \
+		-I. \
+		-I$(srcdir) \
+		-I$(includedir)
 
-RANLIB 		= @RANLIB@
-AR 		= ar
-VPATH		= $(srcdir):$(srcdir)/scew:$(srcdir)/b64
-RM		= rm -f
+RANLIB          = @RANLIB@
+AR              = ar
+VPATH           = $(srcdir):$(srcdir)/scew:$(srcdir)/b64
+RM              = rm -f
 
 CDEBUGFLAGS     = -g -Wall
 
-LIBS		= -lexpat -lz -lm -lstdc++
+LIBS            = -lexpat -lz -lm -lstdc++
 
 HEADERS = \
@@ -76,5 +78,5 @@
 		RpUtilsFInterface.h \
 		RpUtilsFStubs.h \
-		rappture.h 
+		rappture.h
 
 SCEW_HEADERS 	= \
@@ -94,6 +96,6 @@
 		xprint.h \
 		xtree.h \
-	        writer.h \
-	        xerror.h 
+		writer.h \
+		xerror.h
 
 # Build the scew and b64 libraries directly into Rappture for now.  
@@ -116,5 +118,5 @@
 		xhandler.o \
 		xparser.o \
-		xprint.o 
+		xprint.o
 
 OBJS = 		\
@@ -144,8 +146,8 @@
 		$(B64_OBJS)
 
-name		= rappture
-libname 	= lib$(name)
-lib		= $(libname).a
-shared_lib	= $(libname)$(SHLIB_SUFFIX)
+name        = rappture
+libname     = lib$(name)
+lib         = $(libname).a
+shared_lib  = $(libname)$(SHLIB_SUFFIX)
 
 all: $(lib) $(shared_lib)
Index: /trunk/src/objects/Makefile.in
===================================================================
--- /trunk/src/objects/Makefile.in	(revision 1269)
+++ /trunk/src/objects/Makefile.in	(revision 1270)
@@ -14,5 +14,6 @@
 
 CXX             = @CXX@
-CC              = @CXX@
+CC              = $(CXX)
+CCC             = @CC@
 CFLAGS_DEBUG    = @CFLAGS_DEBUG@
 CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@
@@ -29,4 +30,6 @@
 
 INCLUDES	= \
+		-I. \
+		-I../core \
 		-I$(srcdir) \
 		-I$(srcdir)/../core \
@@ -48,5 +51,13 @@
 
 HEADERS = \
-		RpBoolean.h \
+		RpChain.h \
+		RpInt.h \
+		RpHash.h \
+		RpHashHelper.h \
+		RpNumber.h \
+		RpPool.h \
+		RpVariable.h
+
+#		RpBoolean.h \
 		RpAbout.h \
 		RpNumber.h \
@@ -57,5 +68,12 @@
 
 OBJS = \
-		RpAbout.o \
+		RpChain.o \
+		RpHash.o \
+		RpHashHelper.o \
+		RpNumber.o \
+		RpPool.o \
+		RpVariable.o
+
+#		RpAbout.o \
 		RpBoolean.o \
 		RpChoice.o \
@@ -93,5 +111,5 @@
 	$(CXX) $(CC_SWITCHES) -c $? 
 .c.o: 
-	$(CC) $(CC_SWITCHES) -c $? 
+	$(CCC) $(CC_SWITCHES) -c $? 
 
 clean: 
Index: /trunk/src/objects/RpChain.c
===================================================================
--- /trunk/src/objects/RpChain.c	(revision 1270)
+++ /trunk/src/objects/RpChain.c	(revision 1270)
@@ -0,0 +1,445 @@
+/*
+ * bltChain.c --
+ *
+ *  The module implements a generic linked list package.
+ *
+ * Copyright 1991-1998 Lucent Technologies, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Lucent Technologies disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness.  In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ */
+
+#include "RpInt.h"
+#include "RpChain.h"
+
+#ifndef ALIGN
+#define ALIGN(a) \
+    (((size_t)a + (sizeof(double) - 1)) & (~(sizeof(double) - 1)))
+#endif /* ALIGN */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainCreate --
+ *
+ *  Creates a new linked list (chain) structure and initializes 
+ *  its pointers;
+ *
+ * Results:
+ *  Returns a pointer to the newly created chain structure.
+ *
+ *----------------------------------------------------------------------
+ */
+Rp_Chain *
+Rp_ChainCreate()
+{
+    Rp_Chain *chainPtr;
+
+    chainPtr = (Rp_Chain *) Rp_Malloc(sizeof(Rp_Chain));
+    if (chainPtr != NULL) {
+        Rp_ChainInit(chainPtr);
+    }
+    return chainPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainAllocLink --
+ *
+ *  Creates a new chain link.  Unlink Rp_ChainNewLink, this 
+ *  routine also allocates extra memory in the node for data.
+ *
+ * Results:
+ *  The return value is the pointer to the newly created entry.
+ *
+ *----------------------------------------------------------------------
+ */
+Rp_ChainLink *
+Rp_ChainAllocLink(extraSize)
+    unsigned int extraSize;
+{
+    Rp_ChainLink *linkPtr;
+    unsigned int linkSize;
+
+    linkSize = ALIGN(sizeof(Rp_ChainLink));
+    linkPtr = Rp_Calloc(1, linkSize + extraSize);
+    assert(linkPtr);
+    if (extraSize > 0) {
+        /* Point clientData at the memory beyond the normal structure. */
+        linkPtr->clientData = (ClientData)((char *)linkPtr + linkSize);
+    }
+    return linkPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainNewLink --
+ *
+ *  Creates a new link.
+ *
+ * Results:
+ *  The return value is the pointer to the newly created link.
+ *
+ *----------------------------------------------------------------------
+ */
+Rp_ChainLink *
+Rp_ChainNewLink()
+{
+    Rp_ChainLink *linkPtr;
+
+    linkPtr = (Rp_ChainLink *) Rp_Malloc(sizeof(Rp_ChainLink));
+    assert(linkPtr);
+    linkPtr->clientData = NULL;
+    linkPtr->nextPtr = linkPtr->prevPtr = NULL;
+    return linkPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainReset --
+ *
+ *  Removes all the links from the chain, freeing the memory for
+ *  each link.  Memory pointed to by the link (clientData) is not
+ *  freed.  It's the caller's responsibility to deallocate it.
+ *
+ * Results:
+ *  None.
+ *
+ *---------------------------------------------------------------------- 
+ */
+void
+Rp_ChainReset(chainPtr)
+    Rp_Chain *chainPtr;	/* Chain to clear */
+{
+    if (chainPtr != NULL) {
+        Rp_ChainLink *oldPtr;
+        Rp_ChainLink *linkPtr = chainPtr->headPtr;
+
+        while (linkPtr != NULL) {
+            oldPtr = linkPtr;
+            linkPtr = linkPtr->nextPtr;
+            Rp_Free(oldPtr);
+        }
+        Rp_ChainInit(chainPtr);
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainDestroy
+ *
+ *     Frees all the nodes from the chain and deallocates the memory
+ *     allocated for the chain structure itself.  It's assumed that
+ *     the chain was previous allocated by Rp_ChainCreate.
+ *
+ * Results:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_ChainDestroy(chainPtr)
+    Rp_Chain *chainPtr;
+{
+    if (chainPtr != NULL) {
+        Rp_ChainReset(chainPtr);
+        Rp_Free(chainPtr);
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainInit --
+ *
+ *  Initializes a linked list.
+ *
+ * Results:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_ChainInit(chainPtr)
+    Rp_Chain *chainPtr;
+{
+    chainPtr->nLinks = 0;
+    chainPtr->headPtr = chainPtr->tailPtr = NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainLinkAfter --
+ *
+ *  Inserts an entry following a given entry.
+ *
+ * Results:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_ChainLinkAfter(chainPtr, linkPtr, afterPtr)
+    Rp_Chain *chainPtr;
+    Rp_ChainLink *linkPtr, *afterPtr;
+{
+    if (chainPtr->headPtr == NULL) {
+        chainPtr->tailPtr = chainPtr->headPtr = linkPtr;
+    } else {
+        if (afterPtr == NULL) {
+            /* Prepend to the front of the chain */
+            linkPtr->nextPtr = chainPtr->headPtr;
+            linkPtr->prevPtr = NULL;
+            chainPtr->headPtr->prevPtr = linkPtr;
+            chainPtr->headPtr = linkPtr;
+        } else {
+            linkPtr->nextPtr = afterPtr->nextPtr;
+            linkPtr->prevPtr = afterPtr;
+            if (afterPtr == chainPtr->tailPtr) {
+                chainPtr->tailPtr = linkPtr;
+            } else {
+                afterPtr->nextPtr->prevPtr = linkPtr;
+            }
+            afterPtr->nextPtr = linkPtr;
+        }
+    }
+    chainPtr->nLinks++;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainLinkBefore --
+ *
+ *  Inserts a link preceding a given link.
+ *
+ * Results:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_ChainLinkBefore(chainPtr, linkPtr, beforePtr)
+    Rp_Chain *chainPtr;         /* Chain to contain new entry */
+    Rp_ChainLink *linkPtr;      /* New entry to be inserted */
+    Rp_ChainLink *beforePtr;    /* Entry to link before */
+{
+    if (chainPtr->headPtr == NULL) {
+        chainPtr->tailPtr = chainPtr->headPtr = linkPtr;
+    } else {
+        if (beforePtr == NULL) {
+            /* Append to the end of the chain. */
+            linkPtr->nextPtr = NULL;
+            linkPtr->prevPtr = chainPtr->tailPtr;
+            chainPtr->tailPtr->nextPtr = linkPtr;
+            chainPtr->tailPtr = linkPtr;
+        } else {
+            linkPtr->prevPtr = beforePtr->prevPtr;
+            linkPtr->nextPtr = beforePtr;
+            if (beforePtr == chainPtr->headPtr) {
+                chainPtr->headPtr = linkPtr;
+            } else {
+                beforePtr->prevPtr->nextPtr = linkPtr;
+            }
+            beforePtr->prevPtr = linkPtr;
+        }
+    }
+    chainPtr->nLinks++;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainUnlinkLink --
+ *
+ *	Unlinks a link from the chain. The link is not deallocated, 
+ *	but only removed from the chain.
+ *
+ * Results:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_ChainUnlinkLink(chainPtr, linkPtr)
+    Rp_Chain *chainPtr;
+    Rp_ChainLink *linkPtr;
+{
+    int unlinked;       /* Indicates if the link is actually
+                         * removed from the chain. */
+
+    unlinked = FALSE;
+    if (chainPtr->headPtr == linkPtr) {
+        chainPtr->headPtr = linkPtr->nextPtr;
+        unlinked = TRUE;
+    }
+    if (chainPtr->tailPtr == linkPtr) {
+        chainPtr->tailPtr = linkPtr->prevPtr;
+        unlinked = TRUE;
+    }
+    if (linkPtr->nextPtr != NULL) {
+        linkPtr->nextPtr->prevPtr = linkPtr->prevPtr;
+        unlinked = TRUE;
+    }
+    if (linkPtr->prevPtr != NULL) {
+        linkPtr->prevPtr->nextPtr = linkPtr->nextPtr;
+        unlinked = TRUE;
+    }
+    if (unlinked) {
+        chainPtr->nLinks--;
+    }
+    linkPtr->prevPtr = linkPtr->nextPtr = NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainDeleteLink --
+ *
+ *  Unlinks and also frees the given link.
+ *
+ * Results:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_ChainDeleteLink(chainPtr, linkPtr)
+    Rp_Chain *chainPtr;
+    Rp_ChainLink *linkPtr;
+{
+    Rp_ChainUnlinkLink(chainPtr, linkPtr);
+    Rp_Free(linkPtr);
+}
+
+Rp_ChainLink *
+Rp_ChainAppend(chainPtr, clientData)
+    Rp_Chain *chainPtr;
+    ClientData clientData;
+{
+    Rp_ChainLink *linkPtr;
+
+    linkPtr = Rp_ChainNewLink();
+    Rp_ChainLinkBefore(chainPtr, linkPtr, (Rp_ChainLink *)NULL);
+    Rp_ChainSetValue(linkPtr, clientData);
+    return linkPtr;
+}
+
+Rp_ChainLink *
+Rp_ChainPrepend(chainPtr, clientData)
+    Rp_Chain *chainPtr;
+    ClientData clientData;
+{
+    Rp_ChainLink *linkPtr;
+
+    linkPtr = Rp_ChainNewLink();
+    Rp_ChainLinkAfter(chainPtr, linkPtr, (Rp_ChainLink *)NULL);
+    Rp_ChainSetValue(linkPtr, clientData);
+    return linkPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainGetNthLink --
+ *
+ *  Find the link at the given position in the chain.
+ *
+ * Results:
+ *  Returns the pointer to the link, if that numbered link
+ *  exists. Otherwise NULL.
+ *
+ *----------------------------------------------------------------------
+ */
+Rp_ChainLink *
+Rp_ChainGetNthLink(chainPtr, position)
+    Rp_Chain *chainPtr; /* Chain to traverse */
+    int position;       /* Index of link to select from front
+                         * or back of the chain. */
+{
+    Rp_ChainLink *linkPtr;
+
+    if (chainPtr != NULL) {
+        for (linkPtr = chainPtr->headPtr; linkPtr != NULL;
+            linkPtr = linkPtr->nextPtr) {
+            if (position == 0) {
+                return linkPtr;
+            }
+            position--;
+        }
+    }
+    return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_ChainSort --
+ *
+ *  Sorts the chain according to the given comparison routine.
+ *
+ * Results:
+ *  None.
+ *
+ * Side Effects:
+ *  The chain is reordered.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_ChainSort(chainPtr, proc)
+    Rp_Chain *chainPtr;	/* Chain to traverse */
+    Rp_ChainCompareProc *proc;
+{
+    Rp_ChainLink **linkArr;
+    register Rp_ChainLink *linkPtr;
+    register int i;
+
+    if (chainPtr->nLinks < 2) {
+        return;
+    }
+    linkArr = (Rp_ChainLink **) Rp_Malloc(sizeof(Rp_ChainLink *) * (chainPtr->nLinks + 1));
+    if (linkArr == NULL) {
+        return;         /* Out of memory. */
+    }
+    i = 0;
+    for (linkPtr = chainPtr->headPtr; linkPtr != NULL;
+         linkPtr = linkPtr->nextPtr) {
+        linkArr[i++] = linkPtr;
+    }
+    qsort((char *)linkArr, chainPtr->nLinks, sizeof(Rp_ChainLink *),
+        (QSortCompareProc *)proc);
+
+    /* Rethread the chain. */
+    linkPtr = linkArr[0];
+    chainPtr->headPtr = linkPtr;
+    linkPtr->prevPtr = NULL;
+    for (i = 1; i < chainPtr->nLinks; i++) {
+        linkPtr->nextPtr = linkArr[i];
+        linkPtr->nextPtr->prevPtr = linkPtr;
+        linkPtr = linkPtr->nextPtr;
+    }
+    chainPtr->tailPtr = linkPtr;
+    linkPtr->nextPtr = NULL;
+    Rp_Free(linkArr);
+}
Index: /trunk/src/objects/RpChain.h
===================================================================
--- /trunk/src/objects/RpChain.h	(revision 1270)
+++ /trunk/src/objects/RpChain.h	(revision 1270)
@@ -0,0 +1,85 @@
+/*
+ * bltChain.h --
+ *
+ * Copyright 1993-2000 Lucent Technologies, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Lucent Technologies disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness.  In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ */
+#ifndef _RP_CHAIN_H
+#define _RP_CHAIN_H
+
+typedef struct Rp_ChainLinkStruct Rp_ChainLink;
+
+/*
+ * A Rp_ChainLink is the container structure for the Rp_Chain.
+ */
+
+struct Rp_ChainLinkStruct {
+    Rp_ChainLink *prevPtr;  /* Link to the previous link */
+    Rp_ChainLink *nextPtr;  /* Link to the next link */
+    ClientData clientData;  /* Pointer to the data object */
+};
+
+typedef int (Rp_ChainCompareProc) _ANSI_ARGS_((Rp_ChainLink **l1PtrPtr, 
+    Rp_ChainLink **l2PtrPtr));
+
+/*
+ * A Rp_Chain is a doubly chained list structure.
+ */
+typedef struct {
+    Rp_ChainLink *headPtr;  /* Pointer to first element in chain */
+    Rp_ChainLink *tailPtr;  /* Pointer to last element in chain */
+    int nLinks;             /* Number of elements in chain */
+} Rp_Chain;
+
+extern void Rp_ChainInit _ANSI_ARGS_((Rp_Chain * chainPtr));
+extern Rp_Chain *Rp_ChainCreate _ANSI_ARGS_(());
+extern void Rp_ChainDestroy _ANSI_ARGS_((Rp_Chain * chainPtr));
+extern Rp_ChainLink *Rp_ChainNewLink _ANSI_ARGS_((void));
+extern Rp_ChainLink *Rp_ChainAllocLink _ANSI_ARGS_((unsigned int extraSize));
+extern Rp_ChainLink *Rp_ChainAppend _ANSI_ARGS_((Rp_Chain * chainPtr,
+    ClientData clientData));
+extern Rp_ChainLink *Rp_ChainPrepend _ANSI_ARGS_((Rp_Chain * chainPtr,
+    ClientData clientData));
+extern void Rp_ChainReset _ANSI_ARGS_((Rp_Chain * chainPtr));
+extern void Rp_ChainLinkAfter _ANSI_ARGS_((Rp_Chain * chainPtr,
+    Rp_ChainLink * linkPtr, Rp_ChainLink * afterLinkPtr));
+extern void Rp_ChainLinkBefore _ANSI_ARGS_((Rp_Chain * chainPtr,
+    Rp_ChainLink * linkPtr, Rp_ChainLink * beforeLinkPtr));
+extern void Rp_ChainUnlinkLink _ANSI_ARGS_((Rp_Chain * chainPtr,
+    Rp_ChainLink * linkPtr));
+extern void Rp_ChainDeleteLink _ANSI_ARGS_((Rp_Chain * chainPtr,
+    Rp_ChainLink * linkPtr));
+extern Rp_ChainLink *Rp_ChainGetNthLink _ANSI_ARGS_((Rp_Chain * chainPtr, int n));
+extern void Rp_ChainSort _ANSI_ARGS_((Rp_Chain * chainPtr,
+    Rp_ChainCompareProc * proc));
+
+#define Rp_ChainGetLength(c)        (((c) == NULL) ? 0 : (c)->nLinks)
+#define Rp_ChainFirstLink(c)        (((c) == NULL) ? NULL : (c)->headPtr)
+#define Rp_ChainLastLink(c)         (((c) == NULL) ? NULL : (c)->tailPtr)
+#define Rp_ChainPrevLink(l)         ((l)->prevPtr)
+#define Rp_ChainNextLink(l)         ((l)->nextPtr)
+#define Rp_ChainGetValue(l)         ((l)->clientData)
+#define Rp_ChainSetValue(l, value)  ((l)->clientData = (ClientData)(value))
+#define Rp_ChainAppendLink(c, l) \
+    (Rp_ChainLinkBefore((c), (l), (Rp_ChainLink *)NULL))
+#define Rp_ChainPrependLink(c, l) \
+    (Rp_ChainLinkAfter((c), (l), (Rp_ChainLink *)NULL))
+
+#endif /* _RP_CHAIN_H */
Index: /trunk/src/objects/RpHash.c
===================================================================
--- /trunk/src/objects/RpHash.c	(revision 1270)
+++ /trunk/src/objects/RpHash.c	(revision 1270)
@@ -0,0 +1,1335 @@
+
+/*
+ * bltHash.c --
+ *
+ *
+ * This module implements an in-memory hash table for the BLT
+ * toolkit.  Built upon the Tcl hash table, it adds pool
+ * allocation 64-bit address handling, improved array hash
+ * function.
+ *
+ * Copyright 2001 Silicon Metrics Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Silicon Metrics disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness.  In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ *
+ * Bob Jenkins, 1996.  hash.c.  Public Domain.
+ * Bob Jenkins, 1997.  lookup8.c.  Public Domain.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * RCS: @(#) $Id: bltHash.c,v 1.10 2002/08/09 07:15:18 ghowlett Exp $
+ */
+
+#include <RpInt.h>
+
+#include <stdio.h>
+#include <string.h>
+/* The following header is required for LP64 compilation */
+#include <stdlib.h>
+
+#include "RpHash.h"
+
+/*
+ * When there are this many entries per bucket, on average, rebuild
+ * the hash table to make it larger.
+ */
+
+#define REBUILD_MULTIPLIER  3
+
+#if (SIZEOF_VOID_P == 8)
+#define RANDOM_INDEX        HashOneWord
+#define DOWNSHIFT_START     62
+#else
+
+/*
+ * The following macro takes a preliminary integer hash value and
+ * produces an index into a hash tables bucket list.  The idea is
+ * to make it so that preliminary values that are arbitrarily similar
+ * will end up in different buckets.  The hash function was taken
+ * from a random-number generator.
+ */
+#define RANDOM_INDEX(tablePtr, i) \
+    (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)
+#define DOWNSHIFT_START     28
+#endif
+
+/*
+ * Procedure prototypes for static procedures in this file:
+ */
+static Rp_Hash HashArray _ANSI_ARGS_((CONST void *key, size_t length));
+static Rp_HashEntry *ArrayFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key));
+static Rp_HashEntry *ArrayCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key, int *newPtr));
+static Rp_HashEntry *BogusFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key));
+static Rp_HashEntry *BogusCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key, int *newPtr));
+static Rp_Hash HashString _ANSI_ARGS_((CONST char *string));
+static void RebuildTable _ANSI_ARGS_((Rp_HashTable *tablePtr));
+static Rp_HashEntry *StringFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key));
+static Rp_HashEntry *StringCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key, int *newPtr));
+static Rp_HashEntry *OneWordFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key));
+static Rp_HashEntry *OneWordCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key, int *newPtr));
+
+#if (SIZEOF_VOID_P == 8)
+static Rp_Hash HashOneWord _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    CONST void *key));
+
+#endif /* SIZEOF_VOID_P == 8 */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HashString --
+ *
+ *  Compute a one-word summary of a text string, which can be
+ *  used to generate a hash index.
+ *
+ * Results:
+ *  The return value is a one-word summary of the information in
+ *  string.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+static Rp_Hash
+HashString(register CONST char *string) /* String from which to
+                                         * compute hash value. */
+{
+    register Rp_Hash result;
+    register Rp_Hash c;
+
+    /*
+     * I tried a zillion different hash functions and asked many other
+     * people for advice.  Many people had their own favorite functions,
+     * all different, but no-one had much idea why they were good ones.
+     * I chose the one below (multiply by 9 and add new character)
+     * because of the following reasons:
+     *
+     * 1. Multiplying by 10 is perfect for keys that are decimal strings,
+     *    and multiplying by 9 is just about as good.
+     * 2. Times-9 is (shift-left-3) plus (old).  This means that each
+     *    character's bits hang around in the low-order bits of the
+     *    hash value for ever, plus they spread fairly rapidly up to
+     *    the high-order bits to fill out the hash value.  This seems
+     *    to work well both for decimal and non-decimal strings.
+     */
+
+    result = 0;
+    while ((c = *string++) != 0) {
+        result += (result << 3) + c;
+    }
+    return (Rp_Hash)result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringFind --
+ *
+ *	Given a hash table with string keys, and a string key, find
+ *	the entry with a matching key.
+ *
+ * Results:
+ *	The return value is a token for the matching entry in the
+ *	hash table, or NULL if there was no matching entry.
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+static Rp_HashEntry *
+StringFind(
+    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
+    CONST void *key)        /* Key to use to find matching entry. */
+{
+    Rp_Hash hval;
+    register Rp_HashEntry *hPtr;
+    size_t hindex;
+
+    hval = HashString((char *)key);
+    hindex = hval & tablePtr->mask;
+
+    /*
+     * Search all of the entries in the appropriate bucket.
+     */
+
+    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
+        hPtr = hPtr->nextPtr) {
+        if (hPtr->hval == hval) {
+            register CONST char *p1, *p2;
+
+            for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
+                if (*p1 != *p2) {
+                    break;
+                }
+                if (*p1 == '\0') {
+                    return hPtr;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringCreate --
+ *
+ *  Given a hash table with string keys, and a string key, find
+ *  the entry with a matching key.  If there is no matching entry,
+ *  then create a new entry that does match.
+ *
+ * Results:
+ *  The return value is a pointer to the matching entry.  If this
+ *  is a newly-created entry, then *newPtr will be set to a non-zero
+ *  value;  otherwise *newPtr will be set to 0.  If this is a new
+ *  entry the value stored in the entry will initially be 0.
+ *
+ * Side effects:
+ *  A new entry may be added to the hash table.
+ *
+ *----------------------------------------------------------------------
+ */
+static Rp_HashEntry *
+StringCreate(
+    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
+    CONST void *key,        /* Key to use to find or create matching
+                             * entry. */
+    int *newPtr)            /* Store info here telling whether a new
+                             * entry was created. */
+{
+    Rp_Hash hval;
+    Rp_HashEntry **bucketPtr;
+    register Rp_HashEntry *hPtr;
+    size_t size, hindex;
+
+    hval = HashString(key);
+    hindex = hval & tablePtr->mask;
+
+    /*
+     * Search all of the entries in this bucket.
+     */
+
+    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
+        hPtr = hPtr->nextPtr) {
+        if (hPtr->hval == hval) {
+            register CONST char *p1, *p2;
+
+            for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
+                if (*p1 != *p2) {
+                    break;
+                }
+                if (*p1 == '\0') {
+                    *newPtr = FALSE;
+                    return hPtr;
+                }
+            }
+        }
+    }
+
+    /*
+     * Entry not found.  Add a new one to the bucket.
+     */
+
+    *newPtr = TRUE;
+    size = sizeof(Rp_HashEntry) + strlen(key) - sizeof(Rp_HashKey) + 1;
+    if (tablePtr->hPool != NULL) {
+        hPtr = Rp_PoolAllocItem(tablePtr->hPool, size);
+    } else {
+        hPtr = Rp_Malloc(size);
+    }
+    bucketPtr = tablePtr->buckets + hindex;
+    hPtr->nextPtr = *bucketPtr;
+    hPtr->hval = hval;
+    hPtr->clientData = 0;
+    strcpy(hPtr->key.string, key);
+    *bucketPtr = hPtr;
+    tablePtr->numEntries++;
+
+    /*
+     * If the table has exceeded a decent size, rebuild it with many
+     * more buckets.
+     */
+
+    if (tablePtr->numEntries >= tablePtr->rebuildSize) {
+        RebuildTable(tablePtr);
+    }
+    return hPtr;
+}
+
+#if (SIZEOF_VOID_P == 8)
+/*
+ *----------------------------------------------------------------------
+ *
+ * HashOneWord --
+ *
+ *  Compute a one-word hash value of a 64-bit word, which then can
+ *  be used to generate a hash index.
+ *
+ *  From Knuth, it's a multiplicative hash.  Multiplies an unsigned
+ *  64-bit value with the golden ratio (sqrt(5) - 1) / 2.  The
+ *  downshift value is 64 - n, when n is the log2 of the size of
+ *  the hash table.
+ *
+ * Results:
+ *  The return value is a one-word summary of the information in
+ *  64 bit word.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+static Rp_Hash
+HashOneWord(
+    Rp_HashTable *tablePtr,
+    CONST void *key)
+{
+    uint64_t a0, a1;
+    uint64_t y0, y1;
+    uint64_t y2, y3;
+    uint64_t p1, p2;
+    uint64_t result;
+    /* Compute key * GOLDEN_RATIO in 128-bit arithmetic */
+    a0 = (uint64_t)key & 0x00000000FFFFFFFF; 
+    a1 = (uint64_t)key >> 32;
+
+    y0 = a0 * 0x000000007f4a7c13;
+    y1 = a0 * 0x000000009e3779b9;
+    y2 = a1 * 0x000000007f4a7c13;
+    y3 = a1 * 0x000000009e3779b9;
+    y1 += y0 >> 32;     /* Can't carry */
+    y1 += y2;           /* Might carry */
+    if (y1 < y2) {
+        y3 += (1LL << 32);  /* Propagate */
+    }
+
+    /* 128-bit product: p1 = loword, p2 = hiword */
+    p1 = ((y1 & 0x00000000FFFFFFFF) << 32) + (y0 & 0x00000000FFFFFFFF);
+    p2 = y3 + (y1 >> 32);
+
+    /* Left shift the value downward by the size of the table */
+    if (tablePtr->downShift > 0) {
+        if (tablePtr->downShift < 64) {
+            result = ((p2 << (64 - tablePtr->downShift)) |
+                      (p1 >> (tablePtr->downShift & 63)));
+        } else {
+            result = p2 >> (tablePtr->downShift & 63);
+        }
+    } else {
+        result = p1;
+    }
+    /* Finally mask off the high bits */
+    return (Rp_Hash)(result & tablePtr->mask);
+}
+
+#endif /* SIZEOF_VOID_P == 8 */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * OneWordFind --
+ *
+ *  Given a hash table with one-word keys, and a one-word key,
+ *  find the entry with a matching key.
+ *
+ * Results:
+ *  The return value is a token for the matching entry in the
+ *  hash table, or NULL if there was no matching entry.
+ *
+ * Side effects:
+ *  None.
+ *
+ *---------------------------------------------------------------------- 
+ */
+static Rp_HashEntry *
+OneWordFind(
+    Rp_HashTable *tablePtr,     /* Table in which to lookup entry. */
+    register CONST void *key)   /* Key to use to find matching entry. */
+{
+    register Rp_HashEntry *hPtr;
+    size_t hindex;
+
+    hindex = RANDOM_INDEX(tablePtr, key);
+
+    /*
+     * Search all of the entries in the appropriate bucket.
+     */
+    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
+        hPtr = hPtr->nextPtr) {
+        if (hPtr->key.oneWordValue == key) {
+            return hPtr;
+        }
+    }
+    return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * OneWordCreate --
+ *
+ *  Given a hash table with one-word keys, and a one-word key, find
+ *  the entry with a matching key.  If there is no matching entry,
+ *  then create a new entry that does match.
+ *
+ * Results:
+ *  The return value is a pointer to the matching entry.  If this
+ *  is a newly-created entry, then *newPtr will be set to a non-zero
+ *  value;  otherwise *newPtr will be set to 0.  If this is a new
+ *  entry the value stored in the entry will initially be 0.
+ *
+ * Side effects:
+ *  A new entry may be added to the hash table.
+ *
+ *----------------------------------------------------------------------
+ */
+static Rp_HashEntry *
+OneWordCreate(
+    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
+    CONST void *key,        /* Key to use to find or create matching
+                             * entry. */
+    int *newPtr)            /* Store info here telling whether a new
+                             * entry was created. */
+{
+    Rp_HashEntry **bucketPtr;
+    register Rp_HashEntry *hPtr;
+    size_t hindex;
+
+    hindex = RANDOM_INDEX(tablePtr, key);
+
+    /*
+     * Search all of the entries in this bucket.
+     */
+    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
+        hPtr = hPtr->nextPtr) {
+        if (hPtr->key.oneWordValue == key) {
+            *newPtr = FALSE;
+            return hPtr;
+        }
+    }
+
+    /*
+     * Entry not found.  Add a new one to the bucket.
+     */
+
+    *newPtr = TRUE;
+    if (tablePtr->hPool != NULL) {
+        hPtr = Rp_PoolAllocItem(tablePtr->hPool, sizeof(Rp_HashEntry));
+    } else {
+        hPtr = Rp_Malloc(sizeof(Rp_HashEntry));
+    }
+    bucketPtr = tablePtr->buckets + hindex;
+    hPtr->nextPtr = *bucketPtr;
+    hPtr->hval = (Rp_Hash)key;
+    hPtr->clientData = 0;
+    hPtr->key.oneWordValue = (void *)key;   /* CONST XXXX */
+    *bucketPtr = hPtr;
+    tablePtr->numEntries++;
+
+    /*
+     * If the table has exceeded a decent size, rebuild it with many
+     * more buckets.
+     */
+
+    if (tablePtr->numEntries >= tablePtr->rebuildSize) {
+        RebuildTable(tablePtr);
+    }
+    return hPtr;
+}
+
+
+#if (SIZEOF_VOID_P == 4)
+/*
+ * --------------------------------------------------------------------
+ *
+ * MIX32 -- 
+ *
+ *      Bob Jenkins, 1996.  Public Domain.
+ *
+ *  Mix 3 32/64-bit values reversibly.  For every delta with one or
+ *  two bit set, and the deltas of all three high bits or all
+ *  three low bits, whether the original value of a,b,c is almost
+ *  all zero or is uniformly distributed, If mix() is run
+ *  forward or backward, at least 32 bits in a,b,c have at least
+ *  1/4 probability of changing.  * If mix() is run forward, every
+ *  bit of c will change between 1/3 and 2/3 of the time.  (Well,
+ *  22/100 and 78/100 for some 2-bit deltas.)  mix() was built out
+ *  of 36 single-cycle latency instructions in a structure that
+ *  could supported 2x parallelism, like so:
+ *
+ *      a -= b;
+ *      a -= c; x = (c>>13);
+ *      b -= c; a ^= x;
+ *      b -= a; x = (a<<8);
+ *      c -= a; b ^= x;
+ *      c -= b; x = (b>>13);
+ *      ...
+ *
+ *   Unfortunately, superscalar Pentiums and Sparcs can't take
+ *   advantage of that parallelism.  They've also turned some of
+ *   those single-cycle latency instructions into multi-cycle
+ *   latency instructions.  Still, this is the fastest good hash I
+ *   could find.  There were about 2^^68 to choose from.  I only
+ *   looked at a billion or so.
+ *
+ * -------------------------------------------------------------------- 
+ */
+#define MIX32(a,b,c) \
+	a -= b, a -= c, a ^= (c >> 13), \
+	b -= c, b -= a, b ^= (a <<  8), \
+	c -= a, c -= b, c ^= (b >> 13), \
+	a -= b, a -= c, a ^= (c >> 12), \
+	b -= c, b -= a, b ^= (a << 16), \
+	c -= a, c -= b, c ^= (b >>  5), \
+	a -= b, a -= c, a ^= (c >>  3), \
+	b -= c, b -= a, b ^= (a << 10), \
+	c -= a, c -= b, c ^= (b >> 15)
+
+#define GOLDEN_RATIO32	0x9e3779b9	/* An arbitrary value */
+
+/*
+ * --------------------------------------------------------------------
+ *
+ * HashArray --
+ *
+ *      Bob Jenkins, 1996.  Public Domain.
+ *
+ *  This works on all machines.  Length has to be measured in
+ *  unsigned longs instead of bytes.  It requires that
+ *
+ *    o The key be an array of unsigned ints.
+ *    o All your machines have the same endianness
+ *    o The length be the number of unsigned ints in the key.
+ *
+ * --------------------------------------------------------------------
+ */
+static Rp_Hash
+HashArray(
+    CONST void *key,
+    size_t length)      /* Length of the key in 32-bit words */
+{
+    register uint32_t a, b, c, len;
+    register uint32_t *arrayPtr = (uint32_t *)key;
+    /* Set up the internal state */
+    len = length;
+    a = b = GOLDEN_RATIO32; /* An arbitrary value */
+    c = 0;                  /* Previous hash value */
+
+    while (len >= 3) {      /* Handle most of the key */
+        a += arrayPtr[0];
+        b += arrayPtr[1];
+        c += arrayPtr[2];
+        MIX32(a, b, c);
+        arrayPtr += 3; len -= 3;
+    }
+    c += length;
+    /* And now the last 2 words */
+    /* Note that all the case statements fall through */
+    switch(len) {
+        /* c is reserved for the length */
+    case 2 : b += arrayPtr[1];
+    case 1 : a += arrayPtr[0];
+        /* case 0: nothing left to add */
+    }
+    MIX32(a, b, c);
+    return (Rp_Hash)c;
+}
+#endif /* SIZEOF_VOID_P == 4 */
+
+#if (SIZEOF_VOID_P == 8)
+
+/* 
+ * --------------------------------------------------------------------
+ *
+ * MIX64 --
+ *
+ *  Bob Jenkins, January 4 1997, Public Domain.  You can use
+ *  this free for any purpose.  It has no warranty.
+ *
+ *  Returns a 64-bit value.  Every bit of the key affects every
+ *  bit of the return value.  No funnels.  Every 1-bit and 2-bit
+ *  delta achieves avalanche.  About 41+5len instructions.
+ *
+ *  The best hash table sizes are powers of 2.  There is no need
+ *  to do mod a prime (mod is sooo slow!).  If you need less than
+ *  64 bits, use a bitmask.  For example, if you need only 10
+ *  bits, do h = (h & hashmask(10)); In which case, the hash table
+ *  should have hashsize(10) elements.
+ *
+ *  By Bob Jenkins, Jan 4 1997.  bob_jenkins@burtleburtle.net.
+ *  You may use this code any way you wish, private, educational,
+ *  or commercial, as long as this whole comment accompanies it.
+ *
+ *  See http://burtleburtle.net/bob/hash/evahash.html
+ *  Use for hash table lookup, or anything where one collision in
+ *  2^^64 * is acceptable.  Do NOT use for cryptographic purposes.
+ *
+ * --------------------------------------------------------------------
+ */
+
+#define MIX64(a,b,c) \
+	a -= b, a -= c, a ^= (c >> 43), \
+	b -= c, b -= a, b ^= (a <<  9), \
+	c -= a, c -= b, c ^= (b >>  8), \
+	a -= b, a -= c, a ^= (c >> 38), \
+	b -= c, b -= a, b ^= (a << 23), \
+	c -= a, c -= b, c ^= (b >>  5), \
+	a -= b, a -= c, a ^= (c >> 35), \
+	b -= c, b -= a, b ^= (a << 49), \
+	c -= a, c -= b, c ^= (b >> 11), \
+	a -= b, a -= c, a ^= (c >> 12), \
+	b -= c, b -= a, b ^= (a << 18), \
+	c -= a, c -= b, c ^= (b >> 22)
+
+#define GOLDEN_RATIO64	0x9e3779b97f4a7c13LL
+
+/*
+ * --------------------------------------------------------------------
+ *
+ * HashArray --
+ *
+ *  Bob Jenkins, January 4 1997, Public Domain.  You can use
+ *  this free for any purpose.  It has no warranty.
+ *
+ *  This works on all machines.  The length has to be measured in
+ *  64 bit words, instead of bytes.  It requires that
+ *
+ *    o The key be an array of 64 bit words (unsigned longs).
+ *    o All your machines have the same endianness.
+ *    o The length be the number of 64 bit words in the key.
+ *
+ * --------------------------------------------------------------------
+ */
+static Rp_Hash
+HashArray(
+    CONST void *key,
+    size_t length)      /* Length of key in 32-bit words. */
+{
+    register uint64_t a, b, c, len;
+    register uint32_t *iPtr = (uint32_t *)key;
+
+#ifdef WORDS_BIGENDIAN
+#define PACK(a,b)   ((uint64_t)(b) | ((uint64_t)(a) << 32))
+#else
+#define PACK(a,b)   ((uint64_t)(a) | ((uint64_t)(b) << 32))
+#endif
+    /* Set up the internal state */
+    len = length;           /* Length is the number of 64-bit words. */
+    a = b = GOLDEN_RATIO64; /* An arbitrary value */
+    c = 0;                  /* Previous hash value */
+
+    while (len >= 6) {      /* Handle most of the key */
+        a += PACK(iPtr[0], iPtr[1]);
+        b += PACK(iPtr[2], iPtr[3]);
+        c += PACK(iPtr[4], iPtr[5]);
+        MIX64(a,b,c);
+        iPtr += 6; len -= 6;
+    }
+    c += length;
+    /* And now the last 2 words */
+    /* Note that all the case statements fall through */
+    switch(len) {
+        /* c is reserved for the length */
+    case 5 :
+    case 4 :
+        a += PACK(iPtr[0], iPtr[1]);
+        b += PACK(iPtr[2], iPtr[3]);
+        iPtr += 4; len -= 4;
+        break;
+    case 3 :
+    case 2 :
+        a += PACK(iPtr[0], iPtr[1]);
+        iPtr += 2; len -= 2;
+ /* case 0: nothing left to add */
+    }
+    if (len > 0) {
+        b += iPtr[0];
+    }
+    MIX64(a,b,c);
+    return (Rp_Hash)c;
+}
+#endif /* SIZEOF_VOID_P == 8 */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ArrayFind --
+ *
+ *  Given a hash table with array-of-int keys, and a key, find
+ *  the entry with a matching key.
+ *
+ * Results:
+ *  The return value is a token for the matching entry in the
+ *  hash table, or NULL if there was no matching entry.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+static Rp_HashEntry *
+ArrayFind(
+    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
+    CONST void *key)        /* Key to use to find matching entry. */
+{
+    Rp_Hash hval;
+    register Rp_HashEntry *hPtr;
+    size_t hindex;
+
+    hval = HashArray(key, tablePtr->keyType);
+    hindex = hval & tablePtr->mask;
+    /*
+     * Search all of the entries in the appropriate bucket.
+     */
+
+    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
+        hPtr = hPtr->nextPtr) {
+        if (hPtr->hval == hval) {
+            register unsigned int *iPtr1, *iPtr2;
+            unsigned int count;
+
+            for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words,
+                 count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
+                if (count == 0) {
+                    return hPtr;
+                }
+                if (*iPtr1 != *iPtr2) {
+                    break;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ArrayCreate --
+ *
+ *  Given a hash table with one-word keys, and a one-word key, find
+ *  the entry with a matching key.  If there is no matching entry,
+ *  then create a new entry that does match.
+ *
+ * Results:
+ *  The return value is a pointer to the matching entry.  If this
+ *  is a newly-created entry, then *newPtr will be set to a non-zero
+ *  value;  otherwise *newPtr will be set to 0.  If this is a new
+ *  entry the value stored in the entry will initially be 0.
+ *
+ * Side effects:
+ *  A new entry may be added to the hash table.
+ *
+ *----------------------------------------------------------------------
+ */
+static Rp_HashEntry *
+ArrayCreate(
+    Rp_HashTable *tablePtr,     /* Table in which to lookup entry. */
+    register CONST void *key,   /* Key to use to find or create matching
+                                 * entry. */
+    int *newPtr)                /* Store info here telling whether a new
+                                 * entry was created. */
+{
+    Rp_Hash hval;
+    Rp_HashEntry **bucketPtr;
+    int count;
+    register Rp_HashEntry *hPtr;
+    register uint32_t *iPtr1, *iPtr2;
+    size_t size, hindex;
+
+    hval = HashArray(key, tablePtr->keyType);
+    hindex = hval & tablePtr->mask;
+
+    /*
+     * Search all of the entries in the appropriate bucket.
+     */
+    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
+        hPtr = hPtr->nextPtr) {
+        if (hPtr->hval == hval) {
+            for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words,
+                 count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
+                if (count == 0) {
+                    *newPtr = FALSE;
+                    return hPtr;
+                }
+                if (*iPtr1 != *iPtr2) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /*
+     * Entry not found.  Add a new one to the bucket.
+     */
+    *newPtr = TRUE;
+    /* We assume here that the size of the key is at least 2 words */
+    size = sizeof(Rp_HashEntry) + tablePtr->keyType * sizeof(uint32_t) -
+        sizeof(Rp_HashKey);
+    if (tablePtr->hPool != NULL) {
+        hPtr = Rp_PoolAllocItem(tablePtr->hPool, size);
+    } else {
+        hPtr = Rp_Malloc(size);
+    }
+    bucketPtr = tablePtr->buckets + hindex;
+    hPtr->nextPtr = *bucketPtr;
+    hPtr->hval = hval;
+    hPtr->clientData = 0;
+    count = tablePtr->keyType;
+    for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words;
+         count > 0; count--, iPtr1++, iPtr2++) {
+        *iPtr2 = *iPtr1;
+    }
+    *bucketPtr = hPtr;
+    tablePtr->numEntries++;
+
+    /*
+     * If the table has exceeded a decent size, rebuild it with many
+     * more buckets.
+     */
+    if (tablePtr->numEntries >= tablePtr->rebuildSize) {
+        RebuildTable(tablePtr);
+    }
+    return hPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * BogusFind --
+ *
+ *  This procedure is invoked when an Rp_FindHashEntry is called
+ *  on a table that has been deleted.
+ *
+ * Results:
+ *  If panic returns (which it shouldn't) this procedure returns
+ *  NULL.
+ *
+ * Side effects:
+ *  Generates a panic.
+ *
+ *----------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static Rp_HashEntry *
+BogusFind(
+    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
+    CONST void *key)        /* Key to use to find matching entry. */
+{
+    Rp_Panic("called Rp_FindHashEntry on deleted table");
+    return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * BogusCreate --
+ *
+ *  This procedure is invoked when an Rp_CreateHashEntry is called
+ *  on a table that has been deleted.
+ *
+ * Results:
+ *  If panic returns (which it shouldn't) this procedure returns
+ *  NULL.
+ *
+ * Side effects:
+ *  Generates a panic.
+ *
+ *----------------------------------------------------------------------
+ */
+/* ARGSUSED */
+static Rp_HashEntry *
+BogusCreate(
+    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
+    CONST void *key,        /* Key to use to find or create matching
+                             * entry. */
+    int *newPtr)            /* Store info here telling whether a new
+                             * entry was created. */
+{
+    Rp_Panic("called Rp_CreateHashEntry on deleted table");
+    return NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * RebuildTable --
+ *
+ *  This procedure is invoked when the ratio of entries to hash
+ *  buckets becomes too large.  It creates a new table with a
+ *  larger bucket array and moves all of the entries into the
+ *  new table.
+ *
+ * Results:
+ *  None.
+ *
+ * Side effects:
+ *  Memory gets reallocated and entries get re-hashed to new
+ *  buckets.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+RebuildTable(Rp_HashTable *tablePtr) /* Table to enlarge. */
+{
+    Rp_HashEntry **bucketPtr, **oldBuckets;
+    register Rp_HashEntry **oldChainPtr, **endPtr;
+    register Rp_HashEntry *hPtr, *nextPtr;
+    size_t hindex;
+
+    oldBuckets = tablePtr->buckets;
+    endPtr = tablePtr->buckets + tablePtr->numBuckets;
+    /*
+     * Allocate and initialize the new bucket array, and set up
+     * hashing constants for new array size.
+     */
+    tablePtr->numBuckets <<= 2;
+    tablePtr->buckets = Rp_Calloc(tablePtr->numBuckets,
+                           sizeof(Rp_HashEntry *));
+    tablePtr->rebuildSize <<= 2;
+    tablePtr->downShift -= 2;
+    tablePtr->mask = tablePtr->numBuckets - 1;
+
+    /*
+     * Move all of the existing entries into the new bucket array,
+     * based on their hash values.
+     */
+    if (tablePtr->keyType == RP_ONE_WORD_KEYS) {
+    /*
+     * RP_ONE_WORD_KEYS are handled slightly differently because
+     * they use the current table size (number of buckets) to be
+     * distributed.
+     */
+        for (oldChainPtr = oldBuckets; oldChainPtr < endPtr; oldChainPtr++) {
+            for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = nextPtr) {
+                nextPtr = hPtr->nextPtr;
+                hindex = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
+                bucketPtr = tablePtr->buckets + hindex;
+                hPtr->nextPtr = *bucketPtr;
+                *bucketPtr = hPtr;
+            }
+        }
+    } else {
+        for (oldChainPtr = oldBuckets; oldChainPtr < endPtr; oldChainPtr++) {
+            for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = nextPtr) {
+                nextPtr = hPtr->nextPtr;
+                hindex = hPtr->hval & tablePtr->mask;
+                bucketPtr = tablePtr->buckets + hindex;
+                hPtr->nextPtr = *bucketPtr;
+                *bucketPtr = hPtr;
+            }
+        }
+    }
+
+    /*
+     * Free up the old bucket array, if it was dynamically allocated.
+     */
+    if (oldBuckets != tablePtr->staticBuckets) {
+        Rp_Free(oldBuckets);
+    }
+}
+
+
+/* Public hash table routines */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_InitHashTable --
+ *
+ *  Given storage for a hash table, set up the fields to prepare
+ *  the hash table for use.
+ *
+ * Results:
+ *  None.
+ *
+ * Side effects:
+ *  TablePtr is now ready to be passed to Rp_FindHashEntry and
+ *  Rp_CreateHashEntry.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_InitHashTable(
+    register Rp_HashTable *tablePtr,    /* Pointer to table record, which
+                                         * is supplied by the caller. */
+    size_t keyType)                     /* Type of keys to use in table. */
+{
+#if (RP_SMALL_HASH_TABLE != 4)
+    Rp_Panic("Rp_InitHashTable: RP_SMALL_HASH_TABLE is %d, not 4\n",
+        RP_SMALL_HASH_TABLE);
+#endif
+    tablePtr->buckets = tablePtr->staticBuckets;
+    tablePtr->numBuckets = RP_SMALL_HASH_TABLE;
+    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
+    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
+    tablePtr->numEntries = 0;
+    tablePtr->rebuildSize = RP_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
+    tablePtr->downShift = DOWNSHIFT_START;
+
+    /* The number of buckets is always a power of 2, so we can
+     * generate the mask by simply subtracting 1 from the number of
+     * buckets. */
+    tablePtr->mask = (Rp_Hash)(tablePtr->numBuckets - 1);
+    tablePtr->keyType = keyType;
+
+    switch (keyType) {
+    case RP_STRING_KEYS:    /* NUL terminated string keys. */
+        tablePtr->findProc = StringFind;
+        tablePtr->createProc = StringCreate;
+        break;
+
+    case RP_ONE_WORD_KEYS:  /* 32 or 64 bit atomic keys. */
+        tablePtr->findProc = OneWordFind;
+        tablePtr->createProc = OneWordCreate;
+        break;
+
+    default:                /* Structures/arrays. */
+        if (keyType == 0) {
+            Rp_Panic("Rp_InitHashTable: Key size can't be %d, must be > 0\n",
+              keyType);
+        }
+        tablePtr->findProc = ArrayFind;
+        tablePtr->createProc = ArrayCreate;
+        break;
+    }
+    tablePtr->hPool = NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_InitHashTableWithPool --
+ *
+ *  Given storage for a hash table, set up the fields to prepare
+ *  the hash table for use.  The only difference between this 
+ *  routine and Rp_InitHashTable is that is uses a pool allocator
+ *  to allocate memory for hash table entries.  The type of pool
+ *  is either fixed or variable size (string) keys.
+ *
+ * Results:
+ *  None.
+ *
+ * Side effects:
+ *  TablePtr is now ready to be passed to Rp_FindHashEntry and
+ *  Rp_CreateHashEntry.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_InitHashTableWithPool(
+    register Rp_HashTable *tablePtr,    /* Pointer to table record, which
+                                         * is supplied by the caller. */
+    size_t keyType)                     /* Type of keys to use in table. */
+{
+    Rp_InitHashTable(tablePtr, keyType);
+    if (keyType == RP_STRING_KEYS) {
+        tablePtr->hPool = Rp_PoolCreate(RP_VARIABLE_SIZE_ITEMS);
+    } else {
+        tablePtr->hPool = Rp_PoolCreate(RP_FIXED_SIZE_ITEMS);
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_DeleteHashEntry --
+ *
+ *  Remove a single entry from a hash table.
+ *
+ * Results:
+ *  None.
+ *
+ * Side effects:
+ *  The entry given by entryPtr is deleted from its table and
+ *  should never again be used by the caller.  It is up to the
+ *  caller to free the clientData field of the entry, if that
+ *  is relevant.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_DeleteHashEntry(
+    Rp_HashTable *tablePtr,
+    Rp_HashEntry *entryPtr)
+{
+    register Rp_HashEntry *prevPtr;
+    Rp_HashEntry **bucketPtr;
+    size_t hindex;
+
+    if (tablePtr->keyType == RP_ONE_WORD_KEYS) {
+        hindex = RANDOM_INDEX(tablePtr, (CONST void *)entryPtr->hval);
+    } else {
+        hindex = (entryPtr->hval & tablePtr->mask);
+    }
+    bucketPtr = tablePtr->buckets + hindex;
+    if (*bucketPtr == entryPtr) {
+        *bucketPtr = entryPtr->nextPtr;
+    } else {
+        for (prevPtr = *bucketPtr; /*empty*/; prevPtr = prevPtr->nextPtr) {
+            if (prevPtr == NULL) {
+                Rp_Panic("malformed bucket chain in Rp_DeleteHashEntry");
+            }
+            if (prevPtr->nextPtr == entryPtr) {
+                prevPtr->nextPtr = entryPtr->nextPtr;
+                break;
+            }
+        }
+    }
+    tablePtr->numEntries--;
+    if (tablePtr->hPool != NULL) {
+        Rp_PoolFreeItem(tablePtr->hPool, (char *)entryPtr);
+    } else {
+        Rp_Free(entryPtr);
+    }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_DeleteHashTable --
+ *
+ *  Free up everything associated with a hash table except for
+ *  the record for the table itself.
+ *
+ * Results:
+ *  None.
+ *
+ * Side effects:
+ *  The hash table is no longer useable.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_DeleteHashTable(Rp_HashTable *tablePtr)	/* Table to delete. */
+{
+    /*
+     * Free up all the entries in the table.
+     */
+    if (tablePtr->hPool != NULL) {
+        Rp_PoolDestroy(tablePtr->hPool);
+        tablePtr->hPool = NULL;
+    } else {
+        register Rp_HashEntry *hPtr, *nextPtr;
+        size_t i;
+
+        for (i = 0; i < tablePtr->numBuckets; i++) {
+            hPtr = tablePtr->buckets[i];
+            while (hPtr != NULL) {
+                nextPtr = hPtr->nextPtr;
+                Rp_Free(hPtr);
+                hPtr = nextPtr;
+            }
+        }
+    }
+
+    /*
+     * Free up the bucket array, if it was dynamically allocated.
+     */
+    if (tablePtr->buckets != tablePtr->staticBuckets) {
+        Rp_Free(tablePtr->buckets);
+    }
+
+    /*
+     * Arrange for panics if the table is used again without
+     * re-initialization.
+     */
+
+    tablePtr->findProc = BogusFind;
+    tablePtr->createProc = BogusCreate;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_FirstHashEntry --
+ *
+ *  Locate the first entry in a hash table and set up a record
+ *  that can be used to step through all the remaining entries
+ *  of the table.
+ *
+ * Results:
+ *  The return value is a pointer to the first entry in tablePtr,
+ *  or NULL if tablePtr has no entries in it.  The memory at
+ *  *searchPtr is initialized so that subsequent calls to
+ *  Rp_NextHashEntry will return all of the entries in the table,
+ *  one at a time.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+Rp_HashEntry *
+Rp_FirstHashEntry(
+    Rp_HashTable *tablePtr,         /* Table to search. */
+    Rp_HashSearch *searchPtr)       /* Place to store information about
+                                     * progress through the table. */
+{
+    searchPtr->tablePtr = tablePtr;
+    searchPtr->nextIndex = 0;
+    searchPtr->nextEntryPtr = NULL;
+    return Rp_NextHashEntry(searchPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_NextHashEntry --
+ *
+ *  Once a hash table enumeration has been initiated by calling
+ *  Rp_FirstHashEntry, this procedure may be called to return
+ *  successive elements of the table.
+ *
+ * Results:
+ *  The return value is the next entry in the hash table being
+ *  enumerated, or NULL if the end of the table is reached.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+Rp_HashEntry *
+Rp_NextHashEntry(Rp_HashSearch *searchPtr)
+{
+    Rp_HashEntry *hPtr;
+
+    while (searchPtr->nextEntryPtr == NULL) {
+        if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) {
+            return NULL;
+        }
+        searchPtr->nextEntryPtr =
+                searchPtr->tablePtr->buckets[searchPtr->nextIndex];
+        searchPtr->nextIndex++;
+    }
+    hPtr = searchPtr->nextEntryPtr;
+    searchPtr->nextEntryPtr = hPtr->nextPtr;
+    return hPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_HashStats --
+ *
+ *  Return statistics describing the layout of the hash table
+ *  in its hash buckets.
+ *
+ * Results:
+ *  The return value is a malloc-ed string containing information
+ *  about tablePtr.  It is the caller's responsibility to free
+ *  this string.
+ *
+ * Side effects:
+ *  None.
+ *
+ *----------------------------------------------------------------------
+ */
+char *
+Rp_HashStats(Rp_HashTable *tablePtr) /* Table for which to produce stats. */
+{
+#define NUM_COUNTERS 10
+    size_t count[NUM_COUNTERS], overflow, i, j, max;
+    double average, tmp;
+    register Rp_HashEntry *hPtr;
+    Rp_HashEntry **bucketPtr, **endPtr;
+    char *result, *p;
+
+    /*
+     * Compute a histogram of bucket usage.
+     */
+    for (i = 0; i < NUM_COUNTERS; i++) {
+        count[i] = 0;
+    }
+    overflow = 0;
+    average = 0.0;
+    max = 0;
+    endPtr = tablePtr->buckets + tablePtr->numBuckets;
+    for (bucketPtr = tablePtr->buckets; bucketPtr < endPtr; bucketPtr++) {
+        j = 0;
+        for (hPtr = *bucketPtr; hPtr != NULL; hPtr = hPtr->nextPtr) {
+            j++;
+        }
+        if (j > max) {
+            max = j;
+        }
+        if (j < NUM_COUNTERS) {
+            count[j]++;
+        } else {
+            overflow++;
+        }
+        tmp = j;
+        average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
+    }
+
+    /*
+     * Print out the histogram and a few other pieces of information.
+     */
+    result = Rp_Malloc((unsigned) ((NUM_COUNTERS*60) + 300));
+#if SIZEOF_VOID_P == 8
+    sprintf(result, "%ld entries in table, %ld buckets\n",
+            tablePtr->numEntries, tablePtr->numBuckets);
+#else
+    sprintf(result, "%d entries in table, %d buckets\n",
+            tablePtr->numEntries, tablePtr->numBuckets);
+#endif
+    p = result + strlen(result);
+    for (i = 0; i < NUM_COUNTERS; i++) {
+#if SIZEOF_VOID_P == 8
+        sprintf(p, "number of buckets with %ld entries: %ld\n",
+                i, count[i]);
+#else
+        sprintf(p, "number of buckets with %d entries: %d\n",
+                i, count[i]);
+#endif
+        p += strlen(p);
+    }
+#if SIZEOF_VOID_P == 8
+    sprintf(p, "number of buckets with %d or more entries: %ld\n",
+            NUM_COUNTERS, overflow);
+#else
+    sprintf(p, "number of buckets with %d or more entries: %d\n",
+            NUM_COUNTERS, overflow);
+#endif
+    p += strlen(p);
+    sprintf(p, "average search distance for entry: %.2f\n", average);
+    p += strlen(p);
+#if SIZEOF_VOID_P == 8
+    sprintf(p, "maximum search distance for entry: %ld", max);
+#else
+    sprintf(p, "maximum search distance for entry: %d", max);
+#endif
+    return result;
+}
Index: /trunk/src/objects/RpHash.h.in
===================================================================
--- /trunk/src/objects/RpHash.h.in	(revision 1270)
+++ /trunk/src/objects/RpHash.h.in	(revision 1270)
@@ -0,0 +1,223 @@
+
+/*
+ * bltHash.h --
+ *
+ * Copyright 2001 Silicon Metrics Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Silicon Metrics disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness.  In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ *
+ * Bob Jenkins, 1996.  hash.c.  Public Domain.
+ * Bob Jenkins, 1997.  lookup8.c.  Public Domain.
+ *
+ * Copyright (c) 1991-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * RCS: @(#) $Id: bltHash.h.in,v 1.5 2002/07/14 00:08:13 ghowlett Exp $
+ */
+
+#ifndef RP_HASH_H
+#define RP_HASH_H 1
+
+#ifndef RP_INT_H
+#ifndef SIZEOF_LONG
+#define SIZEOF_LONG @SIZEOF_LONG@
+#endif
+#ifndef SIZEOF_LONG_LONG
+#define SIZEOF_LONG_LONG @SIZEOF_LONG_LONG@
+#endif
+#ifndef SIZEOF_INT
+#define SIZEOF_INT @SIZEOF_INT@
+#endif
+#ifndef SIZEOF_VOID_P
+#define SIZEOF_VOID_P @SIZEOF_VOID_P@
+#endif
+#ifndef HAVE_INTTYPES_H
+#if @HAVE_INTTYPES_H@
+#define HAVE_INTTYPES_H 1
+#endif
+#endif
+#endif /* !RP_INT_H */
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#if (SIZEOF_VOID_P == 8)
+#if (SIZEOF_LONG == 8)
+typedef signed long int64_t;
+typedef unsigned long uint64_t;
+#else
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+#endif /* SIZEOF_LONG == 8 */
+#else
+#ifndef __CYGWIN__
+typedef signed int int32_t;
+#endif /* __CYGWIN__ */
+typedef unsigned int uint32_t;
+#endif /* SIZEOF_VOID_P == 8 */
+#endif /* HAVE_INTTYPES_H */
+
+#if (SIZEOF_VOID_P == 8)
+typedef uint64_t Rp_Hash;
+#else
+typedef uint32_t Rp_Hash;
+#endif /* SIZEOF_VOID_P == 8 */
+
+#include "RpPool.h"
+
+/*
+ * Acceptable key types for hash tables:
+ */
+#define RP_STRING_KEYS      0
+#define RP_ONE_WORD_KEYS    ((size_t)-1)
+
+/*
+ * Forward declaration of Rp_HashTable.  Needed by some C++ compilers
+ * to prevent errors when the forward reference to Rp_HashTable is
+ * encountered in the Rp_HashEntry structure.
+ */
+
+#ifdef __cplusplus
+struct Rp_HashTable;
+#endif
+
+typedef union {             /* Key has one of these forms: */
+    void *oneWordValue;     /* One-word value for key. */
+    unsigned long words[1]; /* Multiple integer words for key.
+                             * The actual size will be as large
+                             * as necessary for this table's
+                             * keys. */
+    char string[4];         /* string for key.  The actual size
+                             * will be as large as needed to hold
+                             * the key. */
+} Rp_HashKey;
+
+/*
+ * Structure definition for an entry in a hash table.  No-one outside
+ * Rp should access any of these fields directly;  use the macros
+ * defined below.
+ */
+typedef struct Rp_HashEntry {
+    struct Rp_HashEntry *nextPtr;   /* Pointer to next entry in this
+                                     * hash bucket, or NULL for end of
+                                     * chain. */
+    Rp_Hash hval;
+
+    ClientData clientData;          /* Application stores something here
+                                     * with Rp_SetHashValue. */
+    Rp_HashKey key;                 /* MUST BE LAST FIELD IN RECORD!! */
+} Rp_HashEntry;
+
+/*
+ * Structure definition for a hash table.  Must be in blt.h so clients
+ * can allocate space for these structures, but clients should never
+ * access any fields in this structure.
+ */
+#define RP_SMALL_HASH_TABLE 4
+typedef struct Rp_HashTable {
+    Rp_HashEntry **buckets;         /* Pointer to bucket array.  Each
+                                     * element points to first entry in
+                                     * bucket's hash chain, or NULL. */
+    Rp_HashEntry *staticBuckets[RP_SMALL_HASH_TABLE];
+                                    /* Bucket array used for small tables
+                                     * (to avoid mallocs and frees). */
+    size_t numBuckets;              /* Total number of buckets allocated
+                                     * at **buckets. */
+    size_t numEntries;              /* Total number of entries present
+                                     * in table. */
+    size_t rebuildSize;             /* Enlarge table when numEntries gets
+                                     * to be this large. */
+    Rp_Hash mask;                   /* Mask value used in hashing
+                                     * function. */
+    unsigned int downShift;         /* Shift count used in hashing
+                                     * function.  Designed to use high
+                                     * order bits of randomized keys. */
+    size_t keyType;                 /* Type of keys used in this table.
+                                     * It's either RP_STRING_KEYS,
+                                     * RP_ONE_WORD_KEYS, or an integer
+                                     * giving the number of ints that
+                                     * is the size of the key.
+                                     */
+    Rp_HashEntry *(*findProc) _ANSI_ARGS_((struct Rp_HashTable *tablePtr,
+        CONST void *key));
+    Rp_HashEntry *(*createProc) _ANSI_ARGS_((struct Rp_HashTable *tablePtr,
+        CONST void *key, int *newPtr));
+
+    Rp_Pool hPool;      /* Pointer to the pool allocator used
+                         * for entries in this hash table. If
+                         * NULL, the standard Tcl_Alloc,
+                         * Tcl_Free routines will be used
+                         * instead.
+                         */
+} Rp_HashTable;
+
+/*
+ * Structure definition for information used to keep track of searches
+ * through hash tables:
+ */
+
+typedef struct {
+    Rp_HashTable *tablePtr;         /* Table being searched. */
+    unsigned long nextIndex;        /* Index of next bucket to be
+                                     * enumerated after present one. */
+    Rp_HashEntry *nextEntryPtr;     /* Next entry to be enumerated in the
+                                     * the current bucket. */
+} Rp_HashSearch;
+
+/*
+ * Macros for clients to use to access fields of hash entries:
+ */
+
+#define Rp_GetHashValue(h) ((h)->clientData)
+#define Rp_SetHashValue(h, value) ((h)->clientData = (ClientData)(value))
+#define Rp_GetHashKey(tablePtr, h) \
+    ((void *) (((tablePtr)->keyType == RP_ONE_WORD_KEYS) ? \
+     (void *)(h)->key.oneWordValue : (h)->key.string))
+
+/*
+ * Macros to use for clients to use to invoke find and create procedures
+ * for hash tables:
+ */
+#define Rp_FindHashEntry(tablePtr, key) \
+    (*((tablePtr)->findProc))(tablePtr, key)
+#define Rp_CreateHashEntry(tablePtr, key, newPtr) \
+    (*((tablePtr)->createProc))(tablePtr, key, newPtr)
+
+EXTERN void Rp_InitHashTable _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    size_t keyType));
+
+EXTERN void Rp_InitHashTableWithPool _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    size_t keyType));
+
+EXTERN void Rp_DeleteHashTable _ANSI_ARGS_((Rp_HashTable *tablePtr));
+
+EXTERN void Rp_DeleteHashEntry _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    Rp_HashEntry *entryPtr));
+
+EXTERN Rp_HashEntry *Rp_FirstHashEntry _ANSI_ARGS_((Rp_HashTable *tablePtr,
+    Rp_HashSearch *searchPtr));
+
+EXTERN Rp_HashEntry *Rp_NextHashEntry _ANSI_ARGS_((Rp_HashSearch *srchPtr));
+
+EXTERN char *Rp_HashStats _ANSI_ARGS_((Rp_HashTable *tablePtr));
+
+#endif /* RP_HASH_H */
Index: /trunk/src/objects/RpHashHelper.c
===================================================================
--- /trunk/src/objects/RpHashHelper.c	(revision 1270)
+++ /trunk/src/objects/RpHashHelper.c	(revision 1270)
@@ -0,0 +1,255 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "RpHashHelper.h"
+
+int
+Rp_HashPrint(
+    Rp_HashTable *h)
+{
+    Rp_HashEntry *hEntry = NULL;
+    Rp_HashSearch hSearch;
+    char *k = NULL;
+    char *v = NULL;
+
+    printf("hash table start\n");
+    hEntry = Rp_FirstHashEntry(h,&hSearch);
+    while (hEntry != NULL) {
+        k = (char *) Rp_GetHashKey(h,hEntry);
+        v = (char *) Rp_GetHashValue(hEntry);
+        printf("hentry = :%s->%s:\n",k,v);
+        hEntry = Rp_NextHashEntry(&hSearch);
+    }
+    printf("hash table end\n");
+    return 0;
+}
+
+int
+Rp_HashAddNode(
+    Rp_HashTable *h,
+    const char* key,
+    const void *n)
+{
+    int isNew = 0;
+    Rp_HashEntry *hEntry = NULL;
+
+    hEntry = Rp_CreateHashEntry(h,key,&isNew);
+    if (isNew == 0) {
+        // hash entry is not new
+        // warn user: two vals with the same name
+        // warn("hash entry is not new\n");
+    }
+    Rp_SetHashValue(hEntry,(ClientData)n);
+    return isNew;
+}
+
+/*
+ *  hRslt = h1 U h2
+ */
+
+int
+Rp_HashUnion(
+    Rp_HashTable *hRslt,
+    Rp_HashTable *h1,
+    Rp_HashTable *h2,
+    int (*cpyFxn)(void **to, void *from),
+    int (*cmpFxn) (void *he1, void *he2))
+{
+    Rp_HashSearch hSearch;
+    Rp_HashEntry *hEntry = NULL;
+    void *origKey = NULL;
+    void *origNode = NULL;
+    void *newNode = NULL;
+    void *searchRslt = NULL;
+    int nodesAddedCnt = 0;
+
+    Rp_HashCopy(hRslt,h1,cpyFxn);
+
+    hEntry = Rp_FirstHashEntry(h2,&hSearch);
+    while (hEntry != NULL) {
+        origKey = Rp_GetHashKey(h2,hEntry);
+        origNode = Rp_GetHashValue(hEntry);
+        searchRslt = Rp_HashSearchNode(hRslt,origKey);
+        if (searchRslt == NULL) {
+            // node not in hRslt, add it
+            cpyFxn(&newNode,origNode);
+            Rp_HashAddNode(hRslt,origKey,newNode);
+            nodesAddedCnt++;
+        }
+        hEntry = Rp_NextHashEntry(&hSearch);
+    }
+    return nodesAddedCnt;
+}
+
+/*
+ *  hRslt = h1 - h2
+ */
+
+int
+Rp_HashSubrtact(
+    Rp_HashTable *hRslt,
+    Rp_HashTable *h1,
+    Rp_HashTable *h2,
+    int (*cpyFxn)(void **to, void *from),
+    int (*cmpFxn)(void *he1, void *he2))
+{
+    Rp_HashSearch hSearch;
+    Rp_HashEntry *hEntry = NULL;
+    void *origKey = NULL;
+    void *origNode = NULL;
+    void *newNode = NULL;
+    int nodesAddedCnt = 0;
+
+    hEntry = Rp_FirstHashEntry(h1,&hSearch);
+    while (hEntry != NULL) {
+        origKey = Rp_GetHashKey(h1,hEntry);
+        origNode = Rp_GetHashValue(hEntry);
+        if (Rp_HashSearchNode(h2,origKey) == NULL) {
+            // node not in h2, add it to hRslt
+            cpyFxn(&newNode,origNode);
+            Rp_HashAddNode(hRslt,origKey,newNode);
+            nodesAddedCnt++;
+        }
+        hEntry = Rp_NextHashEntry(&hSearch);
+    }
+    return nodesAddedCnt;
+}
+
+int
+Rp_HashCompare(
+    Rp_HashTable *h1,
+    Rp_HashTable *h2,
+    int (*cmpFxn)(void *n1,void *n2))
+{
+    Rp_HashSearch hSearch;
+    Rp_HashEntry *h1Entry = NULL;
+    Rp_HashEntry *h2Entry = NULL;
+    void *h1Node = NULL;
+    void *h2Key = NULL;
+    void *h2Node = NULL;
+    int compareResult = 0;
+
+    // check the pointer values
+    if ( (h1 == NULL) && (h2 != NULL) ) {
+        return -1;
+    } else if ( (h1 != NULL) && (h2 == NULL) ) {
+        return 1;
+    } else if (h1 == h2) {
+        return 0;
+    }
+
+    // check hash table sizes
+    if (h1->numEntries < h2->numEntries) {
+        return -1;
+    } else if (h1 ->numEntries > h2->numEntries) {
+        return 1;
+    }
+
+    // equal number of entries, have to check each entry.
+
+    h2Entry = Rp_FirstHashEntry(h2,&hSearch);
+    while (h2Entry != NULL) {
+        h2Key = Rp_GetHashKey(h2,h2Entry);
+        h2Node = Rp_GetHashValue(h2Entry);
+        h1Entry = Rp_FindHashEntry(h1,h2Key);
+        if (h1Entry == NULL) {
+            compareResult = -1;
+            break;
+        } else {
+            h1Node = Rp_GetHashValue(h1Entry);
+            compareResult = cmpFxn(h1Node,h2Node);
+            if (compareResult != 0) {
+                break;
+            }
+        }
+        h2Entry = Rp_NextHashEntry(&hSearch);
+    }
+    return compareResult;
+}
+
+
+/*
+ *  forall(i) h1(i) = h2(i) : i E (nodes(h2))
+ *  elements of h2 are copied to h1 regardless of if h1
+ *  already has elements in it.
+ */
+
+int
+Rp_HashCopy(
+    Rp_HashTable *h1,
+    Rp_HashTable *h2,
+    int (*cpyFxn)(void **to,void *from))
+{
+    Rp_HashSearch hSearch;
+    Rp_HashEntry *hEntry = NULL;
+    void *origKey = NULL;
+    void *origNode = NULL;
+    void *newNode = NULL;
+
+    hEntry = Rp_FirstHashEntry(h2,&hSearch);
+    while (hEntry != NULL) {
+        origKey = Rp_GetHashKey(h2,hEntry);
+        origNode = Rp_GetHashValue(hEntry);
+        if (cpyFxn(&newNode,origNode) != 0) {
+            // error while copying
+        }
+        Rp_HashAddNode(h1,origKey,newNode);
+        hEntry = Rp_NextHashEntry(&hSearch);
+    }
+    return 0;
+}
+
+/*
+ * this function will not work for you if you put
+ * entries in the hash table with null data value
+ */
+
+void *
+Rp_HashSearchNode(
+    Rp_HashTable *h,
+    const char *key)
+{
+    Rp_HashEntry *hEntry = NULL;
+    void *n = NULL;
+    hEntry = Rp_FindHashEntry(h,key);
+    if (hEntry != NULL) {
+        n = Rp_GetHashValue(hEntry);
+    }
+    return n;
+}
+
+void *
+Rp_HashRemoveNode(
+    Rp_HashTable *h,
+    const char *key)
+{
+    Rp_HashEntry *hEntry = NULL;
+    void *n = NULL;
+    hEntry = Rp_FindHashEntry(h,key);
+    if (hEntry != NULL) {
+        n = Rp_GetHashValue(hEntry);
+        Rp_DeleteHashEntry(h,hEntry);
+    }
+    return n;
+}
+
+int charCpyFxn(
+    void **to,
+    void *from)
+{
+    size_t len = 0;
+
+    len = strlen((char*)from);
+    *to = (void*) malloc(len*sizeof(char));
+    strcpy((char*)(*to),(char*)from);
+    return 0;
+}
+
+int charCmpFxn(
+    void *to,
+    void *from)
+{
+    return strcmp(to,from);
+}
+
Index: /trunk/src/objects/RpHashHelper.h
===================================================================
--- /trunk/src/objects/RpHashHelper.h	(revision 1270)
+++ /trunk/src/objects/RpHashHelper.h	(revision 1270)
@@ -0,0 +1,38 @@
+#ifndef _RP_HASH_HELPER_H
+#define _RP_HASH_HELPER_H 1
+
+#include "RpInt.h"
+#include "RpHash.h"
+
+int Rp_HashPrint        ( Rp_HashTable *h);
+
+int Rp_HashAddNode      ( Rp_HashTable *h, const char *key, const void *n);
+
+int Rp_HashUnion        ( Rp_HashTable *hRslt,
+                          Rp_HashTable *h1,
+                          Rp_HashTable *h2,
+                          int (*cpyFxn)(void **to, void *from),
+                          int (*cmpFxn) (void *he1, void *he2));
+
+int Rp_HashSubrtact     ( Rp_HashTable *hRslt,
+                          Rp_HashTable *h1,
+                          Rp_HashTable *h2,
+                          int (*cpyFxn)(void **to, void *from),
+                          int (*cmpFxn)(void *he1, void *he2));
+
+int Rp_HashCompare      ( Rp_HashTable *h1,
+                          Rp_HashTable *h2,
+                          int (*cmpFxn)(void *n1,void *n2));
+
+int Rp_HashCopy         ( Rp_HashTable *h1,
+                          Rp_HashTable *h2,
+                          int (*cpyFxn)(void **to,void *from));
+
+void *Rp_HashSearchNode ( Rp_HashTable *h, const char *key);
+
+void *Rp_HashRemoveNode ( Rp_HashTable *h, const char *key);
+
+int charCpyFxn(void **to, void *from);
+int charCmpFxn( void *to, void *from);
+
+#endif // _RP_HASH_HELPER_H
Index: /trunk/src/objects/RpInt.h
===================================================================
--- /trunk/src/objects/RpInt.h	(revision 1270)
+++ /trunk/src/objects/RpInt.h	(revision 1270)
@@ -0,0 +1,297 @@
+
+/*
+ * bltInt.h --
+ *
+ * Copyright 1993-1998 Lucent Technologies, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Lucent Technologies disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness.  In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ */
+
+#ifndef _RP_INT_H
+#define _RP_INT_H
+
+// #define USE_NON_CONST
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <memory.h>
+#include <unistd.h>
+#include <limits.h>
+
+// keep this commented until i fix the autoheader setup to
+// automatically #define these
+//
+// #include "bltConfig.h"
+//#ifdef HAVE_STDLIB_H
+//#include <stdlib.h>
+//#endif /* HAVE_STDLIB_H */
+//
+//#ifdef HAVE_STRING_H
+//#include <string.h>
+//#endif /* HAVE_STRING_H */
+//
+//#ifdef HAVE_ERRNO_H
+//#include <errno.h>
+//#endif /* HAVE_ERRNO_H */
+//
+//#ifdef HAVE_CTYPE_H
+//#include <ctype.h>
+//#endif /* HAVE_CTYPE_H */
+//
+//#ifdef HAVE_MEMORY_H
+//#include <memory.h>
+//#endif /* HAVE_MEMORY_H */
+//
+//#ifdef HAVE_UNISTD_H
+//#include <unistd.h>
+//#endif /* HAVE_UNISTD_H */
+//
+//#ifdef HAVE_LIMITS_H
+//#include <limits.h>
+//#endif
+
+#define RP_OK       0
+#define RP_ERROR    1
+#define RP_RETURN   2
+#define RP_BREAK    3
+#define RP_CONTINUE 4
+
+#ifndef _CLIENTDATA
+#   ifndef NO_VOID
+    typedef void *ClientData;
+#   else
+    typedef int *ClientData;
+#   endif
+#   define _CLIENTDATA
+
+#ifndef NO_CONST
+#   define CONST const
+#else
+#   define CONST
+#endif
+
+/*
+#ifndef _ANSI_ARGS_
+#   define _ANSI_ARGS_(x)       ()
+#endif
+*/
+
+#ifndef _ANSI_ARGS_
+#if defined(__STDC__) || defined(__cplusplus)
+#   define _ANSI_ARGS_(x)       x
+#else
+#   define _ANSI_ARGS_(x)       ()
+#endif
+#endif
+
+
+#endif
+#undef INLINE
+#ifdef __GNUC__
+#define INLINE inline
+#else
+#define INLINE
+#endif
+// #undef EXPORT
+// #define EXPORT
+
+#ifndef EXPORT
+#define EXPORT
+#endif
+
+#undef EXTERN
+
+#ifdef __cplusplus
+#   define EXTERN extern "C" EXPORT
+#else
+#   define EXTERN extern EXPORT
+#endif
+
+
+#undef VARARGS
+#ifdef __cplusplus
+#define ANYARGS (...)
+#define VARARGS(first)  (first, ...)
+#define VARARGS2(first, second)  (first, second, ...)
+#else
+#define ANYARGS ()
+#define VARARGS(first) ()
+#define VARARGS2(first, second) ()
+#endif /* __cplusplus */
+
+#undef MIN
+#define MIN(a,b)    (((a)<(b))?(a):(b))
+
+#undef MAX
+#define MAX(a,b)    (((a)>(b))?(a):(b))
+
+#undef MIN3
+#define MIN3(a,b,c) (((a)<(b))?(((a)<(c))?(a):(c)):(((b)<(c))?(b):(c)))
+
+#undef MAX3
+#define MAX3(a,b,c) (((a)>(b))?(((a)>(c))?(a):(c)):(((b)>(c))?(b):(c)))
+
+#define TRUE    1
+#define FALSE   0
+
+/*
+ * The macro below is used to modify a "char" value (e.g. by casting
+ * it to an unsigned character) so that it can be used safely with
+ * macros such as isspace.
+ */
+#define UCHAR(c) ((unsigned char) (c))
+
+#undef panic
+#define panic(mesg) Rp_Panic("%s:%d %s", __FILE__, __LINE__, (mesg))
+
+/*
+ * Since the Tcl/Tk distribution doesn't perform any asserts, dynamic
+ * loading can fail to find the __assert function.  As a workaround,
+ * we'll include our own.
+ */
+#undef  assert
+#ifdef  NDEBUG
+    #define assert(EX) ((void)0)
+#else
+    extern void Rp_Assert _ANSI_ARGS_((char *expr, char *file, int line));
+    #ifdef __STDC__
+        #define assert(EX) (void)((EX) || (Rp_Assert(#EX, __FILE__, __LINE__), 0))
+    #else
+        #define assert(EX) (void)((EX) || (Rp_Assert("EX", __FILE__, __LINE__), 0))
+    #endif /* __STDC__ */
+
+#endif /* NDEBUG */
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ *  Assume we need to declare free if there's no stdlib.h or malloc.h
+ *
+ * ----------------------------------------------------------------------
+ */
+#if !defined(HAVE_STDLIB_H) && !defined(HAVE_MALLOC_H)
+extern void free _ANSI_ARGS_((void *));
+#endif
+
+extern int Rp_DictionaryCompare _ANSI_ARGS_((char *s1, char *s2));
+
+extern void Rp_Panic _ANSI_ARGS_((const char *format, ...));
+
+
+/* ---------------------------------------------------------------- */
+
+typedef int (QSortCompareProc) _ANSI_ARGS_((const void *, const void *));
+
+/*
+ * -------------------------------------------------------------------
+ *
+ * Point2D --
+ *
+ *	2-D coordinate.
+ *
+ * -------------------------------------------------------------------
+ */
+typedef struct {
+    double x, y;
+} Point2D;
+
+/*
+ * -------------------------------------------------------------------
+ *
+ * Point3D --
+ *
+ *	3-D coordinate.
+ *
+ * -------------------------------------------------------------------
+ */
+typedef struct {
+    double x, y, z;
+} Point3D;
+
+/*
+ * -------------------------------------------------------------------
+ *
+ * Segment2D --
+ *
+ *	2-D line segment.
+ *
+ * -------------------------------------------------------------------
+ */
+typedef struct {
+    Point2D p, q;		/* The two end points of the segment. */
+} Segment2D;
+
+/*
+ * -------------------------------------------------------------------
+ *
+ * Dim2D --
+ *
+ *	2-D dimension.
+ *
+ * -------------------------------------------------------------------
+ */
+typedef struct {
+    short int width, height;
+} Dim2D;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Region2D --
+ *
+ *      2-D region.  Used to copy parts of images.
+ *
+ *----------------------------------------------------------------------
+ */
+typedef struct {
+    int left, right, top, bottom;
+} Region2D;
+
+#define RegionWidth(r)      ((r)->right - (r)->left + 1)
+#define RegionHeight(r)     ((r)->bottom - (r)->top + 1)
+
+typedef struct {
+    double left, right, top, bottom;
+} Extents2D;
+
+typedef struct {
+    double left, right, top, bottom, front, back;
+} Extents3D;
+
+#define PointInRegion(e,x,y) \
+    (((x) <= (e)->right) && ((x) >= (e)->left) && \
+     ((y) <= (e)->bottom) && ((y) >= (e)->top))
+
+#define PointInRectangle(r,x0,y0) \
+    (((x0) <= (int)((r)->x + (r)->width - 1)) && ((x0) >= (int)(r)->x) && \
+     ((y0) <= (int)((r)->y + (r)->height - 1)) && ((y0) >= (int)(r)->y))
+
+
+#define Rp_Malloc malloc
+#define Rp_Calloc calloc
+#define Rp_Realloc realloc
+#define Rp_Free free
+#define Rp_Strdup strdup
+
+#endif /*_RP_INT_H*/
Index: /trunk/src/objects/RpNumber.cc
===================================================================
--- /trunk/src/objects/RpNumber.cc	(revision 1269)
+++ /trunk/src/objects/RpNumber.cc	(revision 1270)
@@ -5,5 +5,5 @@
  * ======================================================================
  *  AUTHOR:  Derrick Kearney, Purdue University
- *  Copyright (c) 2004-2005  Purdue Research Foundation
+ *  Copyright (c) 2005-2009  Purdue Research Foundation
  *
  *  See the file "license.terms" for information on usage and
@@ -12,138 +12,117 @@
  */
 
+#include <cstring>
+#include <stdlib.h>
 #include "RpNumber.h"
 
-/**********************************************************************/
-// METHOD: setDefaultValue()
-/// set the default value of a RpNumber object.
-/**
- */
+#ifndef _RpUNITS_H
+    #include "RpUnits.h"
+#endif
 
-RpNumber&
-RpNumber::setDefaultValue(double newDefaultVal) {
+RpNumber::RpNumber (
+            const char *path,
+            const char *unit,
+            double val
+        )
+    :   RpVariable  (),
+        _default    (val),
+        _current    (val),
+        _min        (0.0),
+        _max        (0.0),
+        _minmaxSet  (0.0)
+{
+    const RpUnits *u = NULL;
 
-    double* def = NULL;
+    property("path",(const void *)path);
 
-    def = (double*) RpVariable::getDefaultValue(); 
+    u = RpUnits::find(std::string(unit));
+    if (!u) {
+        u = RpUnits::define(unit,NULL);
+    }
+    property("units",(const void *)unit);
 
-    if (!def) {
-        RpVariable::setDefaultValue(new double (newDefaultVal));
+    property("default",(const void *)&_default);
+    property("current",(const void *)&_current);
+    property("min",(const void *)&_min);
+    property("max",(const void *)&_max);
+}
+
+RpNumber::RpNumber (
+            const char *path,
+            const char *unit,
+            double val,
+            double min,
+            double max,
+            const char *label,
+            const char *desc
+        )
+    :   RpVariable  (),
+        _default    (val),
+        _current    (val),
+        _min         (min),
+        _max         (max),
+        _minmaxSet   (0)
+{
+    const RpUnits *u = NULL;
+
+    property("path",(const void *)path);
+
+    u = RpUnits::find(std::string(unit));
+    if (! u) {
+        u = RpUnits::define(unit,NULL);
+    }
+    property("units",(const void *)unit);
+
+    if ((min == 0) && (max == 0)) {
+        _minmaxSet = 0;
     }
     else {
-        *def = newDefaultVal;
+
+        if (min > val) {
+            _min = val;
+        }
+
+        if (max < val) {
+            _max = val;
+        }
     }
 
-    return *this;
+    property("default",(const void *)&_default);
+    property("current",(const void *)&_current);
+    property("min",(const void *)&_min);
+    property("max",(const void *)&_max);
+}
+
+// copy constructor
+RpNumber::RpNumber ( const RpNumber& o )
+    :   RpVariable(o),
+        _default    (o._default),
+        _current    (o._current),
+        _min        (o._min),
+        _max        (o._max),
+        _minmaxSet  (o._minmaxSet)
+{}
+
+// default destructor
+RpNumber::~RpNumber ()
+{
+    // clean up dynamic memory
+
 }
 
 /**********************************************************************/
-// METHOD: setCurrentValue()
-/// Set the current value of a RpNumber object.
+// METHOD: units()
+/// get / set the units of this number
 /**
+ * get / set the units property of this object
  */
 
-RpNumber&
-RpNumber::setCurrentValue(double newCurrentVal) {
-
-    double* cur = (double*) RpVariable::getCurrentValue();
-    double* def = (double*) RpVariable::getDefaultValue();
-
-    if (cur == def) {
-        RpVariable::setCurrentValue(new double (newCurrentVal));
-    }
-    else {
-        *cur = newCurrentVal;
-    }
-
-    return *this;
+const char *
+RpNumber::units(
+    const char *val)
+{
+    return (const char *) property("units",val);
 }
 
-
-/**********************************************************************/
-// METHOD: setMin()
-/// Set the min value of a RpNumber object.
-/**
- */
-
-RpNumber&
-RpNumber::setMin(double newMin) {
-
-    min = newMin;
-    return *this;
-}
-
-/**********************************************************************/
-// METHOD: setMax()
-/// set the min value of a RpNumber object
-/**
- */
-
-RpNumber&
-RpNumber::setMax(double newMax) {
-
-    max = newMax;
-    return *this;
-}
-
-/**********************************************************************/
-// METHOD: getUnits()
-/// Report the units of the object.
-/**
- */
-
-std::string 
-RpNumber::getUnits() const {
-
-    return units->getUnitsName(); 
-}
-
-
-/**********************************************************************/
-// METHOD: getDefaultValue()
-/// Report the default value of the object.
-/**
- */
-
-double
-RpNumber::getDefaultValue(void* null_val) const {
-
-    return *((double*) RpVariable::getDefaultValue()); 
-}
-
-/**********************************************************************/
-// METHOD: getCurrentValue()
-/// Report the current value of the object.
-/**
- */
-
-double
-RpNumber::getCurrentValue(void* null_val) const {
-
-    return *((double*) RpVariable::getCurrentValue()); 
-}
-
-/**********************************************************************/
-// METHOD: getMin()
-/// Report the min of the object.
-/**
- */
-
-double
-RpNumber::getMin() const {
-
-    return min;
-}
-
-/**********************************************************************/
-// METHOD: getMax()
-/// report the max of the object.
-/**
- */
-
-double
-RpNumber::getMax() const {
-
-    return max;
-}
 
 /**********************************************************************/
@@ -155,91 +134,43 @@
 
 double
-RpNumber::convert(std::string toUnitStr, int storeResult, int* result) {
+RpNumber::convert(const char *to) {
 
     const RpUnits* toUnit = NULL;
-    double retVal = 0;
-    int my_result = 0;
+    const RpUnits* fromUnit = NULL;
+    double convertedVal = _current;
+    int err = 0;
 
-    toUnit = RpUnits::find(toUnitStr);
-
-    // set the result to the default value if it exists
-    if (result) {
-        *result = my_result;
+    // make sure all units functions accept char*'s
+    toUnit = RpUnits::find(std::string(to));
+    if (!toUnit) {
+        // should raise error!
+        // conversion not defined because unit does not exist
+        return _current;
     }
 
-    if (!toUnit) {
-        // should raise error! 
+    fromUnit = RpUnits::find(std::string(units(NULL)));
+    if (!fromUnit) {
+        // should raise error!
         // conversion not defined because unit does not exist
-        return retVal;
+        return _current;
     }
 
     // perform the conversion
-    retVal = convert(toUnit,&my_result); 
-
-    // check the result of the conversion and store if necessary
-    if (my_result) {
-        if (result) {
-            *result = my_result;
-        }
-
-        // check if we should store the value and change units
-        if (storeResult) {
-            // no need to deallocate old units, 
-            // because they are stored in static dictionary
-            units = toUnit;
-            RpNumber::setCurrentValue(retVal);
-        }
+    convertedVal = fromUnit->convert(toUnit,_default, &err);
+    if (!err) {
+        _default = convertedVal;
     }
 
-    return retVal;
+    convertedVal = fromUnit->convert(toUnit,_current, &err);
+    if (!err) {
+        _current = convertedVal;
+    }
+
+    if (err) {
+        convertedVal = _current;
+    }
+
+    return convertedVal;
 }
-
-/**********************************************************************/
-// METHOD: convert()
-/// Convert the number object to another unit from string.
-/**
- */
-
-double
-RpNumber::convert(std::string toUnitStr, int* result) {
-
-    const RpUnits* toUnit = NULL;
-    toUnit = RpUnits::find(toUnitStr);
-    if (!toUnit) {
-        // should raise error! 
-        // conversion not defined because unit does not exist
-        if (result) {
-            *result = -1;
-        }
-        return 0.0;
-    }
-    return convert(toUnit, result); 
-}
-
-/**********************************************************************/
-// METHOD: convert()
-/// Convert the number object to another unit from RpUnits object.
-/**
- */
-
-double
-RpNumber::convert(const RpUnits* toUnit, int *result) {
-
-    return units->convert(toUnit,getCurrentValue(), result); 
-}
-
-/**********************************************************************/
-// METHOD: put()
-/// Store the information of this Rappture Object into the xml
-/**
- */
-//
-//RpNumber&
-//RpNumber::put() const {
-//
-//    
-//    return *this; 
-//}
-
 
 // -------------------------------------------------------------------- //
Index: /trunk/src/objects/RpNumber.h
===================================================================
--- /trunk/src/objects/RpNumber.h	(revision 1269)
+++ /trunk/src/objects/RpNumber.h	(revision 1270)
@@ -1,5 +1,6 @@
 /*
  * ======================================================================
- *  Copyright (c) 2004-2005  Purdue Research Foundation
+ *  AUTHOR:  Derrick Kearney, Purdue University
+ *  Copyright (c) 2005-2009  Purdue Research Foundation
  *
  *  See the file "license.terms" for information on usage and
@@ -7,12 +8,5 @@
  * ======================================================================
  */
-#include <iostream>
-#include <string>
-#include <sstream>
-#include <stdlib.h>
 #include <errno.h>
-
-
-// #include "RpLibrary.h"
 
 #ifndef _RpVARIABLE_H
@@ -20,9 +14,5 @@
 #endif
 
-#ifndef _RpUNITS_H
-    #include "RpUnits.h"
-#endif
-
-#ifndef _RpNUMBER_H 
+#ifndef _RpNUMBER_H
 #define _RpNUMBER_H
 
@@ -31,144 +21,36 @@
     public:
 
-        // users member fxns
+        RpNumber (  const char *path,
+                    const char *unit,
+                    double val);
 
-        /*
-        virtual RpNumber& setUnits(std::string newUnits);
-        */
-
-        virtual RpNumber& setDefaultValue(double newDefaultVal);
-        virtual RpNumber& setCurrentValue(double newCurrentVal);
-        virtual RpNumber& setMin(double newMin);
-        virtual RpNumber& setMax(double newMax);
-
-        std::string getUnits() const;
-        // changed from "Value" to "Val" because base class makes 
-        // these functions virtual and derived class has a different
-        // return type. compiler doesnt like this. need to find another
-        // way around this
-        //
-        // if we keep the null_val=NULL will that give us undefined behavior?
-        //
-        double getDefaultValue(void* null_val=NULL) const;
-        double getCurrentValue(void* null_val=NULL) const;
-        double getMin() const;
-        double getMax() const;
-
-        double convert( std::string toUnitStr, 
-                        int storeResult, 
-                        int* result = NULL  );
-        double convert(std::string toUnitStr, int* result = NULL);
-        double convert(const RpUnits* toUnit, int* result = NULL);
-
-        // place the information from this object into the xml library 'lib'
-        // virtual RpNumber& put(RpLibrary lib);
-        RpNumber& put() const;
-        RpNumber& put(double currentVal);
-
-
-
-        /*
-         * user provides a 'path' for where this object lives in xml file
-         * user calls define with standard hints as described in Number docs
-         *  'units' - string providing units of the number
-         *  'defaultVal' - numeric value to be used if user provides no value
-         *  'min' - (optional) minimum allowed value
-         *  'max' - (optional) maximum allowed value
-         *  'label' - (optional) name of the input for a gui field
-         *  'desc' - (optional) description of the input for the gui
-         *
-         *  Notes: 
-         *      if the user sets a min or max value the following applies:
-         *          if the value of min is greater than the value of default,
-         *          then min will be set to default
-         *
-         *          if the value of max is less than the value of default, 
-         *          then max will be set to default.
-         *
-         *
-         *
-         */
-
-        /* what about unit-less numbers */
-        RpNumber (
-                    std::string path, 
-                    std::string units,
-                    double defaultVal
-                )
-            :   RpVariable  (path, new double (defaultVal) ),
-                // units       (units),
-                min         (0),
-                max         (0),
-                minmaxSet   (0)
-        {
-            this->units = RpUnits::find(units);
-            if (! this->units) {
-                this->units = RpUnits::define(units,NULL);
-            }
-        }
-
-        RpNumber (
-                    std::string path, 
-                    std::string units,
-                    double defaultVal,
+        RpNumber (  const char *path,
+                    const char *unit,
+                    double val,
                     double min,
                     double max,
-                    std::string label,
-                    std::string desc
-                )
-            :   RpVariable  (path, new double (defaultVal), label, desc),
-                // units       (units),
-                min         (min),
-                max         (max),
-                minmaxSet   (0)
-        { 
+                    const char *label,
+                    const char *desc);
 
-            this->units = RpUnits::find(units);
-            if (! this->units) {
-                this->units = RpUnits::define(units,NULL);
-            }
+        RpNumber ( const RpNumber& o );
+        virtual ~RpNumber ();
 
-            if ((min == 0) && (max == 0)) {
-                minmaxSet = 0;
-            }
-            else {
+        virtual const double defaultValue    (double val);
+        virtual const double currentValue    (double val);
+        virtual const double min             (double val);
+        virtual const double max             (double val);
+        virtual const char *units            (const char *val);
+        // need to add a way to tell user conversion failed
+        virtual double convert               (const char *to);
 
-                if (min > defaultVal) {
-                    this->min = defaultVal;
-                }
-
-                if (max < defaultVal) {
-                    this->max = defaultVal;
-                }
-            }
-
-        }
-
-        // copy constructor
-        RpNumber ( const RpNumber& myRpNumber )
-            :   RpVariable(myRpNumber),
-                units       (myRpNumber.units),
-                min         (myRpNumber.min),
-                max         (myRpNumber.max),
-                minmaxSet   (myRpNumber.minmaxSet)
-        {}
-
-        // default destructor
-        // virtual ~RpNumber ()
-        virtual ~RpNumber ()
-        {
-            // clean up dynamic memory
-
-        }
     private:
 
-        // std::string units;
-        const RpUnits* units;
-        double min;
-        double max;
+        double _default;
+        double _current;
+        double _min;
+        double _max;
 
-        // flag to tell if the user specified the min and max values 
-        int minmaxSet;
-
+        // flag tells if user specified min and max values
+        int _minmaxSet;
 };
 
Index: /trunk/src/objects/RpPool.c
===================================================================
--- /trunk/src/objects/RpPool.c	(revision 1270)
+++ /trunk/src/objects/RpPool.c	(revision 1270)
@@ -0,0 +1,458 @@
+/*
+ * bltPool.c --
+ *
+ * Copyright 2001 Silicon Metrics, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and warranty
+ * disclaimer appear in supporting documentation, and that the names
+ * of Lucent Technologies any of their entities not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.
+ *
+ * Silicon Metrics disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability and
+ * fitness.  In no event shall Lucent Technologies be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether in
+ * an action of contract, negligence or other tortuous action, arising
+ * out of or in connection with the use or performance of this
+ * software.
+ */
+
+#include "RpInt.h"
+#include "RpPool.h"
+
+/*
+ * Rp_Pool --
+ *
+ *  Implements a pool memory allocator.
+ *
+ *    + It's faster allocating memory since malloc/free are called
+ *      only a fraction of the normal times.  Fixed size items can
+ *      be reused without deallocating/reallocating memory.
+ *    + You don't have the extra 8-16 byte overhead per malloc.
+ *    - Memory is freed only when the entire pool is destroyed.
+ *    - Memory is allocated in chunks. More memory is allocated
+ *      than used.
+ *    0 Depending upon allocation/deallocation patterns, locality
+ *      may be improved or degraded.
+ *
+ *      The pool is a chain of malloc'ed blocks.
+ *
+ *             +---------+  +---------+  +---------+
+ *       NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr
+ *             |---------|  |---------|  |---------|
+ *             | chunk1  |  | chunk2  |  | chunk3  |
+ *             +---------+  |         |  |         |
+ *                          +---------+  |         |
+ *                                       |         |
+ *                                       |         |
+ *                                       +---------+
+ *
+ *      Each chunk contains an integral number of fixed size items.
+ *      The number of items doubles until a maximum size is reached
+ *      (each subsequent new chunk will be the maximum).  Chunks
+ *      are allocated only when needed (no more space is available
+ *      in the last chunk).
+ *
+ *      The chain of blocks is only freed when the entire pool is
+ *      destroyed.
+ *
+ *      A freelist of unused items also maintained. Each freed item
+ *      is prepended to a free list.  Before allocating new chunks
+ *      the freelist is examined to see if an unused items exist.
+ *
+ *               chunk1       chunk2       chunk3
+ *            +---------+  +---------+  +---------+
+ *      NULL<-| unused  |  |         |  |         |
+ *            +----^----+  +---------+  +---------+
+ *            | unused  |<-| unused  |<-| unused  |
+ *            +---------+  +---------+  +----^----+
+ *            |         |  |         |  | unused  |
+ *            +---------+  |         |  +----^----+
+ *                         |         |  |    |    |
+ *                         +---------+  +----|----+
+ *                                      | usused  |<- freePtr
+ *                                      +---------+
+ */
+
+#define POOL_MAX_CHUNK_SIZE      ((1<<16) - sizeof(Rp_PoolChain))
+
+#ifndef ALIGN
+#define ALIGN(a) \
+    (((size_t)a + (sizeof(void *) - 1)) & (~(sizeof(void *) - 1)))
+#endif /* ALIGN */
+
+static Rp_PoolAllocProc VariablePoolAllocItem;
+static Rp_PoolFreeProc  VariablePoolFreeItem;
+static Rp_PoolAllocProc FixedPoolAllocItem;
+static Rp_PoolFreeProc  FixedPoolFreeItem;
+static Rp_PoolAllocProc StringPoolAllocItem;
+static Rp_PoolFreeProc  StringPoolFreeItem;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VariablePoolAllocItem --
+ *
+ *      Returns a new item.  First check if there is any more space
+ *      left in the current chunk.  If there isn't then next check
+ *      the free list for unused items.  Finally allocate a new
+ *      chunk and return its first item.
+ *
+ * Results:
+ *      Returns a new (possible reused) item.
+ *
+ * Side Effects:
+ *      A new memory chunk may be allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+static void *
+VariablePoolAllocItem(poolPtr, size)
+    struct Rp_PoolStruct *poolPtr;
+    size_t size;    /* Number of bytes to allocate. */
+{
+    Rp_PoolChain *chainPtr;
+    void *memPtr;
+
+    size = ALIGN(size);
+    if (size >= POOL_MAX_CHUNK_SIZE) {
+    /*
+     * Handle oversized requests by allocating a chunk to hold the
+     * single item and immediately placing it into the in-use list.
+     */
+        chainPtr = malloc(sizeof(Rp_PoolChain) + size);
+        if (poolPtr->headPtr == NULL) {
+            poolPtr->headPtr = chainPtr;
+        } else {
+            chainPtr->nextPtr = poolPtr->headPtr->nextPtr;
+            poolPtr->headPtr->nextPtr = chainPtr;
+        }
+        memPtr = (void *)chainPtr;
+    } else {
+        if (poolPtr->bytesLeft >= size) {
+            poolPtr->bytesLeft -= size;
+            memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
+        } else {
+            poolPtr->waste += poolPtr->bytesLeft;
+            /* Create a new block of items and prepend it to the in-use list */
+            poolPtr->bytesLeft = POOL_MAX_CHUNK_SIZE;
+            /* Allocate the requested chunk size, plus the header */
+            chainPtr = malloc(sizeof(Rp_PoolChain) + poolPtr->bytesLeft);
+            chainPtr->nextPtr = poolPtr->headPtr;
+            poolPtr->headPtr = chainPtr;
+            /* Peel off a new item. */
+            poolPtr->bytesLeft -= size;
+            memPtr = (char *)(chainPtr + 1) + poolPtr->bytesLeft;
+        }
+    }
+    return memPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VariablePoolFreeItem --
+ *
+ *      Placeholder for freeProc routine.  The pool memory is
+ *      not reclaimed or freed until the entire pool is released.
+ *
+ * Results:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static void
+VariablePoolFreeItem(poolPtr, item)
+    struct Rp_PoolStruct *poolPtr;
+    void *item;
+{
+    /* Does nothing */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringPoolAllocItem --
+ *
+ *      Returns a new item.  First check if there is any more space
+ *      left in the current chunk.  If there isn't then next check
+ *      the free list for unused items.  Finally allocate a new
+ *      chunk and return its first item.
+ *
+ * Results:
+ *      Returns a new (possible reused) item.
+ *
+ * Side Effects:
+ *      A new memory chunk may be allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+static void *
+StringPoolAllocItem(poolPtr, size)
+    struct Rp_PoolStruct *poolPtr;
+    size_t size;        /* Number of bytes to allocate. */
+{
+    Rp_PoolChain *chainPtr;
+    void *memPtr;
+
+    if (size >= POOL_MAX_CHUNK_SIZE) {
+        /*
+         * Handle oversized requests by allocating a chunk to hold the
+         * single item and immediately placing it into the in-use list.
+         */
+        chainPtr = malloc(sizeof(Rp_PoolChain) + size);
+        if (poolPtr->headPtr == NULL) {
+            poolPtr->headPtr = chainPtr;
+        } else {
+            chainPtr->nextPtr = poolPtr->headPtr->nextPtr;
+            poolPtr->headPtr->nextPtr = chainPtr;
+        }
+        memPtr = (void *)chainPtr;
+    } else {
+        if (poolPtr->bytesLeft >= size) {
+            poolPtr->bytesLeft -= size;
+            memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
+        } else {
+            poolPtr->waste += poolPtr->bytesLeft;
+            /* Create a new block of items and prepend it to the
+             * in-use list */
+            poolPtr->bytesLeft = POOL_MAX_CHUNK_SIZE;
+            /* Allocate the requested chunk size, plus the header */
+            chainPtr = malloc(sizeof(Rp_PoolChain) + poolPtr->bytesLeft);
+            chainPtr->nextPtr = poolPtr->headPtr;
+            poolPtr->headPtr = chainPtr;
+            /* Peel off a new item. */
+            poolPtr->bytesLeft -= size;
+            memPtr = (char *)(chainPtr + 1) + poolPtr->bytesLeft;
+        }
+    }
+    return memPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringPoolFreeItem --
+ *
+ *      Placeholder for freeProc routine.  String pool memory is
+ *      not reclaimed or freed until the entire pool is released.
+ *
+ * Results:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+/*ARGSUSED*/
+static void
+StringPoolFreeItem(poolPtr, item)
+    struct Rp_PoolStruct *poolPtr;
+    void *item;
+{
+    /* Does nothing */
+}
+
+/*
+ *       The fixed size pool is a chain of malloc'ed blocks.
+ *
+ *             +---------+  +---------+  +---------+
+ *       NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr
+ *             |---------|  |---------|  |---------|
+ *             | chunk1  |  | chunk2  |  | chunk3  |
+ *             +---------+  |         |  |         |
+ *                          +---------+  |         |
+ *                                       |         |
+ *                                       |         |
+ *                                       +---------+
+ *
+ *      Each chunk contains an integral number of fixed size items.
+ *      The number of items doubles until a maximum size is reached
+ *      (each subsequent new chunk will be the maximum).  Chunks
+ *      are allocated only when needed (no more space is available
+ *      in the last chunk).
+ *
+ *      The chain of blocks is only freed when the entire pool is
+ *      destroyed.
+ *
+ *      A freelist of unused items also maintained. Each freed item
+ *      is prepended to a free list.  Before allocating new chunks
+ *      the freelist is examined to see if an unused items exist.
+ *
+ *               chunk1       chunk2       chunk3
+ *            +---------+  +---------+  +---------+
+ *      NULL<-| unused  |  |         |  |         |
+ *            +----^----+  +---------+  +---------+
+ *            | unused  |<-| unused  |<-| unused  |
+ *            +---------+  +---------+  +----^----+
+ *            |         |  |         |  | unused  |
+ *            +---------+  |         |  +----^----+
+ *                         |         |  |    |    |
+ *                         +---------+  +----|----+
+ *                                      | usused  |<- freePtr
+ *                                      +---------+
+ */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FixedPoolFreeItem --
+ *
+ *      Returns a new item.  First check if there is any more space
+ *      left in the current chunk.  If there isn't then next check
+ *      the free list for unused items.  Finally allocate a new
+ *      chunk and return its first item.
+ *
+ * Results:
+ *      Returns a new (possible reused) item.
+ *
+ * Side Effects:
+ *      A new memory chunk may be allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+static void *
+FixedPoolAllocItem(poolPtr, size)
+    struct Rp_PoolStruct *poolPtr;
+    size_t size;
+{
+    Rp_PoolChain *chainPtr;
+    void *newPtr;
+
+    size = ALIGN(size);
+    if (poolPtr->itemSize == 0) {
+        poolPtr->itemSize = size;
+    }
+    assert(size == poolPtr->itemSize);
+
+    if (poolPtr->bytesLeft > 0) {
+        poolPtr->bytesLeft -= poolPtr->itemSize;
+        newPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
+    } else if (poolPtr->freePtr != NULL) { /* Reuse from the free list. */
+        /* Reuse items on the free list */
+        chainPtr = poolPtr->freePtr;
+        poolPtr->freePtr = chainPtr->nextPtr;
+        newPtr = (void *)chainPtr;
+    } else {            /* Allocate another block. */
+
+        /* Create a new block of items and prepend it to the in-use list */
+        poolPtr->bytesLeft = poolPtr->itemSize * (1 << poolPtr->poolSize);
+        if (poolPtr->bytesLeft < POOL_MAX_CHUNK_SIZE) {
+            poolPtr->poolSize++; /* Keep doubling the size of the new
+                                  * chunk up to a maximum size. */
+        }
+        /* Allocate the requested chunk size, plus the header */
+        chainPtr = malloc(sizeof(Rp_PoolChain) + poolPtr->bytesLeft);
+        chainPtr->nextPtr = poolPtr->headPtr;
+        poolPtr->headPtr = chainPtr;
+
+        /* Peel off a new item. */
+        poolPtr->bytesLeft -= poolPtr->itemSize;
+        newPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
+    }
+    return newPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FixedPoolFreeItem --
+ *
+ *      Frees an item.  The actual memory is not freed.  The item
+ *      instead is prepended to a freelist where it may be reclaimed
+ *      and used again.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      Item is placed on the pool's free list.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+FixedPoolFreeItem(poolPtr, item)
+    struct Rp_PoolStruct *poolPtr;
+    void *item;
+{
+    Rp_PoolChain *chainPtr = (Rp_PoolChain *)item;
+
+    /* Prepend the newly deallocated item to the free list. */
+    chainPtr->nextPtr = poolPtr->freePtr;
+    poolPtr->freePtr = chainPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_PoolCreate --
+ *
+ *      Creates a new memory pool for fixed-size/variable-size/string
+ *      items.
+ *
+ * Results:
+ *      Returns a pointer to the newly allocated pool.
+ *
+ *---------------------------------------------------------------------- 
+ */
+
+Rp_Pool
+Rp_PoolCreate(type)
+    int type;
+{
+    struct Rp_PoolStruct *poolPtr;
+
+    poolPtr = malloc(sizeof(struct Rp_PoolStruct));
+    switch (type) {
+    case RP_VARIABLE_SIZE_ITEMS:
+        poolPtr->allocProc = VariablePoolAllocItem;
+        poolPtr->freeProc = VariablePoolFreeItem;
+        break;
+    case RP_FIXED_SIZE_ITEMS:
+        poolPtr->allocProc = FixedPoolAllocItem;
+        poolPtr->freeProc = FixedPoolFreeItem;
+        break;
+    case RP_STRING_ITEMS:
+        poolPtr->allocProc = StringPoolAllocItem;
+        poolPtr->freeProc = StringPoolFreeItem;
+        break;
+    }
+    poolPtr->headPtr = poolPtr->freePtr = NULL;
+    poolPtr->waste = poolPtr->bytesLeft = 0;
+    poolPtr->poolSize = poolPtr->itemSize = 0;
+    return poolPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Rp_PoolDestroy --
+ *
+ *      Destroys the given memory pool.  The chain of allocated blocks
+ *      are freed.  The is the only time that memory is actually freed.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      All memory used by the pool is freed.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Rp_PoolDestroy(poolPtr)
+    struct Rp_PoolStruct *poolPtr;
+{
+    register Rp_PoolChain *chainPtr, *nextPtr;
+
+    for (chainPtr = poolPtr->headPtr; chainPtr != NULL; chainPtr = nextPtr) {
+        nextPtr = chainPtr->nextPtr;
+        free(chainPtr);
+    }
+    free(poolPtr);
+}
+
Index: /trunk/src/objects/RpPool.h
===================================================================
--- /trunk/src/objects/RpPool.h	(revision 1270)
+++ /trunk/src/objects/RpPool.h	(revision 1270)
@@ -0,0 +1,36 @@
+#ifndef RP_POOL_H
+#define RP_POOL_H
+
+typedef struct Rp_PoolChainStruct {
+   struct Rp_PoolChainStruct *nextPtr;
+} Rp_PoolChain;
+
+#define RP_STRING_ITEMS         0
+#define RP_FIXED_SIZE_ITEMS     1
+#define RP_VARIABLE_SIZE_ITEMS  2
+
+typedef struct Rp_PoolStruct *Rp_Pool;
+
+typedef void *(Rp_PoolAllocProc) _ANSI_ARGS_((Rp_Pool pool, size_t size));
+typedef void (Rp_PoolFreeProc) _ANSI_ARGS_((Rp_Pool pool, void *item));
+
+struct Rp_PoolStruct {
+    Rp_PoolChain *headPtr;  /* Chain of malloc'ed chunks. */
+    Rp_PoolChain *freePtr;  /* List of deleted items. This is only used
+                             * for fixed size items. */
+    size_t poolSize;        /* Log2 of # of items in the current block. */
+    size_t itemSize;        /* Size of an item. */
+    size_t bytesLeft;       /* # of bytes left in the current chunk. */
+    size_t waste;
+
+    Rp_PoolAllocProc *allocProc;
+    Rp_PoolFreeProc *freeProc;
+};
+
+extern Rp_Pool Rp_PoolCreate _ANSI_ARGS_((int type));
+extern void Rp_PoolDestroy _ANSI_ARGS_((Rp_Pool pool));
+
+#define Rp_PoolAllocItem(poolPtr, n) (*((poolPtr)->allocProc))(poolPtr, n)
+#define Rp_PoolFreeItem(poolPtr, item) (*((poolPtr)->freeProc))(poolPtr, item)
+
+#endif /* RP_POOL_H */
Index: /trunk/src/objects/RpUtils2.c
===================================================================
--- /trunk/src/objects/RpUtils2.c	(revision 1270)
+++ /trunk/src/objects/RpUtils2.c	(revision 1270)
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+void
+Rp_Assert(testExpr, fileName, lineNumber)
+    char *testExpr;
+    char *fileName;
+    int lineNumber;
+{
+    fprintf(stderr, "line %d of %s: Assert \"%s\" failed\n",
+    lineNumber, fileName, testExpr);
+    fflush(stderr);
+    abort();
+}
+
+void
+Rp_Panic (
+    const char *format,
+    ...)
+{
+    va_list argList;
+
+    va_start(argList, format);
+    vfprintf(stderr, format, argList);
+    fprintf(stderr, "\n");
+    fflush(stderr);
+    abort();
+}
Index: /trunk/src/objects/RpVariable.cc
===================================================================
--- /trunk/src/objects/RpVariable.cc	(revision 1269)
+++ /trunk/src/objects/RpVariable.cc	(revision 1270)
@@ -7,5 +7,5 @@
  * ======================================================================
  *  AUTHOR:  Derrick Kearney, Purdue University
- *  Copyright (c) 2004-2005  Purdue Research Foundation
+ *  Copyright (c) 2005-2009  Purdue Research Foundation
  *
  *  See the file "license.terms" for information on usage and
@@ -14,207 +14,115 @@
  */
 
- #include "RpVariable.h"
+#include <cstring>
+#include <stdlib.h>
+#include "RpVariable.h"
+#include "RpHashHelper.h"
 
-/**********************************************************************/
-// METHOD: setPath()
-/// Set the path of this object
-/**
- */
-
-RpVariable&
-RpVariable::setPath(std::string newPath)
+RpVariable::RpVariable()
 {
-    path = newPath;
-    return *this; 
+    __init();
 }
 
-/**********************************************************************/
-// METHOD: setDefaultValue()
-/// Set the default value of this object
-/**
- */
-
-RpVariable&
-RpVariable::setDefaultValue(void* newDefaultVal)
+RpVariable::RpVariable(const RpVariable& o)
+    :
+        _path (o._path)
 {
-    // who is responsible for freeing the pointer?
-    defaultVal = newDefaultVal; 
-    return *this; 
+    if (o._h != NULL) {
+        Rp_HashCopy(_h,o._h,charCpyFxn);
+    }
 }
 
-/**********************************************************************/
-// METHOD: setCurrentValue()
-/// Set the current value of this object
-/**
- */
-
-RpVariable&
-RpVariable::setCurrentValue(void* newCurrentVal)
+RpVariable::~RpVariable()
 {
-    // who is responsible for freeing the pointer?
-    currentVal = newCurrentVal; 
-    return *this; 
+    __close();
 }
 
-/**********************************************************************/
-// METHOD: setLabel()
-/// Set the label of this object
-/**
- */
-
-RpVariable&
-RpVariable::setLabel(std::string newLabel)
+const char *
+RpVariable::label(
+    const char *val)
 {
-    about.setLabel(newLabel); 
-    return *this; 
+    return (const char *) property("label",val);
 }
 
-/**********************************************************************/
-// METHOD: setDesc()
-/// Set the desc of this object
-/**
- */
-
-RpVariable& 
-RpVariable::setDesc(std::string newDesc)
+const char *
+RpVariable::desc(
+    const char *val)
 {
-    about.setDesc(newDesc); 
-    return *this; 
+    return (const char *) property("desc",val);
 }
 
-/**********************************************************************/
-// METHOD: setHints()
-/// Set the hints of this object
-/**
- */
-
-RpVariable& 
-RpVariable::setHints(std::string newHints)
+const char *
+RpVariable::hints(
+    const char *val)
 {
-    about.setHints(newHints); 
-    return *this; 
+    return (const char *) property("hints",val);
 }
 
-/**********************************************************************/
-// METHOD: setColor()
-/// Set the color of this object
-/**
- */
-
-RpVariable& 
-RpVariable::setColor(std::string newColor)
+const char *
+RpVariable::color(
+    const char *val)
 {
-    about.setColor(newColor); 
-    return *this; 
+    return (const char *) property("color",val);
 }
 
-/**********************************************************************/
-// METHOD: setIcon()
-/// Set the icon of this object 
-/**
- */
-
-RpVariable& 
-RpVariable::setIcon(std::string newIcon)
+const char *
+RpVariable::icon(
+    const char *val)
 {
-    about.setIcon(newIcon); 
-    return *this; 
+    return (const char *) property("icon",val);
 }
 
-
-/**********************************************************************/
-// METHOD: getPath()
-/// Report the path of this object
-/**
- */
-
-std::string 
-RpVariable::getPath() const
+const char *
+RpVariable::path(
+    const char *val)
 {
-    return path; 
+    return (const char *) property("path",val);
 }
 
-/**********************************************************************/
-// METHOD: getDefaultValue()
-/// Report the default value of the object
-/**
- */
+const void *
+RpVariable::property(
+    const char *key,
+    const void *val)
+{
+    const void *r = NULL;
+    if (_h == NULL) {
+        // hash table does not exist, create it
+        _h = (Rp_HashTable*) malloc(sizeof(Rp_HashTable));
+        Rp_InitHashTable(_h,RP_STRING_KEYS);
+        return NULL;
+    }
 
-void*
-RpVariable::getDefaultValue() const
-{
-    return defaultVal; 
+    if (val == NULL) {
+        // get the value
+        r = Rp_HashSearchNode(_h,key);
+    } else {
+        //set the value
+        Rp_HashRemoveNode(_h,key);
+        Rp_HashAddNode(_h,key,val);
+        r = val;
+    }
+
+    return r;
 }
 
-/**********************************************************************/
-// METHOD: getCurrentValue()
-/// Report the current value of the object
-/**
- */
-
-void* 
-RpVariable::getCurrentValue() const
+void
+RpVariable::__init()
 {
-    return currentVal; 
+    _path = NULL;
+    _h = NULL;
 }
 
-/**********************************************************************/
-// METHOD: getLabel()
-/// Report the label of the object
-/**
- */
+void
+RpVariable::__close()
+{
+    if (_path != NULL) {
+        free((void *)_path);
+    }
 
-std::string 
-RpVariable::getLabel() const
-{
-    return about.getLabel(); 
-}
+    if (_h != NULL) {
+        Rp_DeleteHashTable(_h);
+    }
 
-/**********************************************************************/
-// METHOD: getDesc()
-/// Report the desc of the object
-/**
- */
-
-std::string 
-RpVariable::getDesc() const
-{
-    return about.getDesc(); 
-}
-
-/**********************************************************************/
-// METHOD: getHints()
-/// Report the hints of this object
-/**
- */
-
-std::string 
-RpVariable::getHints() const
-{
-    return about.getHints(); 
-}
-
-/**********************************************************************/
-// METHOD: getColor()
-/// Report the color of this object
-/**
- */
-
-std::string 
-RpVariable::getColor() const
-{
-    return about.getColor(); 
-}
-
-/**********************************************************************/
-// METHOD: getIcon()
-/// Report the icon of this object
-/**
- */
-
-std::string 
-RpVariable::getIcon() const
-{
-    return about.getIcon(); 
+    __init();
 }
 
Index: /trunk/src/objects/RpVariable.h
===================================================================
--- /trunk/src/objects/RpVariable.h	(revision 1269)
+++ /trunk/src/objects/RpVariable.h	(revision 1270)
@@ -1,5 +1,6 @@
 /*
  * ======================================================================
- *  Copyright (c) 2004-2005  Purdue Research Foundation
+ *  AUTHOR:  Derrick S. Kearney, Purdue University
+ *  Copyright (c) 2005-2009  Purdue Research Foundation
  *
  *  See the file "license.terms" for information on usage and
@@ -7,99 +8,39 @@
  * ======================================================================
  */
-#include <iostream>
-#include <string>
-#include <sstream>
-#include <stdlib.h>
-#include <errno.h>
 
+#ifndef _RpVARIABLE_H
+#define _RpVARIABLE_H
 
-// #include "RpLibrary.h"
-
-#ifndef _RpABOUT_H
-    #include "RpAbout.h"
-#endif
-
-#ifndef _RpVARIABLE_H 
-#define _RpVARIABLE_H
+#include "RpInt.h"
+#include "RpHash.h"
 
 class RpVariable
 {
     public:
-        
-        // users member fxns
+        RpVariable ();
+        RpVariable (const RpVariable& o);
+        virtual ~RpVariable();
 
-        virtual RpVariable& setPath         (std::string newPath);
-        virtual RpVariable& setDefaultValue (void* newDefaultVal);
-        virtual RpVariable& setCurrentValue (void* newCurrentVal);
-        virtual RpVariable& setLabel        (std::string newLabel);
-        virtual RpVariable& setDesc         (std::string newDesc);
-        virtual RpVariable& setHints        (std::string newHints);
-        virtual RpVariable& setColor        (std::string newColor);
-        virtual RpVariable& setIcon         (std::string newIcon);
-
-        virtual std::string getPath         () const;
-        /* maybe we dont need 2 get functions? */
-        virtual void* getDefaultValue       () const;
-        virtual void* getCurrentValue       () const;
-        virtual std::string getLabel        () const;
-        virtual std::string getDesc         () const;
-        virtual std::string getHints        () const;
-        virtual std::string getColor        () const;
-        virtual std::string getIcon         () const;
-
-        // place the information from this object into the xml library 'lib'
-        // virtual RpNumber& put(RpLibrary lib);
-        // virtual RpVariable& put() const;
-
-        // we need a copy of defaultVal in currentVal, not the same pointer.
-        // need to fix this.
-        
-        RpVariable (
-                    std::string path, 
-                    void* defaultVal
-                )
-            :   about       (RpAbout()),
-                path        (path),
-                defaultVal  (defaultVal),
-                currentVal  (defaultVal)
-        {
-            // about's default no-arg const is called
-        };
-
-        RpVariable (
-                    std::string path, 
-                    void* defaultVal,
-                    std::string label,
-                    std::string desc
-                )
-            :   about       (RpAbout(label,desc)),
-                path        (path),
-                defaultVal  (defaultVal),
-                currentVal  (defaultVal)
-        {}
-        
-        // copy constructor
-        RpVariable ( const RpVariable& myRpVariable ) 
-                // will the RpAbout copy constructor be called here?
-            :   about       (RpAbout(myRpVariable.about)),
-                path        (myRpVariable.path),
-                defaultVal  (myRpVariable.defaultVal),
-                currentVal  (myRpVariable.currentVal)
-        {}
-
-        // default destructor
-        virtual ~RpVariable ()
-        {
-            // clean up dynamic memory
-        }
+        virtual const char *label           (const char *val);
+        virtual const char *desc            (const char *val);
+        virtual const char *hints           (const char *val);
+        virtual const char *color           (const char *val);
+        virtual const char *icon            (const char *val);
+        virtual const char *path            (const char *val);
+        virtual const void *property        (const char *key, const void *val);
 
     private:
 
-        RpAbout about;
-        std::string path;
-        void* defaultVal;
-        void* currentVal;
+        /// path of the object in the xml tree and key in hash tables
+        const char *_path;
 
+        /// hash table holding other object properties
+        Rp_HashTable *_h;
 
+        /// initialize the object, set the data members to 0 or null
+        void __init();
+
+        /// close out the object, freeing its memory
+        void __close();
 };
 
