Index: /branches/jch-memory/psLib/src/sys/psAssert.h
===================================================================
--- /branches/jch-memory/psLib/src/sys/psAssert.h	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psAssert.h	(revision 10811)
@@ -0,0 +1,265 @@
+#ifndef PS_ASSERT_H
+#define PS_ASSERT_H
+
+#include <assert.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "psMemory.h"
+#include "psError.h"
+#include "psLogMsg.h"
+
+// Ensure this is a psLib pointer, by checking for the memblock bounds.
+#define PS_ASSERT_PTR(NAME, RVAL) \
+{ \
+    if (NAME == NULL) return(RVAL); \
+    psMemBlock *mb = (psMemBlock*)(NAME) - 1; \
+    if (mb->startblock != P_PS_MEMMAGIC || mb->endblock != P_PS_MEMMAGIC || \
+            *(psPtr *)((int8_t *) (mb + 1) + mb->userMemorySize) != P_PS_MEMMAGIC) { \
+        psError(PS_ERR_MEMORY_CORRUPTION, false, \
+                "Error: Pointer %s is corrupted or not on the PS memory system.", \
+                #NAME); \
+        return (RVAL); \
+    } \
+}
+
+#define PS_ASSERT_INT_UNEQUAL(NAME1, NAME2, RVAL) \
+if ((NAME1) == (NAME2)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s and %s are equal.", \
+            #NAME1, #NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_EQUAL(NAME1, NAME2, RVAL) \
+if ((NAME1) != (NAME2)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s and %s are not equal.", \
+            #NAME1, #NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_NONNEGATIVE(NAME, RVAL) \
+if ((NAME) < 0) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Error: %s is less than 0.", #NAME); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_POSITIVE(NAME, RVAL) \
+if ((NAME) < 1) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s is 0 or less.", #NAME); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_ZERO(NAME, RVAL) \
+if ((NAME) != 0) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s is 0.", #NAME); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_NONZERO(NAME, RVAL) \
+if ((NAME) == 0) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s is 0.", #NAME); \
+    return(RVAL); \
+}
+
+// XXX: Where did these int casts come from?
+#define PS_ASSERT_INT_WITHIN_RANGE(NAME, LOWER, UPPER, RVAL) \
+if ((int)(NAME) < LOWER || (int)(NAME) > UPPER) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s, %d, is out of range.  Must be between %d and %d.", \
+            #NAME,(int)NAME,LOWER,UPPER); \
+    return RVAL; \
+}
+
+#define PS_ASSERT_INT_LESS_THAN(VAR1, VAR2, RVAL) \
+if (!(VAR1 < VAR2)) { \
+    psError(PS_ERR_UNKNOWN, true, \
+            "Error: %s is not less than %s (%d, %d)", #VAR1, #VAR2, VAR1, VAR2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_LESS_THAN_OR_EQUAL(VAR1, VAR2, RVAL) \
+if (!(VAR1 <= VAR2)) { \
+    psError(PS_ERR_UNKNOWN, true, \
+            "Error: %s is not less than %s (%d, %d)", #VAR1, #VAR2, VAR1, VAR2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_LARGER_THAN(NAME1, NAME2, RVAL) \
+if (!((NAME1) > (NAME2))) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: !(%s > %s) (%d %d).", \
+            #NAME1, #NAME2, NAME1, NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_INT_LARGER_THAN_OR_EQUAL(NAME1, NAME2, RVAL) \
+if (!((NAME1) >= (NAME2))) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: !(%s >= %s) (%d %d).", \
+            #NAME1, #NAME2, NAME1, NAME2); \
+    return(RVAL); \
+}
+#define PS_ASSERT_FLOAT_LARGER_THAN(NAME1, NAME2, RVAL) \
+if (!((NAME1) > (NAME2))) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: !(%s > %s) (%f %f).", \
+            #NAME1, #NAME2, NAME1, NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(NAME1, NAME2, RVAL) \
+if (!((NAME1) >= (NAME2))) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: !(%s >= %s) (%f %f).", \
+            #NAME1, #NAME2, NAME1, NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_FLOAT_LESS_THAN(NAME1, NAME2, RVAL) \
+if (!((NAME1) < (NAME2))) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: !(%s < %s) (%f %f).", \
+            #NAME1, #NAME2, NAME1, NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(NAME1, NAME2, RVAL) \
+if (!((NAME1) <= (NAME2))) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: !(%s <= %s) (%f %f).", \
+            #NAME1, #NAME2, NAME1, NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_FLOAT_NON_EQUAL(NAME1, NAME2, RVAL) \
+if (fabs((NAME2) - (NAME1)) < FLT_EPSILON) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s and %s are equal.", \
+            #NAME1, #NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_FLOAT_EQUAL(NAME1, NAME2, RVAL) \
+if (fabs((NAME2) - (NAME1)) > FLT_EPSILON) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s and %s are not equal.", \
+            #NAME1, #NAME2); \
+    return(RVAL); \
+}
+
+// Return an error if the arg lies outside the supplied range.
+#define PS_ASSERT_FLOAT_WITHIN_RANGE(NAME, LOWER, UPPER, RVAL) \
+if ((NAME) < (LOWER) || (NAME) > (UPPER)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s, %f, is out of range.  Must be between %f and %f.", \
+            #NAME, NAME, LOWER, UPPER); \
+    return RVAL; \
+}
+
+#define PS_ASSERT_FLOAT_REAL(NAME, RVAL) \
+if (!isfinite(NAME)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s=%f is not a real value.\n", \
+            #NAME, NAME); \
+    return RVAL; \
+}
+
+#define PS_ASSERT_DOUBLE_WITHIN_RANGE(NAME, LOWER, UPPER, RVAL) \
+if ((NAME) < (LOWER) || (NAME) > (UPPER)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s, %lf, is out of range.  Must be between %lf and %lf.", \
+            #NAME, NAME, LOWER, UPPER); \
+    return RVAL; \
+}
+
+#define PS_ASSERT_LONG_WITHIN_RANGE(NAME, LOWER, UPPER, RVAL) \
+if ((NAME) < (LOWER) || (NAME) > (UPPER)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s, %ld, is out of range.  Must be between %ld and %ld.", \
+            #NAME, NAME, LOWER, UPPER); \
+    return RVAL; \
+}
+
+#define PS_ASSERT_LONG_LARGER_THAN_OR_EQUAL(NAME1, NAME2, RVAL) \
+if (!((NAME1) >= (NAME2))) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Error: !(%s >= %s) (%ld %ld).",\
+            #NAME1, #NAME2, NAME1, NAME2); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_S64_WITHIN_RANGE(NAME, LOWER, UPPER, RVAL) \
+if ((NAME) < (LOWER) || (NAME) > (UPPER)) { \
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
+            "Error: %s, %" PRId64 ", is out of range.  Must be between %" PRId64 " and %" PRId64 ".", \
+            #NAME, NAME, LOWER, UPPER); \
+    return RVAL; \
+}
+
+/*****************************************************************************
+Macros which take a generic psLib type and determine if it is NULL, or has
+the wrong type.
+*****************************************************************************/
+#define PS_WARN_PTR_NON_NULL(NAME) \
+if ((NAME) == NULL) { \
+    psLogMsg(__func__, PS_LOG_WARN, "WARNING: %s is NULL.", #NAME); \
+} \
+
+#define PS_ASSERT_PTR_NON_NULL(NAME, RVAL) PS_ASSERT_GENERAL_PTR_NON_NULL(NAME, return RVAL)
+#define PS_ASSERT_GENERAL_PTR_NON_NULL(NAME, CLEANUP) \
+if ((NAME) == NULL) { \
+    psError(PS_ERR_BAD_PARAMETER_NULL, true, \
+            "Unallowable operation: %s is NULL.", \
+            #NAME); \
+    CLEANUP; \
+}
+
+#define PS_ASSERT_PTR_TYPE(NAME, TYPE, RVAL) \
+if ((NAME)->type.type != TYPE) { \
+    psError(PS_ERR_BAD_PARAMETER_TYPE, true, \
+            "Unallowable operation: %s has incorrect type.", \
+            #NAME); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_PTR_DIMEN(NAME, DIMEN, RVAL) PS_ASSERT_GENERAL_PTR_DIMEN(NAME, DIMEN, return RVAL)
+#define PS_ASSERT_GENERAL_PTR_DIMEN(NAME, DIMEN, CLEANUP) \
+if ((NAME)->type.dimen != DIMEN) { \
+    psError(PS_ERR_BAD_PARAMETER_TYPE, true, \
+            "Unallowable operation: %s has incorrect dimensionality.", \
+            #NAME); \
+    CLEANUP; \
+}
+
+#define PS_ASSERT_PTR_DIMEN_GENERAL_NOT(NAME, DIMEN, CLEANUP) \
+if ((NAME)->type.dimen == DIMEN) { \
+    psError(PS_ERR_BAD_PARAMETER_TYPE, true, \
+            "Unallowable operation: %s has incorrect dimensionality.", \
+            #NAME); \
+    CLEANUP; \
+}
+
+
+#define PS_ASSERT_PTRS_SIZE_EQUAL(PTR1, PTR2, RVAL) \
+if (PTR1->n != PTR2->n) { \
+    psError(PS_ERR_BAD_PARAMETER_SIZE, true, \
+            "ptr %s has size %d, ptr %s has size %d.", \
+            #PTR1, PTR1->n, #PTR2, PTR2->n); \
+    return(RVAL); \
+}
+
+#define PS_ASSERT_PTR_TYPE_EQUAL(PTR1, PTR2, RVAL) PS_ASSERT_PTRS_TYPE_EQUAL_GENERAL(PTR1, PTR2, return RVAL)
+#define PS_ASSERT_PTRS_TYPE_EQUAL_GENERAL(PTR1, PTR2, CLEANUP) \
+if (PTR1->type.type != PTR2->type.type) { \
+    psError(PS_ERR_BAD_PARAMETER_TYPE, true, \
+            "ptr %s has type %d, ptr %s has type %d.", \
+            #PTR1, PTR1->type.type, #PTR2, PTR2->type.type); \
+    CLEANUP; \
+}
+
+
+#endif
Index: /branches/jch-memory/psLib/src/sys/psConfigure.c
===================================================================
--- /branches/jch-memory/psLib/src/sys/psConfigure.c	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psConfigure.c	(revision 10811)
@@ -0,0 +1,160 @@
+/** @file  psConfigure.c
+ *
+ *  @brief Contains the declarations for initialization, memory finalization,
+ *   and configuration.
+ *
+ *  These functions initalize psLib data before the beginning of a run and
+ *  remove (finalize) the same data after the run is complete. A function is
+ *  also provided to return the current psLib version.
+ *
+ *  @ingroup Configure
+ *
+ *  @author Ross Harman, MHPCC
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.20 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-12-06 03:01:42 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "psMemory.h"
+#include "psTrace.h"
+#include "psString.h"
+#include "psTime.h"
+#include "psEarthOrientation.h"
+#include "psError.h"
+#include "psConfigure.h"
+
+#include "config.h"
+
+static char *memCheckName = NULL;       // Filename to which to write results of mem check
+static FILE *memCheckFile = NULL;       // File to which to write results of mem check
+
+static const char *cvsTag = "$Name: not supported by cvs2svn $"; // CVS tag name
+
+psString psLibVersion(void)
+{
+    psString version = NULL;            // Version, to return
+    psStringAppend(&version, "%s-%s",PACKAGE_NAME,PACKAGE_VERSION);
+    return version;
+}
+
+psString psLibVersionLong(void)
+{
+    psString version = psLibVersion();    // Version, to return
+    psString tag = psStringStripCVS(cvsTag, "Name"); // CVS tag
+
+    psStringAppend(&version, " (cvs tag %s), %s, %s with"
+                   #ifdef HAVE_PSDB
+                   "out"
+                   #endif
+                   " psDB", tag, __DATE__, __TIME__);
+
+    psFree(tag);
+    return version;
+}
+
+// Print details of a memory problem to the appropriate file
+static void memoryProblem(const psMemBlock *ptr, // the pointer to the problematic memory block.
+                          const char *file, // the file in which the problem originated
+                          int lineno    // the line number in which the problem originated
+                         )
+{
+    fprintf(memCheckFile,
+            "Memory corruption detected in memBlock %lu\n"
+            "\tFile %s, line %d, size %zd\n"
+            "\tPosts: %p %p %p\n",
+            ptr->id, file, lineno, ptr->userMemorySize, ptr->startblock, ptr->endblock,
+            (ptr + 1 + ptr->userMemorySize));
+}
+
+// Check the memory; intended for use on exit, but might be used elsewhere
+void p_psMemoryCheck(void)
+{
+    if (!memCheckName || strlen(memCheckName) == 0) {
+        return;
+    }
+
+    memCheckFile = fopen(memCheckName, "w"); // File to write leaks to
+    if (!memCheckFile) {
+        psError(PS_ERR_IO, true, "Unable to open leaks file, %s\n", memCheckName);
+        return;
+    }
+
+    int nLeaks = psMemCheckLeaks(0, NULL, memCheckFile, false); // Number of leaks
+    if (nLeaks > 0) {
+        psLogMsg(__func__, PS_LOG_WARN, "%d memory leaks found; list written to %s.\n", nLeaks, memCheckName);
+    } else {
+        psLogMsg(__func__, PS_LOG_INFO, "No memory leaks found.\n");
+    }
+
+    int nCorrupted;                     // Number of corrupted memory blocks
+    (void)psMemProblemCallbackSet((psMemProblemCallback)memoryProblem); // Set callback for corruption
+    nCorrupted = psMemCheckCorruption(false);
+    if (nCorrupted > 0) {
+        psError(PS_ERR_UNKNOWN, true, "%d memory blocks corrupted; list written to %s.\n", nCorrupted, memCheckName);
+    } else {
+        psLogMsg(__func__, PS_LOG_INFO, "No memory corruption found.\n");
+    }
+
+    fclose(memCheckFile);
+
+    return;
+}
+
+
+void psLibInit(const char* timeConfig)
+{
+    // XXX: Still needs error codes to be set
+
+    if (timeConfig && strlen(timeConfig) > 0) {
+        if (!p_psTimeInit(timeConfig)) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                    _("Failed to initialize %s."), "psTime");
+            return;
+        }
+    }
+    if (!p_psEOCInit()) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                _("Failed to initialize %s."), "psEOC");
+        return;
+    }
+
+    // Does the user want memory checking at exit?
+    memCheckName = getenv("PS_ALLOC_CHECK"); // The value of PS_ALLOC_CHECK
+    if (memCheckName && strlen(memCheckName) > 0) {
+        atexit(&p_psMemoryCheck);
+    }
+}
+
+void psLibFinalize(void)
+{
+    // Users of persistent memory should free them in this function
+
+    // Stop timers
+    psTimerStop();
+
+    // Free the time tables
+    if (!p_psTimeFinalize()) {
+        psError(PS_ERR_UNKNOWN, false,
+                _("Failed to finalize %s."), "psTime");
+        return;
+    }
+
+    // Free the precession tables
+    if (!p_psEOCFinalize()) {
+        psError(PS_ERR_UNKNOWN, false,
+                _("Failed to finalize %s."), "psEOC");
+        return;
+    }
+
+    // Free the trace system
+    psTraceReset();
+
+    // Free the error system
+    psErrorClear();
+
+}
Index: /branches/jch-memory/psLib/src/sys/psError.c
===================================================================
--- /branches/jch-memory/psLib/src/sys/psError.c	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psError.c	(revision 10811)
@@ -0,0 +1,283 @@
+/** @file  psError.c
+ *
+ *  @brief Contains the definitions for the error reporting functions
+ *
+ *  Error reporting functions shall be used to create log entries in the
+ *  event errors are detected.  The messages shall give enough information
+ *  to allow the user to know where the error has occurred and the type
+ *  of error detected.
+ *
+ *  @author Joshua Hoblitt, University of Hawaii
+ *  @author Eric Van Alst, MHPCC
+ *
+ *  @version $Revision: 1.41 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-10-24 22:52:56 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#include <stdarg.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "psLogMsg.h"
+#include "psError.h"
+#include "psMemory.h"
+#include "psString.h"
+#include "psTrace.h"
+#include "psAbort.h"
+
+#define MAX_STRING_LENGTH 2048
+#define MAX_ERROR_STACK_SIZE 64
+
+static pthread_mutex_t lockErrorStack = PTHREAD_MUTEX_INITIALIZER;
+static bool errorStackKeyInitialized = false;
+static pthread_key_t errorStack_key;
+
+static void psFreeWrapper(void *ptr);
+static void psErrorStackPush(psErr* err);
+static psArray *psErrorStackGet(void);
+static void psErrFree(psErr* err);
+
+// needed for pthread_key_create() because p_psFree() does not match free()'s
+// prototype
+// XXX does something like this need to be global in psMmemory.h
+static void psFreeWrapper(void *ptr)
+{
+    psFree(ptr);
+}
+
+static void psErrorStackPush(psErr* err)
+{
+    psArray *errorStack = psErrorStackGet();
+
+    // push the item onto the stack and increment the error count
+    if (psArrayLength(errorStack) < MAX_ERROR_STACK_SIZE) {
+        // make the psErr persistent
+        p_psMemSetPersistent(err, true);
+        p_psMemSetPersistent(err->msg, true);
+        p_psMemSetPersistent(err->name, true);
+
+        psArrayAdd(errorStack, 0, err);
+    } else {
+        psAbort(__func__, "attempt to exceed maximum error stack depth of %ld",
+                (long)MAX_ERROR_STACK_SIZE);
+    }
+}
+
+static psArray *psErrorStackGet(void)
+{
+    // check to see if the error stack key has been initialized
+    pthread_mutex_lock(&lockErrorStack);
+    if (errorStackKeyInitialized == false) {
+        // note that each error stack will automatically be free'd when it's
+        // thread exits
+        if (pthread_key_create(&errorStack_key, psFreeWrapper)) {
+            psAbort(__func__, "pthread_key_create() failed");
+        }
+        errorStackKeyInitialized = true;
+    }
+    pthread_mutex_unlock(&lockErrorStack);
+
+    // check to see if the error stack for this thread has been allocated
+    psArray *errorStack = NULL;
+    if ((errorStack = pthread_getspecific(errorStack_key)) == NULL) {
+        // allocate the error stack
+        errorStack = psArrayAllocEmpty(MAX_ERROR_STACK_SIZE);
+        p_psMemSetPersistent(errorStack, true);
+        p_psMemSetPersistent(errorStack->data, true);
+        // store this threads error stack
+        // note that pthread_setspecifc() does not take a pointer as the first
+        // param
+        if (pthread_setspecific(errorStack_key, errorStack)) {
+            psAbort(__func__, "pthread_setspecific() failed");
+        }
+    }
+
+    return errorStack;
+}
+
+static void psErrFree(psErr* err)
+{
+    if (err != NULL) {
+        psFree(err->msg);
+        psFree(err->name);
+    }
+}
+
+psErr* psErrAlloc(const char* name, psErrorCode code, const char* msg)
+{
+    psErr* err = psAlloc(sizeof(psErr));
+    err->msg = psStringCopy(msg);
+    err->name = psStringCopy(name);
+    err->code = code;
+
+    psMemSetDeallocator(err, (psFreeFunc)psErrFree);
+
+    return err;
+}
+
+psErrorCode p_psError(const char* filename,
+                      unsigned int lineno,
+                      const char* func,
+                      psErrorCode code,
+                      bool new,
+                      const char* format,
+                      ...)
+{
+    char errMsg[MAX_STRING_LENGTH];
+    char msgName[MAX_STRING_LENGTH];
+
+    // if this the origin of a new error reset the error stack
+    if (new) {
+        psErrorClear();
+    }
+
+    snprintf(msgName, MAX_STRING_LENGTH, "%s (%s:%d)", func, filename, lineno);
+
+    va_list ap;
+    va_start(ap, format);
+
+    vsnprintf(errMsg, MAX_STRING_LENGTH, format, ap);
+
+    va_end(ap);
+
+    // Remove a single trailing \n from message -- it interferes with
+    // psErrorStackPrint
+    size_t len = strlen(errMsg);
+    if (len > 0 && errMsg[len - 1] == '\n') {
+        errMsg[len - 1] = '\0';
+    }
+
+    psErr *err = psErrAlloc(msgName, code, errMsg);
+    psErrorStackPush(err);
+
+    #ifndef PS_NO_TRACE
+    // Call tracing function with PS_LOG_ERROR level
+    // p_psTrace() automatically appends the the function name to the facility
+    // for us
+    p_psTrace(__FILE__, __LINE__, func, "err", PS_LOG_ERROR, "%s : %s", err->name, err->msg);
+    #endif
+
+    psFree(err);
+
+    return code;
+}
+
+void p_psWarning(const char* file,
+                 int lineno,
+                 const char* func,
+                 const char* format,
+                 ...)
+{
+    char msgName[MAX_STRING_LENGTH];
+
+    snprintf(msgName, MAX_STRING_LENGTH, "%s (%s:%d)", func, file, lineno);
+
+    va_list ap;
+    va_start(ap, format);
+
+    psLogMsgV(msgName, PS_LOG_WARN, format, ap);
+
+    va_end(ap);
+
+    return;
+}
+
+psErr* psErrorGet(long which)
+{
+    psErr* result;
+
+    psArray *errorStack = psErrorStackGet();
+
+    // Check for negative reference and if found return PS_ERR_NONE
+    if (which < 0 ) {
+        result = psErrAlloc("", PS_ERR_NONE, "");
+    } else {
+        // the which input is from the end of errorStack
+        which = psArrayLength(errorStack) - 1 - which;
+        if (which < 0 || which >= psArrayLength(errorStack)) {
+            // no error at the given location
+            result = psErrAlloc("", PS_ERR_NONE, "");
+        } else {
+            // a new reference passed back
+            result = psMemIncrRefCounter(errorStack->data[which]);
+        }
+    }
+
+    return result;
+}
+
+long psErrorGetStackSize()
+{
+    psArray *errorStack = psErrorStackGet();
+
+    return psArrayLength(errorStack);
+}
+
+psErr* psErrorLast(void)
+{
+    return psErrorGet(0);
+}
+
+psErrorCode psErrorCodeLast(void)
+{
+    const psErr *err = psErrorGet(0);
+    psErrorCode code = err->code;
+    psFree(err);
+
+    return code;
+}
+
+void psErrorClear(void)
+{
+    psArray *errorStack = psErrorStackGet();
+
+    for (long i = 0; i < psArrayLength(errorStack); i++) {
+        psErr *err = errorStack->data[i];
+
+        p_psMemSetPersistent(err, false);
+        p_psMemSetPersistent(err->msg, false);
+        p_psMemSetPersistent(err->name, false);
+    }
+
+    psArrayElementsFree(errorStack);
+}
+
+void psErrorStackPrint(FILE *fd, const char *format, ...)
+{
+    if (fd == NULL) {
+        fd = stdout;
+    }
+
+    va_list ap;             // variable list arguement pointer
+
+    va_start(ap, format);
+
+    psErrorStackPrintV(fd, format, ap);
+
+    va_end(ap);
+}
+
+void psErrorStackPrintV(FILE *fd, const char *format, va_list va)
+{
+    psArray *errorStack = psErrorStackGet();
+
+    vfprintf(fd, format, va);
+
+    for (long i = 0; i < psArrayLength(errorStack); i++) {
+        psErr *err = errorStack->data[i];
+        if(err->code >= PS_ERR_BASE) {
+            fprintf(fd," -> %s: %s\n     %s\n",
+                    err->name,
+                    psErrorCodeString(err->code),
+                    err->msg);
+        } else {
+            fprintf(fd," -> %s: %s\n     %s\n",
+                    err->name,
+                    strerror(err->code),
+                    err->msg);
+        }
+    }
+}
+
Index: /branches/jch-memory/psLib/src/sys/psError.h
===================================================================
--- /branches/jch-memory/psLib/src/sys/psError.h	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psError.h	(revision 10811)
@@ -0,0 +1,235 @@
+/** @file  psError.h
+ *
+ *  @brief Contains the declarations for the error reporting functions
+ *
+ *  Error reporting functions shall be used to create log entries in the
+ *  event errors are detected.  The messages shall give enough information
+ *  to allow the user to know where the error has occurred and the type
+ *  of error detected.
+ *
+ *  @ingroup ErrorHandling
+ *
+ *  @author Eric Van Alst, MHPCC
+ *
+ *  @version $Revision: 1.31 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-09-12 21:39:47 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_ERROR_H
+#define PS_ERROR_H
+
+#include<stdio.h>
+#include<stdbool.h>
+#include<stdarg.h>
+
+#include "psErrorCodes.h"
+
+#define _(string) string
+
+/** @addtogroup ErrorHandling
+ *  @{
+ */
+
+/** Error message object */
+typedef struct
+{
+    char* name;                        ///< category of code that caused the error
+    psErrorCode code;                  ///< class of error
+    char* msg;                         ///< the message associated with the error
+}
+psErr;
+
+/** Get a error from the error stack
+ *
+ *  Previous errors on the stack are returned by psErrorGet (a value of 0
+ *  passed to psErrorGet is equivalent to a call to psErrorLast).
+ *
+ *  if no error is at the which position, a non-NULL psErr is returned with
+ *  code PS_ERR_NONE.
+ *
+ *  @return    Error message object at 'which'
+ */
+psErr* psErrorGet(
+    long which                          ///< position in the error stack. 0 is last error on stack.
+);
+
+/** Get last error put on the error stack
+ *
+ *  The last error reported is available from psErrorLast; if no errors are
+ *  current, a non-NULL psErr is returned with code PS_ERR_NONE.
+ *
+ *  @return psErr*     Reference to last error message on error stack
+ */
+psErr* psErrorLast(void);
+
+/** Get errorCode of last error put on the error stack
+ *
+ *  @return psErrorCode     last error code, or PS_ERR_NONE
+ */
+psErrorCode psErrorCodeLast(void);
+
+/** Clears the error stack.
+ *
+ *  The error stack may be completely cleared with psErrorClear.
+ *
+ */
+void psErrorClear(void);
+
+/** Get the error stack depth
+ *
+ *  @return int The number of items on the error stack
+ */
+long psErrorGetStackSize();
+
+/** Prints error stack to specified open file descriptor
+ *
+ *  The entire error stack may be printed to an open file descriptor by
+ *  calling psErrorStackPrint; if and only if there are current errors, the
+ *  printf-style string format is first printed to the file descriptor fd. In
+ *  this printout, error codes are replaced by their string equivalents.
+ *
+ */
+#ifdef __GNUC__
+void psErrorStackPrint(
+    FILE* fd,                          ///< destination file descriptor
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+) __attribute__((format(printf, 2, 3)));
+#else // __GNUC__
+void psErrorStackPrint(
+    FILE* fd,                          ///< destination file descriptor
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+);
+#endif // __GNUC__
+
+
+#ifndef SWIG
+/** Prints error stack to specified open file descriptor
+ *
+ *  The entire error stack may be printed to an open file descriptor by
+ *  calling psErrorStackPrintV; if and only if there are current errors, the
+ *  vprintf-style string format is first printed to the file descriptor fd. In
+ *  this printout, error codes are replaced by their string equivalents.
+ *
+ */
+void psErrorStackPrintV(
+    FILE* fd,                          ///< destination file descriptor
+    const char* format,                   ///< printf-style format of header line
+    va_list va                         ///< any parameters required in format
+);
+#endif // #ifndef SWIG
+
+#ifdef DOXYGEN
+/** Reports an error message to the logging facility
+ *
+ *  This function will invoke the psLogMsg function with a level of
+ *  PS_LOG_ERROR and pass the parameters name and format to generate a proper
+ *  log message.
+ *
+ *  This function modifies the error stack.
+ *
+ *  @return psErrorCode    the given error code
+ */
+psErrorCode psError(
+    psErrorCode code,                  ///< Error class code
+    psBool new,                        ///< true if error originates at this location
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+);
+
+/** Logs a warning message.
+ *
+ *  This procedure logs a message to the destination set by a prior
+ *  call to psLogSetDestination(), This is equivalent to calling
+ *  psLogMsg with a level of PS_LOG_WARN.
+ *
+ */
+void psWarning(
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+);
+#else // #ifdef DOXYGEN
+
+/** Reports an error message to the logging facility
+ *
+ *  This function will invoke the psLogMsg function with a level of
+ *  PS_LOG_ERROR and pass the parameters name and format to generate a proper
+ *  log message.  This function is used to check a specific code location.
+ *
+ *  This function modifies the error stack.
+ *
+ *  @return psErrorcode    the given error code
+ */
+#ifdef __GNUC__
+psErrorCode p_psError(
+    const char* filename,              ///< file name
+    unsigned int lineno,               ///< line number in file
+    const char* func,                  ///< function name
+    psErrorCode code,                  ///< Error class code
+    bool new,                          ///< true if error originates at this location
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+) __attribute__((format(printf, 6, 7)));
+#else // __GNUC__
+psErrorCode p_psError(
+    const char* filename,              ///< file name
+    unsigned int lineno,               ///< line number in file
+    const char* func,                  ///< function name
+    psErrorCode code,                  ///< Error class code
+    bool new,                          ///< true if error originates at this location
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+);
+#endif // __GNUC__
+
+/** Logs a warning message.
+ *
+ *  This procedure logs a message to the destination set by a prior call to
+ *  psLogSetDestination().  This is equivalent to calling psLogMsg with a level of
+ *  PS_LOG_WARN.  This function is used to check a specific code location.
+ *
+*/
+#ifdef __GNUC__
+void p_psWarning(
+    const char* file,                  ///< file name
+    int lineno,                        ///< line number in file
+    const char* func,                  ///< function name
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+) __attribute__((format(printf, 4, 5)));
+#else // __GNUC__
+void p_psWarning(
+    const char* file,                  ///< file name
+    int lineno,                        ///< line number in file
+    const char* func,                  ///< function name
+    const char* format,                ///< printf-style format of header line
+    ...                                ///< any parameters required in format
+);
+#endif // __GNUC__
+
+
+#ifndef SWIG
+#define psError(code,new,...) p_psError(__FILE__,__LINE__,__func__,code,new,__VA_ARGS__)
+#define psWarning(...) p_psWarning(__FILE__,__LINE__,__func__,__VA_ARGS__)
+#endif // #ifndef SWIG
+
+#endif // ! DOXYGEN
+
+/** Create a new psErr struct
+ *
+ *  Creates a new psErr struct, making a copy of the parameters.
+ *
+ *  @return psErr*     new psErr object
+ */
+psErr* psErrAlloc(
+    const char* name,                  ///< Name of error in the form aaa.bbb.ccc
+    psErrorCode code,                  ///< Error class code
+    const char* msg                    ///< Error message
+);
+
+/* @} */// End of SysUtils Functions
+
+#endif
Index: /branches/jch-memory/psLib/src/sys/psErrorCodes.c.in
===================================================================
--- /branches/jch-memory/psLib/src/sys/psErrorCodes.c.in	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psErrorCodes.c.in	(revision 10811)
@@ -0,0 +1,165 @@
+/** @file  psErrorCodes.c
+ *
+ *  @brief Contains the error codes for the error classes
+ *
+ *  @ingroup ErrorHandling
+ *
+ *  @author Robert DeSonia, MHPCC
+ *
+ *  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-08-08 23:39:59 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#include <string.h>
+
+#include "psError.h"
+#include "psErrorCodes.h"
+#include "psList.h"
+#include "psMemory.h"
+
+
+
+static psErrorDescription staticErrorCodes[] = {
+            {PS_ERR_NONE,"not an error"},
+            {PS_ERR_BASE,"base error"},
+            {PS_ERR_${ErrorCode},"${ErrorDescription}"},
+            {PS_ERR_N_ERR_CLASSES,"error classes end marker"}
+        };
+
+static psList* dynamicErrorCodes = NULL;
+static const psErrorDescription* getErrorDescription(psErrorCode code);
+
+
+static const psErrorDescription* getErrorDescription(psErrorCode code)
+{
+    // first, search the static error codes
+
+    psS32 n = 0;
+    while(staticErrorCodes[n].code != PS_ERR_N_ERR_CLASSES &&
+            staticErrorCodes[n].code != code) {
+        n++;
+    }
+
+    if (staticErrorCodes[n].code == code) {
+        return &staticErrorCodes[n];
+    } else {
+        psErrorDescription* desc;
+        // make sure there is a list to search
+        if (dynamicErrorCodes == NULL) {
+            return NULL;
+        }
+
+        // search dynamic list of error descriptions before giving up.
+        psListIterator* iter = psListIteratorAlloc(dynamicErrorCodes,PS_LIST_HEAD,true);
+        while ((desc = (psErrorDescription*)psListGetAndIncrement(iter)) != NULL) {
+            if (desc->code == code) {
+                psFree(iter);
+                return desc;
+            }
+        }
+        psFree(iter);
+    }
+    return NULL;
+}
+
+static void freeErrorDescription(psErrorDescription* err)
+{
+    psFree(err->description);
+}
+
+psErrorDescription* psErrorDescriptionAlloc(psErrorCode code,
+        const char *description)
+{
+    psErrorDescription* err = psAlloc(sizeof(psErrorDescription));
+    err->code = code;
+    if (description == NULL) {
+        err->description = NULL;
+    } else {
+        err->description = psAlloc(sizeof(char)*strlen(description)+1);
+        strcpy((char*)err->description,description);
+    }
+
+    psMemSetDeallocator(err,(psFreeFunc)freeErrorDescription);
+    return err;
+}
+
+
+const char *psErrorCodeString(psErrorCode code)
+{
+    // Check input argument is non-negative
+    if ( code < 0 ) {
+        return NULL;
+    }
+
+    const psErrorDescription* desc = getErrorDescription(code);
+
+    if (desc == NULL) {
+        return NULL;
+    }
+
+    return desc->description;
+}
+
+void psErrorRegister(const psErrorDescription* errors,
+                     int errorCode)
+{
+    if (errorCode < 1) {
+        return;
+    }
+
+    if (errors == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true,
+                _("Specified psErrorDescription pointer can not be NULL."));
+        return;
+    }
+
+    if (dynamicErrorCodes == NULL) {
+        dynamicErrorCodes = psListAlloc(NULL);
+        p_psMemSetPersistent(dynamicErrorCodes,true);
+
+        p_psMemSetPersistent(dynamicErrorCodes->iterators,true);
+        p_psMemSetPersistent(dynamicErrorCodes->iterators->data,true);
+        for (int i = 0; i < dynamicErrorCodes->iterators->n;i++) {
+            p_psMemSetPersistent(dynamicErrorCodes->iterators->data[i],true);
+        }
+    }
+
+    for (psS32 i = 0; i < errorCode; i++) {
+        psErrorDescription* err = psErrorDescriptionAlloc(
+                                      errors[i].code, errors[i].description);
+        p_psMemSetPersistent(err,true);
+        p_psMemSetPersistent((psPtr)err->description,true);
+        if (! psListAdd(dynamicErrorCodes,
+                        PS_LIST_HEAD,
+                        err) ) {
+
+            psError(PS_ERR_UNKNOWN, false,
+                    _("Failed to add input psErrorDescription at array index %d."),
+                    i);
+        }
+        p_psMemSetPersistent(dynamicErrorCodes->head,true);
+        psFree(err);
+    }
+}
+
+psBool p_psErrorUnregister(psErrorCode code)
+{
+    // Check input argument is non-negative
+    if ( code < 0 ) {
+        return false;
+    }
+
+    const psErrorDescription* desc = getErrorDescription(code);
+
+    if (desc == NULL) {
+        return false;
+    }
+
+    if (dynamicErrorCodes == NULL) {
+        return false;
+    }
+
+    return psListRemoveData(dynamicErrorCodes,(psPtr)desc);
+}
Index: /branches/jch-memory/psLib/src/sys/psMemory.c
===================================================================
--- /branches/jch-memory/psLib/src/sys/psMemory.c	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psMemory.c	(revision 10811)
@@ -0,0 +1,1304 @@
+/** @file  psMemory.c
+*
+*  @brief Contains the definitions for the memory management system
+*
+*  psMemory.h has additional information and documentation of the routines found in this file.
+*
+*  @author Robert DeSonia, MHPCC
+*  @author Robert Lupton, Princeton University
+*
+*  @version $Revision: 1.88 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-12-08 11:35:54 $
+*
+*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+*/
+
+#define PS_ALLOW_MALLOC                    // we're allowed to call malloc()
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include "psMemory.h"
+#include "psError.h"
+#include "psAssert.h"
+#include "psAbort.h"
+#include "psLogMsg.h"
+#include "psBitSet.h"
+#include "psFits.h"
+#include "psPixels.h"
+#include "psSphereOps.h"
+#include "psMinimizeLMM.h"
+#include "psImageConvolve.h"
+#include "psTime.h"
+#include "psLine.h"
+#include "psRegion.h"
+#include "psHistogram.h"
+
+#define P_PS_LARGE_BLOCK_SIZE 65536        // size where under, we try to recycle
+
+static psS32 checkMemBlock(const psMemBlock* m, const char *funcName);
+static psMemBlock* lastMemBlockAllocated = NULL;
+static pthread_mutex_t memBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t memIdMutex = PTHREAD_MUTEX_INITIALIZER;
+
+//private boolean for enabling/disabling thread safety.  Default = enabled.
+static bool safeThreads = true;
+
+// private boolean for deciding if allocated memory is persistent
+static bool memory_is_persistent = false;
+
+#ifdef PS_MEM_USE_RECYCLE               // Only use recycling if this is set
+#define N_RECYCLE_BINS 14               // number of recycle bins
+#define MAX_RECYCLE 100                 // Maximum number permitted in a recycle bin
+static pthread_mutex_t recycleMemBlockListMutex = PTHREAD_MUTEX_INITIALIZER; // Mutex for recycle bins
+static const psS32 recycleBinSize[N_RECYCLE_BINS] = // Size of each bin
+    {
+        8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, P_PS_LARGE_BLOCK_SIZE
+    };
+// N.B. recycleBinSize should be terminated by P_PS_LARGE_BLOCK_SIZE (simplifies search loops)
+static psS32 recycleBinNums[N_RECYCLE_BINS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // Number in each bin
+static psMemBlock* recycleMemBlockList[N_RECYCLE_BINS] = // Contents of the bins
+    { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+#endif // #ifdef PS_MEM_USE_RECYCLE
+
+#ifdef PS_MEM_DEBUG
+static psMemBlock* deadBlockList;       // a place to put dead memBlocks in debug mode.
+#endif // #ifdef PS_MEM_DEBUG
+
+/**
+ * Unique ID for allocated blocks
+ */
+static psMemId memid = 0;
+
+/**
+ *  Default memExhausted callback.
+ */
+static psPtr memExhaustedCallbackDefault(size_t size)
+{
+    #if PS_MEM_USE_RECYCLE
+    psPtr ptr = NULL;
+    if (safeThreads) {
+        pthread_mutex_lock(&recycleMemBlockListMutex);
+    }
+    // Attempt to free up everything I can find so I can alloc my ptr
+    int bin = N_RECYCLE_BINS - 1;       // Recycle bin
+
+    while (bin >= 0 && ptr == NULL) {
+        while (recycleMemBlockList[bin] != NULL && ptr == NULL) {
+            psMemBlock *old = recycleMemBlockList[bin];
+            recycleMemBlockList[bin] = recycleMemBlockList[bin]->nextBlock;
+            free(old);
+            ptr = malloc(size);
+        }
+        bin--;
+    }
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&recycleMemBlockListMutex);
+    }
+    return ptr;
+    #else  // #ifdef PS_MEM_USE_RECYCLE
+
+    return NULL;
+    #endif // #ifdef PS_MEM_USE_RECYCLE
+}
+
+/*
+ * Default callback for both allocate and free. Note that the
+ * value of p_psMemAllocID/p_psMemFreeID is incremented
+ * by the return value (so returning 0 means that the callback
+ * isn't resignalled)
+ */
+static psMemId memAllocCallbackDefault(const psMemBlock* ptr)
+{
+    static psMemId incr = 0; // "p_psMemAllocID += incr"
+
+    return incr;
+}
+
+static psMemId memFreeCallbackDefault(const psMemBlock* ptr)
+{
+    static psMemId incr = 0; // "p_psMemFreeID += incr"
+
+    return incr;
+}
+
+static void memProblemCallbackDefault(psMemBlock* ptr,
+                                      const char *file,
+                                      unsigned int lineno)
+{
+    if (ptr->refCounter < 1) {
+        psError(PS_ERR_MEMORY_CORRUPTION, false,
+                _("Block %lu, allocated at %s:%d, freed multiple times at %s:%d."),
+                (unsigned long)ptr->id, ptr->file, ptr->lineno, file, lineno);
+    }
+
+    if (lineno > 0) {
+        psAbort(__func__, "Detected a problem in the memory system at %s:%d", file, lineno);
+    }
+}
+
+/*
+ * Routines to check the consistency of the allocated and/or free memory arena
+ *
+ * N.b. If the block wasn't allocated by psAlloc, it will appear corrupted
+ */
+static psS32 checkMemBlock(const psMemBlock* m,
+                           const char *funcName)
+{
+    // n.b. since this is called by psMemCheckCorruption while the memblock list is mutex locked,
+    // we shouldn't call such things as p_psAlloc/p_psFree here.
+
+    if (m == NULL) {
+        psError(PS_ERR_MEMORY_CORRUPTION, true,
+                _("NULL memory block found."));
+        return 1;
+    }
+
+    if (m->refCounter == 0) {
+        // using an unreferenced block of memory, are you?
+        psError(PS_ERR_MEMORY_CORRUPTION, true,
+                _("Memory block %lu was freed but still being used."),
+                (unsigned long)m->id);
+        return 1;
+    }
+
+    if (m->startblock != P_PS_MEMMAGIC || m->endblock != P_PS_MEMMAGIC) {
+        psError(PS_ERR_MEMORY_CORRUPTION, true,
+                _("Memory block %lu is corrupted; buffer underflow detected."),
+                (unsigned long)m->id);
+        return 1;
+    }
+    if (*(psPtr *)((int8_t *) (m + 1) + m->userMemorySize) != P_PS_MEMMAGIC) {
+        psError(PS_ERR_MEMORY_CORRUPTION, true,
+                _("Memory block %lu is corrupted; buffer overflow detected."),
+                (unsigned long)m->id);
+        return 1;
+    }
+
+    return 0;
+}
+
+
+/*
+ * A callback function to check the state of the memory system; may be registered
+ * with psMem{Alloc,Free}CallbackSet
+ */
+static psMemId memAllocCallbackCheckCorruption(const psMemBlock *ptr)
+{
+    static psMemId incr = 10; // "p_psMemAllocID += incr"
+    bool abort_on_error = false;
+
+    if (psMemCheckCorruption(abort_on_error) > 0) {
+        fprintf(stderr,"Detected memory corruption\n"); // somewhere to set a breakpoint
+    }
+
+    return incr;
+}
+
+/*
+ * The default callbacks
+ */
+static psMemAllocCallback memAllocCallback = memAllocCallbackDefault;
+static psMemFreeCallback memFreeCallback = memFreeCallbackDefault;
+static psMemProblemCallback memProblemCallback = memProblemCallbackDefault;
+static psMemExhaustedCallback memExhaustedCallback = memExhaustedCallbackDefault;
+
+psMemExhaustedCallback psMemExhaustedCallbackSet(psMemExhaustedCallback func)
+{
+    psMemExhaustedCallback old = memExhaustedCallback;
+
+    if (func != NULL) {
+        memExhaustedCallback = func;
+    } else {
+        memExhaustedCallback = memExhaustedCallbackDefault;
+    }
+
+    return old;
+}
+
+psMemProblemCallback psMemProblemCallbackSet(psMemProblemCallback func)
+{
+    psMemProblemCallback old = memProblemCallback;
+
+    if (func != NULL) {
+        memProblemCallback = func;
+    } else {
+        memProblemCallback = memProblemCallbackDefault;
+    }
+
+    return old;
+}
+
+/*
+ * And now the I-want-to-be-informed callbacks
+ *
+ * Call the callbacks when these IDs are allocated/freed
+ */
+psMemId p_psMemAllocID = 0;       // notify user this block is allocated
+psMemId p_psMemFreeID = 0;   // notify user this block is freed
+
+psMemId psMemAllocCallbackSetID(psMemId id)
+{
+    psMemId old = p_psMemAllocID;
+
+    /*
+     * This is here purely to stop gcc complaining
+     */
+    assert (memAllocCallbackCheckCorruption != NULL);
+
+    p_psMemAllocID = id;
+
+    return old;
+}
+
+psMemId psMemFreeCallbackSetID(psMemId id)
+{
+    psMemId old = p_psMemFreeID;
+
+    p_psMemFreeID = id;
+
+    return old;
+}
+
+psMemAllocCallback psMemAllocCallbackSet(psMemAllocCallback func)
+{
+    psMemFreeCallback old = memAllocCallback;
+
+    if (func != NULL) {
+        memAllocCallback = func;
+    } else {
+        memAllocCallback = memAllocCallbackDefault;
+    }
+
+    return old;
+}
+
+psMemFreeCallback psMemFreeCallbackSet(psMemFreeCallback func)
+{
+    psMemFreeCallback old = memFreeCallback;
+
+    if (func != NULL) {
+        memFreeCallback = func;
+    } else {
+        memFreeCallback = memFreeCallbackDefault;
+    }
+
+    return old;
+}
+
+/*
+ * Return memory ID counter for next block to be allocated
+ */
+psMemId psMemGetId(void)
+{
+    return psMemGetLastId() + 1;
+}
+
+psMemId psMemGetLastId(void)
+{
+    if (safeThreads) {
+        pthread_mutex_lock(&memIdMutex);
+    }
+
+    psMemId id = memid;
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&memIdMutex);
+    }
+
+    return id;
+}
+
+int psMemCheckCorruption(bool abort_on_error)
+{
+    psS32 nbad = 0;               // number of bad blocks
+    psBool failure = false;
+
+    // get exclusive access to the memBlock list to avoid it changing on us while we use it.
+    //    pthread_mutex_lock(&memBlockListMutex);
+
+    for (psMemBlock* iter = lastMemBlockAllocated; iter != NULL; iter = iter->nextBlock) {
+        if (safeThreads) {
+            pthread_mutex_unlock(&memBlockListMutex);
+        }
+        failure = checkMemBlock(iter, __func__);
+        if (safeThreads) {
+            pthread_mutex_lock(&memBlockListMutex);
+        }
+        if ( failure ) {
+            nbad++;
+
+            memProblemCallback(iter, __func__, __LINE__);
+
+            if (abort_on_error) {
+                // release the lock on the memblock list
+                if (safeThreads) {
+                    pthread_mutex_unlock(&memBlockListMutex);
+                }
+                psAbort(__func__, "Detected memory corruption");
+                return nbad;
+            }
+        }
+    }
+
+    // release the lock on the memblock list
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+    return nbad;
+}
+
+/*
+ * Set whether allocated memory is persistent
+ */
+bool p_psMemAllocatePersistent(bool is_persistent)
+{
+    const bool old = memory_is_persistent;
+    memory_is_persistent = is_persistent;
+
+    return old;
+}
+
+#ifdef PS_MEM_USE_RECYCLE
+// Return the appropriate recycle bin number
+static int getRecycleBin(size_t size)
+{
+    if (size >= P_PS_LARGE_BLOCK_SIZE) {
+        return N_RECYCLE_BINS;
+    }
+    int binNum = 0;                     // Recycle bin number
+    while (size > recycleBinSize[binNum]) {
+        binNum++;
+    }
+    return binNum;
+}
+
+// Push a pointer onto the recycle bin
+static void recyclePush(psMemBlock *mb, // Pointer to push
+                        int bin         // Recycling bin
+                       )
+{
+    assert(mb);
+    assert(bin < N_RECYCLE_BINS);
+
+    mb->previousBlock = NULL;
+
+    if (safeThreads) {
+        pthread_mutex_lock(&recycleMemBlockListMutex);
+    }
+
+    mb->nextBlock = recycleMemBlockList[bin];
+    if (recycleMemBlockList[bin] != NULL) {
+        recycleMemBlockList[bin]->previousBlock = mb;
+    }
+    recycleMemBlockList[bin] = mb;
+    recycleBinNums[bin]++;
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&recycleMemBlockListMutex);
+    }
+
+    return;
+}
+
+// Pop a pointer from the recycle bin
+static psMemBlock *recyclePop(int bin   // Recycling bin
+                             )
+{
+    if (bin >= N_RECYCLE_BINS) {
+        return NULL;
+    }
+
+    if (safeThreads) {
+        pthread_mutex_lock(&recycleMemBlockListMutex);
+    }
+
+    psMemBlock *mb = recycleMemBlockList[bin]; // Pointer popped from recycle bin
+
+    if (mb) {
+        // We pull it off the list
+        recycleMemBlockList[bin] = mb->nextBlock;
+        if (recycleMemBlockList[bin] != NULL) {
+            recycleMemBlockList[bin]->previousBlock = NULL;
+        }
+        recycleBinNums[bin]--;
+    }
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&recycleMemBlockListMutex);
+    }
+
+    return mb;
+}
+#endif // #ifdef PS_MEM_USE_RECYCLE
+
+/*
+ * Actually allocate memory
+ */
+psPtr p_psAlloc(size_t size,
+                const char *file,
+                unsigned int lineno)
+{
+
+    psMemBlock *ptr = NULL;
+
+    #ifdef PS_MEM_USE_RECYCLE
+    // Are we in one of the recycle bins?
+    int bin = getRecycleBin(size);
+    if (bin < N_RECYCLE_BINS) {
+        size = recycleBinSize[bin];     // round-up size to next sized bin.
+        ptr = recyclePop(bin);          // grab out of the recycle bin
+    }
+    #endif // #ifdef PS_MEM_USE_RECYCLE
+
+    if (ptr == NULL) {
+        ptr = malloc(sizeof(psMemBlock) + size + sizeof(psPtr ));
+
+        if (ptr == NULL) {
+            ptr = memExhaustedCallback(size);
+            if (ptr == NULL) {
+                psAbort(__func__, "Failed to allocate %zd bytes at %s:%d", size, file, lineno);
+            }
+        }
+
+        *(psPtr*)&ptr->startblock = P_PS_MEMMAGIC;
+        *(psPtr*)&ptr->endblock = P_PS_MEMMAGIC;
+        ptr->userMemorySize = size;
+        if (safeThreads) {
+            pthread_mutex_init(&ptr->refCounterMutex, NULL);
+        }
+    }
+    // increment the memory id safely.
+    if (safeThreads) {
+        pthread_mutex_lock(&memBlockListMutex);
+    }
+    *(psMemId* ) & ptr->id = ++memid;
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+    ptr->file = file;
+    ptr->freeFunc = NULL;
+    ptr->persistent = memory_is_persistent;
+    *(psU32 *)&ptr->lineno = lineno;
+    *(psPtr *)((int8_t *) (ptr + 1) + size) = P_PS_MEMMAGIC;
+    ptr->previousBlock = NULL;
+
+    ptr->refCounter = 1;                   // one user so far
+
+    // need exclusive access of the memory block list now...
+    if (safeThreads) {
+        pthread_mutex_lock(&memBlockListMutex);
+    }
+
+    // insert the new block to the front of the memBlock linked-list
+    ptr->nextBlock = lastMemBlockAllocated;
+    if (ptr->nextBlock != NULL) {
+        ptr->nextBlock->previousBlock = ptr;
+    }
+    lastMemBlockAllocated = ptr;
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+
+    // Did the user ask to be informed about this allocation?
+    if (ptr->id == p_psMemAllocID) {
+        p_psMemAllocID += memAllocCallback(ptr);
+    }
+    // And return the user the memory that they allocated
+    return ptr + 1;                        // user memory
+}
+
+psPtr p_psRealloc(psPtr vptr,
+                  size_t size,
+                  const char *file,
+                  unsigned int lineno)
+{
+    if (vptr == NULL) {
+        return p_psAlloc(size, file, lineno);
+    }
+
+    psMemBlock *ptr = ((psMemBlock*)vptr) - 1;
+
+    if (checkMemBlock(ptr, __func__) != 0) {
+        memProblemCallback(ptr, file, lineno);
+        psAbort(file, "Realloc detected a memory corruption (id %lu @ %s:%d).",
+                (unsigned long)ptr->id, ptr->file, ptr->lineno);
+    }
+
+    #ifdef PS_MEM_USE_RECYCLE
+    // Ensure the size matches that of the recycle bin
+    int bin = getRecycleBin(size);
+    if (bin < N_RECYCLE_BINS) {
+        size = recycleBinSize[bin];     // round-up size to next sized bin.
+    }
+    #endif // #ifdef PS_MEM_USE_RECYCLE
+
+    if (size == ptr->userMemorySize) {
+        // Nothing to do
+        return vptr;
+    }
+
+    // Reallocate the memory
+
+    if (safeThreads) {
+        pthread_mutex_lock(&memBlockListMutex);
+    }
+
+    bool isBlockLast = (ptr == lastMemBlockAllocated); // Is this the last block we allocated?
+    ptr = (psMemBlock *)realloc(ptr, sizeof(psMemBlock) + size + sizeof(psPtr));
+    if (ptr == NULL) {
+        ptr = memExhaustedCallback(size);
+        if (ptr == NULL) {
+            psAbort(__func__, "Failed to reallocate %zd bytes at %s:%d", size, file, lineno);
+        }
+    }
+
+    ptr->userMemorySize = size;
+    *(psPtr *)((int8_t *) (ptr + 1) + size) = P_PS_MEMMAGIC;
+
+    if (isBlockLast) {
+        lastMemBlockAllocated = ptr;
+    }
+
+    // the block location may have changed, so fix the linked list addresses.
+    if (ptr->nextBlock != NULL) {
+        ptr->nextBlock->previousBlock = ptr;
+    }
+    if (ptr->previousBlock != NULL) {
+        ptr->previousBlock->nextBlock = ptr;
+    }
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+
+    // Did the user ask to be informed about this allocation?
+    if (ptr->id == p_psMemAllocID) {
+        p_psMemAllocID += memAllocCallback(ptr);
+    }
+
+    return ptr + 1;                    // usr memory
+}
+
+void p_psFree(psPtr vptr,
+              const char *filename,
+              unsigned int lineno)
+{
+    if (vptr == NULL) {
+        return;
+    }
+    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
+    if (ptr->refCounter < 1) {
+        psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
+
+        psAbort(__func__,_("Block %lu, allocated at %s:%d, freed multiple times at %s:%d."),
+                (unsigned long)ptr->id, ptr->file, ptr->lineno, filename, lineno);
+    }
+
+    if (checkMemBlock(ptr, __func__) != 0) {
+        memProblemCallback(ptr, filename, lineno);
+        psAbort(__func__,"Memory Corruption Detected.");
+    }
+
+    (void)p_psMemDecrRefCounter(vptr, filename, lineno);    // this handles the free, if required.
+}
+
+/*
+ * Check for memory leaks.
+ */
+int psMemCheckLeaks(psMemId id0,
+                    psMemBlock ***array,
+                    FILE * fd,
+                    bool persistence)
+{
+    psS32 nleak = 0;
+    psS32 j = 0;
+    psMemBlock* topBlock = lastMemBlockAllocated;
+
+    if (safeThreads) {
+        pthread_mutex_lock(&memBlockListMutex);
+    }
+
+    for (psMemBlock* iter = topBlock; iter != NULL; iter = iter->nextBlock) {
+        if ( (iter->refCounter > 0) &&
+                ( (persistence) || (!persistence && !iter->persistent) ) &&
+                (iter->id >= id0)) {
+
+            nleak++;
+
+            if (fd != NULL) {
+                if (nleak == 1) {
+                    fprintf(fd, "   %20s:line ID\n", "file");
+                }
+
+                fprintf(fd, "   %20s:%-4d %lu\n", iter->file, (int)iter->lineno, (unsigned long)iter->id);
+            }
+        }
+    }
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+
+    if (nleak == 0 || array == NULL) {
+        return nleak;
+    }
+
+    *array = p_psAlloc(nleak * sizeof(psMemBlock), __FILE__, __LINE__);
+    if (safeThreads) {
+        pthread_mutex_lock(&memBlockListMutex);
+    }
+
+    for (psMemBlock* iter = topBlock; iter != NULL; iter = iter->nextBlock) {
+        if ( (iter->refCounter > 0) &&
+                ( (persistence) || (!persistence && !iter->persistent) ) &&
+                (iter->id >= id0)) {
+
+            (*array)[j++] = iter;
+            if (j == nleak) {              // found them all
+                break;
+            }
+        }
+    }
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+
+    return nleak;
+}
+
+/*
+ * Reference counting APIs
+ */
+
+// return refCounter
+psReferenceCount psMemGetRefCounter(const psPtr ptr)
+{
+    psMemBlock* ptr2;
+    psU32 refCount;
+
+    if (ptr == NULL) {
+        return 0;
+    }
+
+    ptr2 = ((psMemBlock* ) ptr) - 1;
+
+    if (checkMemBlock(ptr2, __func__) != 0) {
+        memProblemCallback(ptr2, __func__, __LINE__);
+    }
+
+    if (safeThreads) {
+        pthread_mutex_lock(&ptr2->refCounterMutex);
+    }
+    refCount = ptr2->refCounter;
+    if (safeThreads) {
+        pthread_mutex_unlock(&ptr2->refCounterMutex);
+    }
+
+    return refCount;
+}
+
+// increment and return refCounter
+psPtr p_psMemIncrRefCounter(const psPtr vptr,
+                            const char *file,
+                            psS32 lineno)
+{
+    psMemBlock* ptr;
+
+    if (vptr == NULL) {
+        return vptr;
+    }
+
+    ptr = ((psMemBlock* ) vptr) - 1;
+
+    if (checkMemBlock(ptr, __func__)) {
+        memProblemCallback(ptr, file, lineno);
+    }
+
+    if (safeThreads) {
+        pthread_mutex_lock(&ptr->refCounterMutex);
+    }
+    ptr->refCounter++;
+    if (safeThreads) {
+        pthread_mutex_unlock(&ptr->refCounterMutex);
+    }
+
+    // Did the user ask to be informed about this allocation?
+    if (ptr->id == p_psMemAllocID) {
+        p_psMemAllocID += memAllocCallback(ptr);
+    }
+
+    return vptr;
+}
+
+psPtr p_psMemSetRefCounter(psPtr vptr,
+                           psReferenceCount count,
+                           const char *file,
+                           psS32 lineno)
+{
+    psMemBlock* ptr;
+
+    if (vptr == NULL) {
+        return vptr;
+    }
+
+    if (count < 0) {
+        count = 0;
+    }
+
+    ptr = ((psMemBlock* ) vptr) - 1;
+
+    if (checkMemBlock(ptr, __func__)) {
+        memProblemCallback(ptr, file, lineno);
+    }
+
+    if (safeThreads) {
+        pthread_mutex_lock(&ptr->refCounterMutex);
+    }
+    ptr->refCounter = count;
+    if (safeThreads) {
+        pthread_mutex_unlock(&ptr->refCounterMutex);
+    }
+
+    if (count < 1) {
+        vptr = p_psMemDecrRefCounter(vptr,file,lineno);
+    }
+
+    return vptr;
+}
+
+// decrement and return refCounter
+psPtr p_psMemDecrRefCounter(psPtr vptr,
+                            const char *file,
+                            psS32 lineno)
+{
+    if (vptr == NULL) {
+        return NULL;
+    }
+
+    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
+
+    if (checkMemBlock(ptr, __func__) != 0) {
+        memProblemCallback(ptr, file, lineno);
+        return NULL;
+    }
+
+    // Did the user ask to be informed about this deallocation?
+    if (ptr->id == p_psMemFreeID) {
+        p_psMemFreeID += memFreeCallback(ptr);
+    }
+
+    if (safeThreads) {
+        pthread_mutex_lock(&ptr->refCounterMutex);
+    }
+
+    if (ptr->refCounter > 1) {
+        ptr->refCounter--;                 // multiple references, just decrement the count.
+        if (safeThreads) {
+            pthread_mutex_unlock(&ptr->refCounterMutex);
+        }
+
+    } else {
+        if (safeThreads) {
+            pthread_mutex_unlock(&ptr->refCounterMutex);
+        }
+
+        if (ptr->freeFunc != NULL) {
+            ptr->freeFunc(vptr);
+        }
+
+        if (safeThreads) {
+            pthread_mutex_lock(&memBlockListMutex);
+        }
+
+        // cut the memBlock out of the memBlock list
+        if (ptr->nextBlock != NULL) {
+            ptr->nextBlock->previousBlock = ptr->previousBlock;
+        }
+        if (ptr->previousBlock != NULL) {
+            ptr->previousBlock->nextBlock = ptr->nextBlock;
+        }
+        if (lastMemBlockAllocated == ptr) {
+            lastMemBlockAllocated = ptr->nextBlock;
+        }
+
+        if (safeThreads) {
+            pthread_mutex_unlock(&memBlockListMutex);
+        }
+
+        #ifdef PS_MEM_USE_RECYCLE
+        // do we recycle?
+        int bin = getRecycleBin(ptr->userMemorySize);
+        if (bin < N_RECYCLE_BINS && recycleBinNums[bin] < MAX_RECYCLE) {
+            ptr->refCounter = 0;
+            recyclePush(ptr, bin);
+        } else
+            #endif  // #ifdef PS_MEM_USE_RECYCLE
+            {
+                // memory is larger than I want to recycle.
+                #ifdef PS_MEM_DEBUG
+                (void)p_psRealloc(vptr, 0, file, lineno);
+                ptr->previousBlock = NULL;
+                ptr->nextBlock = deadBlockList;
+                if (deadBlockList != NULL) {
+                deadBlockList->previous = ptr;
+            }
+        deadBlockList = ptr;
+        #else // #ifdef PS_MEM_DEBUG
+
+        if (safeThreads) {
+            pthread_mutex_destroy(&ptr->refCounterMutex);
+            }
+            free(ptr);
+            #endif // #else - #ifdef PS_MEM_DEBUG
+
+        }
+
+        vptr = NULL;                       // since we freed it, make sure we return NULL.
+    }
+
+    return vptr;
+}
+
+void psMemSetDeallocator(psPtr ptr,
+                         psFreeFunc freeFunc)
+{
+    if (ptr == NULL) {
+        return;
+    }
+
+    psMemBlock* PTR = ((psMemBlock* ) ptr) - 1;
+
+    if (checkMemBlock(PTR, __func__) != 0) {
+        memProblemCallback(PTR, __func__, __LINE__);
+    }
+
+    PTR->freeFunc = freeFunc;
+
+}
+
+psFreeFunc psMemGetDeallocator(const psPtr ptr)
+{
+    if (ptr == NULL) {
+        return NULL;
+    }
+
+    psMemBlock* PTR = ((psMemBlock* ) ptr) - 1;
+
+    if (checkMemBlock(PTR, __func__) != 0) {
+        memProblemCallback(PTR, __func__, __LINE__);
+    }
+
+    return PTR->freeFunc;
+}
+
+bool psMemCheckType(psDataType type,
+                    psPtr ptr)
+{
+    PS_ASSERT_PTR(ptr, false);
+
+    switch(type) {
+    case PS_DATA_ARRAY:
+        if ( psMemCheckArray(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_BITSET:
+        if ( psMemCheckBitSet(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_CUBE:
+        if ( psMemCheckCube(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_FITS:
+        if ( psMemCheckFits(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_HASH:
+        if ( psMemCheckHash(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_HISTOGRAM:
+        if ( psMemCheckHistogram(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_IMAGE:
+        if ( psMemCheckImage(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_KERNEL:
+        if ( psMemCheckKernel(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_LINE:
+        if ( psMemCheckLine(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_LIST:
+        if ( psMemCheckList(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_LOOKUPTABLE:
+        if ( psMemCheckLookupTable(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_METADATA:
+        if ( psMemCheckMetadata(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_METADATAITEM:
+        if ( psMemCheckMetadataItem(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_MINIMIZATION:
+        if ( psMemCheckMinimization(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_PIXELS:
+        if ( psMemCheckPixels(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_PLANE:
+        if ( psMemCheckPlane(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_PLANEDISTORT:
+        if ( psMemCheckPlaneDistort(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_PLANETRANSFORM:
+        if ( psMemCheckPlaneTransform(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_POLYNOMIAL1D:
+        if ( psMemCheckPolynomial1D(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_POLYNOMIAL2D:
+        if ( psMemCheckPolynomial2D(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_POLYNOMIAL3D:
+        if ( psMemCheckPolynomial3D(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_POLYNOMIAL4D:
+        if ( psMemCheckPolynomial4D(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_PROJECTION:
+        if ( psMemCheckProjection(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_REGION:
+        if ( psMemCheckRegion(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_SCALAR:
+        if ( psMemCheckScalar(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_SPHERE:
+        if ( psMemCheckSphere(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_SPHEREROT:
+        if ( psMemCheckSphereRot(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_SPLINE1D:
+        if ( psMemCheckSpline1D(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_STATS:
+        if ( psMemCheckStats(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_STRING:
+        if ( psMemCheckString(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_TIME:
+        if ( psMemCheckTime(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    case PS_DATA_VECTOR:
+        if ( psMemCheckVector(ptr) )
+            return true;
+        else {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                    "Incorrect pointer.  Datatypes do not match.\n");
+            break;
+        }
+    default:
+        psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                "Invalid datatype specified.\n");
+    }
+    return false;
+}
+
+bool psMemSetThreadSafety(bool safe)
+{
+    bool out = safeThreads;
+    safeThreads = safe;
+    return out;
+}
+
+bool psMemGetThreadSafety(void)
+{
+    return safeThreads;
+}
+
+bool p_psMemGetPersistent(psPtr vptr)
+{
+    if (vptr == NULL) {
+        return NULL;
+    }
+
+    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
+
+    if (checkMemBlock(ptr, __func__) != 0) {
+        memProblemCallback(ptr, __func__, __LINE__);
+    }
+
+    return ptr->persistent;
+}
+
+void p_psMemSetPersistent(psPtr vptr,
+                          bool value)
+{
+    if (vptr == NULL) {
+        return;
+    }
+
+    psMemBlock* ptr = ((psMemBlock* ) vptr) - 1;
+
+    if (checkMemBlock(ptr, __func__) != 0) {
+        memProblemCallback(ptr, __func__, __LINE__);
+    }
+
+    ptr->persistent = value;
+}
+
+/************************************************************************************************************/
+/*
+ * Return the total amount of memory owned by psLib; if non-NULL also provide a breakdown
+ * into recyclable, allocated, and allocated-and-persistent
+ *
+ * It would be simple enough to fix this code to return an array of structs to describe
+ * the insides of the allocator rather than the printf used here.
+ */
+size_t psMemStats(const bool print, // print details as they're found?
+                  size_t *allocated, // memory that's currently allocated (but not persistent)
+                  size_t *persistent, // persistent memory that's currently allocated
+                  size_t *freelist) // memory that's waiting to be recycled
+{
+    const size_t overhead = sizeof(psMemBlock) + sizeof(psPtr); // overhead on each allocation
+
+    if (print) {
+        printf("Type       %6s  %10s %8s\n", "size", "nByte", "nBlock");
+    }
+
+    if (safeThreads) {
+        pthread_mutex_lock(&memBlockListMutex);
+    }
+    /*
+     * All memory that's currently allocated, whether persistent or not
+     */
+    size_t allocated_s, persistent_s;
+    if (allocated == NULL) {
+        allocated = &allocated_s;
+    }
+    if (persistent == NULL) {
+        persistent = &persistent_s;
+    }
+
+    size_t alloc = 0, persist = 0;
+    size_t nalloc = 0, npersist = 0;
+    for (psMemBlock* ptr = lastMemBlockAllocated; ptr != NULL; ptr = ptr->nextBlock) {
+        assert (ptr->refCounter > 0);
+
+        if (ptr->persistent) {
+            npersist++;
+            persist += ptr->userMemorySize + overhead;
+        } else {
+            nalloc++;
+            alloc += ptr->userMemorySize + overhead;
+        }
+    }
+    *allocated = alloc;
+    *persistent = persist;
+
+    if (print) {
+        printf("Allocated  %6s  %10zd %8zd\n", "", alloc, nalloc);
+        printf("Persistent %6s  %10zd %8zd\n", "", persist, npersist);
+    }
+    /*
+     * Count the memory on the free list
+     */
+    size_t freelist_s;
+    if (freelist == NULL) {
+        freelist = &freelist_s;
+    }
+
+    *freelist = 0;
+    int nblock_tot = 0;
+    #ifdef PS_MEM_USE_RECYCLE
+
+    for (int i = 0; recycleBinSize[i] < P_PS_LARGE_BLOCK_SIZE; i++) {
+        size_t bin_contents = 0;
+        size_t nblock = 0;
+        for (const psMemBlock *ptr = recycleMemBlockList[i]; ptr != NULL; ptr = ptr->nextBlock) {
+            nblock++;
+            bin_contents += ptr->userMemorySize + overhead;
+        }
+        *freelist += bin_contents;
+        nblock_tot += nblock;
+
+        if (print) {
+            printf("Freelist   %6d  %10d %8d\n", recycleBinSize[i], bin_contents, nblock);
+        }
+    }
+    #endif // #ifdef PS_MEM_USE_RECYCLE
+
+    if (print) {
+        printf("Freelist   %6s  %10zd %8d\n", "", *freelist, nblock_tot);
+    }
+
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+
+    return *freelist + *allocated + *persistent;
+}
Index: /branches/jch-memory/psLib/src/sys/psMemory.h
===================================================================
--- /branches/jch-memory/psLib/src/sys/psMemory.h	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psMemory.h	(revision 10811)
@@ -0,0 +1,552 @@
+/** @file  psMemory.h
+ *
+ *  @brief Contains the definitions for the memory management system
+ *
+ *  This is the generic memory management system put inbetween the user's high level code and the OS-level
+ *  memory allocation routines.  This system adds such features as callback routines for memory error events,
+ *  tracing capabilities, and reference counting.
+ *
+ *  @author Robert DeSonia, MHPCC
+ *  @author Robert Lupton, Princeton University
+ *
+ *  @ingroup MemoryManagement
+ *
+ *  @version $Revision: 1.61 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-10-13 21:13:48 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifndef PS_MEMORY_H
+#define PS_MEMORY_H
+
+#include <stdio.h>                     // needed for FILE
+#include <pthread.h>                   // we need a mutex to make this stuff thread safe.
+
+#include "psType.h"
+
+/** @addtogroup MemoryManagement
+ *  @{
+ */
+
+#define P_PS_MEMMAGIC (psPtr)0xdeadbeef   // Magic number in psMemBlock header
+
+/**
+ *  @addtogroup memCallback Memory Callbacks
+ *
+ *  Routines dealing with the creating and setting of memory management callback functions.
+ */
+
+/**
+ *  @addtogroup memTracing Memory Tracing
+ *
+ *  Routines dealing with memory tracing and corruption checking.
+ */
+
+/**
+ *  @addtogroup memRefCount Reference Count
+ *
+ *  Routines dealing with the reference counting of allocated buffers.
+ */
+
+/// typedef for memory identification numbers.  Guaranteed to be some variety of integer.
+typedef unsigned long psMemId;
+
+/// typedef for a memory block's reference count. Guaranteed to be some variety of integer.
+typedef unsigned long psReferenceCount;
+
+/// typedef for deallocator.
+typedef void (*psFreeFunc) (void* ptr);
+
+/** Book-keeping data for storage allocator.
+ *  N.b. sizeof(psMemBlock) must be chosen such that if ptr is a pointer
+ *  returned by malloc, then ((char *)ptr + sizeof(psMemBlock)) is properly
+ *  aligned for all storage types.
+ */
+typedef struct psMemBlock
+{
+    const void* startblock;            ///< initialised to p_psMEMMAGIC
+    struct psMemBlock* previousBlock;  ///< previous block in allocation list
+    struct psMemBlock* nextBlock;      ///< next block allocation list
+    psFreeFunc freeFunc;               ///< deallocator.  If NULL, use generic deallocation.
+    size_t userMemorySize;             ///< the size of the user-portion of the memory block
+    const psMemId id;                  ///< a unique ID for this allocation
+    const char *file;                  ///< set from __FILE__ in e.g. p_psAlloc
+    const unsigned int lineno;         ///< set from __LINE__ in e.g. p_psAlloc
+    pthread_mutex_t refCounterMutex;   ///< mutex to ensure exclusive access to reference counter
+    psReferenceCount refCounter;       ///< how many times pointer is referenced
+    bool persistent;                   ///< marks if this non-user persistent data like error stack, etc.
+    const void* endblock;              ///< initialised to p_psMEMMAGIC
+}
+psMemBlock;
+
+/** prototype of a basic callback used by memory functions
+ *
+ *  @see psMemAllocCallbackSet
+ *  @ingroup memCallback
+ */
+typedef psMemId(*psMemAllocCallback) (
+    const psMemBlock* ptr              ///< the psMemBlock just allocated
+);
+
+/** prototype of memory free callback used by memory functions
+ *
+ *  @see psMemFreeCallbackSet
+ *  @ingroup memCallback
+ */
+typedef psMemId(*psMemFreeCallback) (
+    const psMemBlock* ptr              ///< the psMemBlock being freed
+);
+
+/** prototype of a callback used in error conditions
+ *
+ *  This callback should not try to call psAlloc or psFree.
+ *
+ *  @see psMemProblemCallbackSet
+ *  @ingroup memCallback
+ */
+typedef void (*psMemProblemCallback) (
+    psMemBlock* ptr,                   ///< the pointer to the problematic memory block.
+    const char *filename,                    ///< the file in which the problem originated
+    unsigned int lineno                ///< the line number in which the problem originated
+);
+
+/** prototype of a callback function used when memory runs out
+ *
+ *  @return psPtr pointer to requested buffer of the size size_t, or NULL if memory could not
+ *          be found.
+ *
+ *  @see psMemExhaustedCallbackSet
+ *  @ingroup memCallback
+ */
+typedef psPtr (*psMemExhaustedCallback) (
+    size_t size                        ///< the size of buffer required
+);
+
+/** Memory allocation.  This operates much like malloc(), but is guaranteed to return a non-NULL value.
+ *
+ *  @return psPtr pointer to the allocated buffer. This will not be NULL.
+ *  @see psFree
+ */
+#ifdef DOXYGEN
+
+psPtr psAlloc(
+    size_t size                        ///< Size required
+);
+
+#else // #ifdef DOXYGEN
+psPtr p_psAlloc(
+    size_t size,                       ///< Size required
+    const char *filename,              ///< File of call
+    unsigned int lineno                ///< Line number of call
+);
+
+/// Memory allocation. psAlloc sends file and line number to p_psAlloc.
+#ifndef SWIG
+#define psAlloc(size) p_psAlloc(size, __FILE__, __LINE__)
+#endif // ! SWIG
+
+#endif // ! DOXYGEN
+
+/** Set the deallocator routine
+ *
+ *  A deallocator routine can optionally be assigned to a memory block to
+ *  ensure that associated memory blocks also get freed, e.g., memory buffers
+ *  referenced within a struct.
+ *
+ */
+void psMemSetDeallocator(
+    psPtr ptr,                         ///< the memory block to operate on
+    psFreeFunc freeFunc                ///< the function to be executed at deallocation
+);
+
+/** Get the deallocator routine
+ *
+ *  This function returns the deallocator for a memory block.  A deallocator
+ *  routine can optionally be assigned to a memory block to ensure that
+ *  associated memory blocks also get freed, e.g., memory buffers referenced
+ *  within a struct.
+ *
+ *  @return psFreeFunc    the routine to be called at deallocation.
+ */
+psFreeFunc psMemGetDeallocator(
+    const psPtr ptr                    ///< the memory block
+);
+
+/** Checks the deallocator to see if the pointer matches the desired datatype.
+ *
+ *  @return bool:       True if type matches, otherwise false.
+ */
+bool psMemCheckType(
+    psDataType type,                   ///< The desired psDataType to match
+    psPtr ptr                          ///< The desired pointer to match
+);
+
+/** Activate or Deactivate thread safety and mutex locking in the memory management.
+ *
+ *  psMemThreadSafety shall turn on thread safety in the memory management functions if
+ *  safe is true, and deactivate all mutex locking in the memory management functions if
+ *  safe is false.  The function shall return the previous value of the thread safety.
+ *  Note that the default behaviour of the library shall be for the locking to be performed.
+ *
+ *  @return bool:       The previous value of the thread safety.
+ */
+bool psMemSetThreadSafety(
+    bool safe                          ///< boolean for turning on/off thread safety
+);
+
+/** Get the current state of thread safety and mutex locking in the memory management.
+ *
+ * psMemGetThreadSafety shall return the current state of thread safety in the memory management system.
+ *
+ *  @return bool:       The current state of thread safety.
+ */
+bool psMemGetThreadSafety(void);
+
+/** Set the memory as persistent so that it is ignored when detecting memory leaks.
+ *
+ *  Used to mark a memory block as persistent data within the library,
+ *  i.e., non user-level data used to hold psLib's state or cache data.  Such
+ *  examples of this class of memory is psTrace's trace-levels and dynamic
+ *  error codes.
+ *
+ *  Memory marked as persistent is excluded from memory leak checks.
+ *
+ */
+void p_psMemSetPersistent(
+    psPtr ptr,                         ///< the memory block to operate on
+    bool value                         ///< true if memory is persistent, otherwise false
+);
+
+/** Set whether allocated memory is persistent
+ *
+ *  Set whether allocated memory is persistent. The defeault is false.
+ *
+ *  @return bool:       The previous value of whether all allocated memory is persistent
+ */
+bool p_psMemAllocatePersistent(bool is_persistent); ///< Should all memory allocated be persistent?
+
+/** Get the memory's persistent flag.
+ *
+ *  Checks if a memory block has been marked as persistent by
+ *  p_psMemSetPresistent.
+ *
+ *  Memory marked as persistent is excluded from memory leak checks.
+ *
+ *  @return bool    true if memory is marked persistent, otherwise false.
+ */
+bool p_psMemGetPersistent(
+    psPtr ptr                          ///< the memory block to check.
+);
+
+
+/** Memory re-allocation.  This operates much like realloc(), but is guaranteed to return a non-NULL value.
+ *
+ *  @return psPtr pointer to resized buffer. This will not be NULL.
+ *  @see psAlloc, psFree
+ */
+#ifdef DOXYGEN
+
+psPtr psRealloc(
+    psPtr ptr,                         ///< Pointer to re-allocate
+    size_t size                        ///< Size required
+);
+#else // #ifdef DOXYGEN
+
+psPtr p_psRealloc(
+    psPtr ptr,                         ///< Pointer to re-allocate
+    size_t size,                       ///< Size required
+    const char *filename,              ///< File of call
+    unsigned int lineno                ///< Line number of call
+);
+
+/// Memory re-allocation.  psRealloc sends file and line number to p_psRealloc.
+#ifndef SWIG
+#define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__)
+#endif // ! SWIG
+
+#endif // ! DOXYGEN
+
+/** Free memory.  This operates much like free().
+ *
+ *  @see psAlloc, psRealloc
+ */
+#ifdef DOXYGEN
+void psFree(
+    psPtr ptr                          ///< Pointer to free, if NULL, function returns immediately.
+);
+#else // #ifdef DOXYGEN
+void p_psFree(
+    psPtr ptr,                         ///< Pointer to free
+    const char *filename,              ///< File of call
+    unsigned int lineno                ///< Line number of call
+);
+
+/// Free memory.  psFree sends file and line number to p_psFree.
+#ifndef SWIG
+//#define psFree(ptr) { p_psFree((psPtr)ptr, __FILE__, __LINE__); *(void**)&(ptr) = NULL; }
+#define psFree(ptr) { p_psFree((psPtr)ptr, __FILE__, __LINE__); }
+#endif // ! SWIG
+
+#endif // ! DOXYGEN
+
+/** Check for memory leaks.  This scans for allocated memory buffers not freed with an ID not less than id0.
+ *  This is used to check for memory leaks by:
+ *      -# before a block of code to be checked, store the current ID count via psGetMemId
+ *      -# after the block of code to be checked, call this function using the ID stored above.  If all
+ *         memory in the block that was allocated has been freed, this call should output nothing and
+ *         return 0.
+ *
+ *  If memory leaks are found, the Memory Problem callback will be called as well.
+ *
+ *  @return int  number of memory blocks found as 'leaks', i.e., the number of currently allocated memory
+ *              blocks above id0 that have not been freed.
+ *  @see psAlloc, psFree, psgetMemId, psMemProblemCallbackSet
+ *  @ingroup memTracing
+ */
+int psMemCheckLeaks(
+    psMemId id0,                       ///< don't list blocks with id < id0
+    psMemBlock ***array,               ///< pointer to array of pointers to leaked blocks, or NULL
+    FILE * fd,                         ///< print list of leaks to fd (or NULL)
+    bool persistence                   ///< make check across all object even persistent ones
+);
+
+/** Check for memory corruption.  Scans all currently allocated memory buffers and checks for corruptions,
+ *  i.e., invalid markers that signify a buffer under/overflow.
+ *
+ *  @return int
+ *
+ *  @ingroup memTracing
+ */
+int psMemCheckCorruption(
+    bool abort_on_error                ///< Abort on detecting corruption?
+);
+
+/** Return reference counter
+ *
+ *  @return psReferenceCount
+ *
+ *  @ingroup memRefCount
+ */
+psReferenceCount psMemGetRefCounter(
+    const psPtr ptr                    ///< Pointer to get refCounter for
+);
+
+/** Increment reference counter and return the pointer
+ *
+ *  @return psPtr
+ *
+ *  @ingroup memRefCount
+ */
+#ifdef DOXYGEN
+psPtr psMemIncrRefCounter(
+    const psPtr ptr                    ///< Pointer to increment refCounter, and return
+);
+#else
+psPtr p_psMemIncrRefCounter(
+    const psPtr vptr,                  ///< Pointer to increment refCounter, and return
+    const char *file,                  ///< File of call
+    psS32 lineno                       ///< Line number of call
+);
+
+#ifndef SWIG
+#define psMemIncrRefCounter(vptr) p_psMemIncrRefCounter(vptr, __FILE__, __LINE__)
+#endif // !SWIG
+
+#endif // !DOXYGEN
+
+/** Decrement reference counter and return the pointer
+ *
+ *  @ingroup memRefCount
+ *
+ *  @return psPtr    the pointer deremented in refCount, or NULL if pointer is
+ *                   fully dereferenced.
+ */
+#ifdef DOXYGEN
+psPtr psMemDecrRefCounter(
+    psPtr ptr                         ///< Pointer to decrement refCounter, and return
+);
+#else // DOXYGEN
+psPtr p_psMemDecrRefCounter(
+    psPtr vptr,                        ///< Pointer to decrement refCounter, and return
+    const char *file,                  ///< File of call
+    psS32 lineno                       ///< Line number of call
+);
+
+#ifndef SWIG
+#define psMemDecrRefCounter(vptr) p_psMemDecrRefCounter(vptr, __FILE__, __LINE__)
+#endif // !SWIG
+
+#endif // !DOXYGEN
+
+/** Set reference counter and return the pointer
+ *
+ *  @ingroup memRefCount
+ *
+ *  @return psPtr    the pointer with refCount set, or NULL if pointer is
+ *                   fully dereferenced.
+ */
+#ifdef DOXYGEN
+psPtr psMemSetRefCounter(
+    psPtr ptr,                        ///< Pointer to decrement refCounter, and return
+    psReferenceCount count            ///< New reference count
+);
+#else // DOXYGEN
+psPtr p_psMemSetRefCounter(
+    psPtr vptr,                        ///< Pointer to decrement refCounter, and return
+    psReferenceCount count,            ///< New reference count
+    const char *file,                  ///< File of call
+    psS32 lineno                       ///< Line number of call
+);
+
+#ifndef SWIG
+#define psMemSetRefCounter(vptr, count) p_psMemSetRefCounter(vptr, count, __FILE__, __LINE__)
+#endif // !SWIG
+
+#endif // !DOXYGEN
+
+/** Set callback for problems.
+ *
+ *  At various occasions, the memory manager can check the state of the memory
+ *  stack. If any of these checks discover that the memory stack is corrupted,
+ *  the psMemProblemCallback is called.
+ 
+ *  @ingroup memCallback
+ *
+ *  @return psMemProblemCallback       old psMemProblemCallback function
+ */
+psMemProblemCallback psMemProblemCallbackSet(
+    psMemProblemCallback func          ///< Function to run at memory problem detection
+);
+
+/** Set callback for out-of-memory.
+ *
+ *  If not enough memory is available to satisfy a request by psAlloc or
+ *  psRealloc, these functions attempt to find an alternative solution by
+ *  calling the psMemExhaustedCallback, a function which may be set by the
+ *  programmer in appropriate circumstances, rather than immediately fail.
+ *  The typical use of such a feature may be when a program needs a large
+ *  chunk of memory to do an operation, but the exact size is not critical.
+ *  This feature gives the programmer the opportunity to make a smaller
+ *  request and try again, limiting the size of the operating buffer.
+ *
+ *  @ingroup memCallback
+ *
+ *  @return psMemExhaustedCallback     old psMemExhaustedCallback function
+ */
+psMemExhaustedCallback psMemExhaustedCallbackSet(
+    psMemExhaustedCallback func        ///< Function to run at memory exhaustion
+);
+
+/** Set call back for when a particular memory block is allocated
+ *
+ *  A private variable, p_psMemAllocID, can be used to trace the allocation
+ *  and freeing of specific memory blocks. If p_psMemAllocID is set and a
+ *  memory block with that ID is allocated, psMemAllocCallback is called
+ *  just before memory is returned to the calling function.
+ *
+ *  @ingroup memCallback
+ *
+ *  @return psMemAllocCallback      old psMemAllocCallback function
+ */
+psMemAllocCallback psMemAllocCallbackSet(
+    psMemAllocCallback func            ///< Function to run at memory allocation of specific mem block
+);
+
+/** Set call back for when a particular memory block is freed
+ *
+ *  A private variable, p_psMemFreeID, can be used to trace the freeing of
+ *  specific memory blocks. If p_psMemFreeID is set and the memory block with
+ *  the ID is about to be freed, the psMemFreeCallback callback is called just
+ *  before the memory block is freed.
+ *
+ *  @ingroup memCallback
+ *
+ *  @return psMemFreeCallback          old psMemFreeCallback function
+ */
+psMemFreeCallback psMemFreeCallbackSet(
+    psMemFreeCallback func             ///< Function to run at memory free of specific mem block
+);
+
+/** get next memory ID
+ *
+ *  @ingroup memCallback
+ *
+ *  @return psMemId                 the next memory ID to be used
+ */
+psMemId psMemGetId(void);
+
+/** get the last memory ID used
+ *
+ *  @ingroup memCallback
+ *
+ *  @return psMemId                 the last memory ID used
+ */
+psMemId psMemGetLastId(void);
+
+/** set p_psMemAllocID to specific id
+ *
+ *  A private variable, p_psMemAllocID, can be used to trace the allocation
+ *  and freeing of specific memory blocks. If p_psMemAllocID is set and a
+ *  memory block with that ID is allocated, psMemAllocCallback is called
+ *  just before memory is returned to the calling function.
+ *
+ *  @ingroup memCallback
+ *
+ *  @return psMemId
+ *
+ *  @see psMemAllocCallbackSet
+ */
+psMemId psMemAllocCallbackSetID(
+    psMemId id                         ///< ID to set
+);
+
+/** set p_psMemFreeID to id
+ *
+ *  A private variable, p_psMemFreeID, can be used to trace the freeing of
+ *  specific memory blocks. If p_psMemFreeID is set and the memory block with
+ *  the ID is about to be freed, the psMemFreeCallback callback is called just
+ *  before the memory block is freed.
+ *
+ *  @ingroup memCallback
+ *
+ *  @return psMemId                 the old p_psMemFreeID
+ *
+ *  @see psMemFreeCallbackSet
+ */
+psMemId psMemFreeCallbackSetID(
+    psMemId id                         ///< ID to set
+);
+
+
+/** return statistics on memory usage
+ *
+ * @return the total amount of memory owned by psLib; if non-NULL also provide a breakdown
+ * into recyclable, allocated, and allocated-and-persistent
+ */
+size_t psMemStats(const bool print, ///< print details as they're found?
+                  size_t *allocated, ///< memory that's currently allocated (but not persistent)
+                  size_t *persistent, ///< persistent memory that's currently allocated
+                  size_t *freelist); ///< memory that's waiting to be recycled
+
+//@} End of Memory Management Functions
+
+#ifndef DOXYGEN
+
+/*
+ * Ensure that any program using malloc/realloc/free will fail to compile
+ */
+#ifndef PS_ALLOW_MALLOC
+#ifdef __GNUC__
+#pragma GCC poison malloc realloc calloc free
+#else // __GNUC__
+#define malloc(S)       _Pragma("error Use of malloc is not allowed.  Use psAlloc instead.")
+#define realloc(P,S)    _Pragma("error Use of realloc is not allowed.  Use psRealloc instead.")
+#define calloc(S)       _Pragma("error Use of calloc is not allowed.  Use psAlloc instead.")
+#define free(P)         _Pragma("error Use of free is not allowed.  Use psFree instead.")
+#endif // ! __GNUC__
+#endif // #ifndef PS_ALLOW_MALLOC
+
+#endif // #ifndef DOXYGEN
+
+#endif // #ifndef PS_MEMORY_H
Index: /branches/jch-memory/psLib/src/sys/psTrace.c
===================================================================
--- /branches/jch-memory/psLib/src/sys/psTrace.c	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psTrace.c	(revision 10811)
@@ -0,0 +1,760 @@
+/** @file psTrace.c
+ *  \brief basic run-time trace facilities
+ *  \ingroup LogTrace
+ *
+ *  This file will hold the code for procedures to insert
+ *  trace messages into the code.
+ *
+ *  @author Robert Lupton, Princeton University
+ *  @author GLG, MHPCC
+ *
+ *  @version $Revision: 1.79 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-10-13 22:04:58 $
+ *
+ *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+ */
+
+/*****************************************************************************
+    NOTES:
+ In the SRD, higher trace levels correspond to a numerically lower trace
+ value in the code.  This is a bit confusing.  For example, a high-level
+ message might be something like "Begin Processing".  The module programmer
+ might give that a numerically low trace level, such as 1, so then any
+ non-zero trace level in that code component will display thatmessage.
+ 
+ We build a tree of trace components.  Every node in the tree has a
+ depth, which is it's distance from the root.  However, this is not
+ not the same thing as a node's "level", which corresponds to the
+ trace level of that node.
+ 
+I think the following is the correct behavior, but not sure:
+    PS_UNKNOWN_TRACE_LEVEL: We never set the level of a component to this
+    value.  This value is only used when psTraceGetLevel is called with
+    a bad component name, or if the component root is undefined, I think.
+ 
+    PS_DEFAULT_TRACE_LEVEL: This should only be used when adding the
+    intermediate components of a psS64 name.  Ie. the "B" in .A.B.C
+ 
+ *****************************************************************************/
+
+#ifndef PS_NO_TRACE
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "psAssert.h"
+#include "psMemory.h"
+#include "psTrace.h"
+#include "psString.h"
+#include "psError.h"
+#include "psLogMsg.h"
+
+#define MAX_HOSTNAME_LENGTH 256
+#define MAX_HEADER_LENGTH 256
+#define MAX_TRACE_LENGTH 1024
+#define MAX_COMPONENT_LENGTH 1024
+
+
+static p_psComponent* cRoot = NULL; // The root of the trace component
+static psBool traceTime = false;     // Flag to include time info
+static psBool traceHost = false;     // Flag to include host info
+static psBool traceLevel = false;    // Flag to include level info
+static psBool traceName = false;     // Flag to include name info
+static psBool traceMsg = true;      // Flag to include message info
+static int traceFD = STDOUT_FILENO; // default value
+
+static void componentFree(p_psComponent* comp);
+static p_psComponent* componentAlloc(const char *name, int level);
+static int getLevel(const char *facil);
+
+/*****************************************************************************
+componentAlloc(): allocate memory for a new node, and initialize members.
+ *****************************************************************************/
+static p_psComponent* componentAlloc(const char *name, int level)
+{
+    assert(name);
+
+    p_psComponent* comp = psAlloc(sizeof(p_psComponent));
+
+    p_psMemSetPersistent(comp,true);
+    psMemSetDeallocator(comp, (psFreeFunc) componentFree);
+    comp->name = psStringCopy(name);
+    p_psMemSetPersistent((psPtr)comp->name,true);
+    comp->level = level;
+    comp->n = 0;
+    comp->p_psSpecified = false;
+    comp->subcomp = NULL;
+    return comp;
+}
+
+/*****************************************************************************
+componentFree(): free the current node in the root tree, and all children
+nodes as well.
+ *****************************************************************************/
+static void componentFree(p_psComponent* comp)
+{
+    if (comp == NULL) {
+        return;
+    }
+
+    if (comp->subcomp != NULL) {
+        for (psS32 i = 0; i < comp->n; i++) {
+            p_psMemSetPersistent(comp->subcomp[i],false);
+            psFree(comp->subcomp[i]);
+        }
+        p_psMemSetPersistent(comp->subcomp,false);
+        psFree(comp->subcomp);
+    }
+
+    p_psMemSetPersistent((psPtr)comp->name,false);
+    psFree(comp->name);
+}
+
+/*****************************************************************************
+initTrace(): simply initialize the component root tree.
+*****************************************************************************/
+static void initTrace(void)
+{
+    if (cRoot == NULL) {
+        cRoot = componentAlloc(".", PS_DEFAULT_TRACE_LEVEL);
+    }
+}
+
+// Append the function name to the facility
+// NB: declares TARGET!
+#define FACILITY(TARGET, FUNC, FACIL) \
+size_t _facilLength = strlen(FACIL); /* Length of facility name */ \
+size_t _funcLength = strlen(FUNC);   /* Length of function name */ \
+char TARGET[_facilLength + _funcLength + 2]; /* facility + the function name */ \
+strcpy(&TARGET[0], FACIL); \
+TARGET[_facilLength] = '.'; \
+strcpy(&TARGET[_facilLength + 1], FUNC);
+
+
+/*****************************************************************************
+Set all trace levels to zero.
+ 
+XXX: Currently, no function calls this routine.
+ *****************************************************************************/
+void p_psTraceReset(p_psComponent* currentNode)
+{
+    assert(currentNode);
+
+    psS32 i = 0;
+
+    if (NULL == currentNode) {
+        return;
+    }
+
+    currentNode->level = 0;
+    for (i = 0; i < currentNode->n; i++) {
+        if (NULL == currentNode->subcomp[i]) {
+            psLogMsg("p_psTraceReset", PS_LOG_WARN,
+                     _("Sub-component %d of node %s in trace tree is NULL."),
+                     i, currentNode->name);
+        } else {
+            p_psTraceReset(currentNode->subcomp[i]);
+        }
+    }
+    return;
+}
+
+/*****************************************************************************
+Set all trace levels to zero.
+ *****************************************************************************/
+void psTraceReset()
+{
+    psFree(cRoot);
+    cRoot = NULL;
+}
+
+/*****************************************************************************
+componentAdd(): Adds the component named "addNodeName" to the root tree.
+ *****************************************************************************/
+static psBool componentAdd(const char *addNodeName, psS32 level)
+{
+    assert(addNodeName);
+
+    psS32 i = 0;                        // Loop index variable.
+    char name[MAX_COMPONENT_LENGTH]; // buffer for writeable copy.
+    char *firstComponent = NULL;        // first component of name
+    p_psComponent* currentNode = cRoot;
+    psS32 nodeExists = 0;
+
+    // XXX: Verify that this is the correct behavior.
+    if (strcmp("", addNodeName) == 0) {
+        psError(PS_ERR_BAD_PARAMETER_NULL,true,
+                _("Failed to add null component to trace tree."));
+        return false;
+    }
+
+    // Is this the root node? If so, simply set level and return.
+    if (strcmp(".", addNodeName) == 0) {
+        cRoot->level = level;
+        return true;
+    }
+
+    if (addNodeName[0] != '.') {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,
+                _("Failed to add '%s' to the root component tree; component must start with '.'."),
+                addNodeName);
+        return false;
+    }
+
+    strncpy(name, addNodeName, MAX_COMPONENT_LENGTH);
+    char *pname = name+1;               // Take off the period
+    // Iterate through the components of addNodeName.  Strip off the first
+    // component of the name, find that in the root tree, or add it if it
+    // does not exist, then move to the next component in the name.
+
+    while (pname != NULL) {
+        firstComponent = pname;
+        pname = strchr(firstComponent, '.');
+        if (pname != NULL) {
+            *pname = '\0';
+            pname++;
+        }
+        nodeExists = 0;
+        for (i = 0; i < currentNode->n; i++) {
+            if (strcmp(currentNode->subcomp[i]->name, firstComponent) == 0) {
+                currentNode = currentNode->subcomp[i];
+                nodeExists = 1;
+                if (pname == NULL) {
+                    currentNode->level = level;
+                }
+            }
+        }
+
+        if (nodeExists == 0) {
+            currentNode->subcomp = psRealloc(currentNode->subcomp,
+                                             (currentNode->n + 1) * sizeof(p_psComponent* ));
+            p_psMemSetPersistent(currentNode->subcomp,true);
+
+            currentNode->n = (currentNode->n) + 1;
+
+            if (pname == NULL) {
+                // This is the final component to add.
+                currentNode->subcomp[(currentNode->n) - 1] =
+                    componentAlloc(firstComponent, level);
+            } else {
+                // We are adding an intermediate component.  The trace level
+                // is not defined.  An undefined trace level inherits the
+                // trace level of it's parent.  However, we do not set that
+                // specifically here since that would inheritance to be a
+                // static, one-time, type of behavior.
+
+                currentNode->subcomp[(currentNode->n) - 1] =
+                    componentAlloc(firstComponent, PS_DEFAULT_TRACE_LEVEL);
+            }
+            currentNode = currentNode->subcomp[(currentNode->n) - 1];
+        }
+    }
+
+    return true;
+}
+
+/*****************************************************************************
+    psSetTraceLevel(): add the component named "comp" to the component tree,
+ if it is not already there, and set it's trace level to "level".
+ 
+    NOTE: We modified this so that the user may omit the leading "," in a
+    component name.  Since the code was already implemented assuming the "."
+    was required, rather than change all that code, in this function, I
+    simply add a leading "." to the component name if there is none.
+ 
+    Input:
+ comp
+ level
+    Output:
+ none
+    Returns:
+ zero
+*****************************************************************************/
+int psTraceSetLevel(const char *comp,   // component of interest
+                    int level)  // desired trace level
+{
+    PS_ASSERT_PTR_NON_NULL(comp, 0);
+
+    char *compName = NULL;
+    int prevLevel = -1;
+
+    // If the root component tree does not exist, then initialize it.
+    if (cRoot == NULL) {
+        initTrace();
+    }
+
+    // If the component name has no leading dot, then supply it.
+    if (comp[0] != '.') {
+        compName = (char *) psAlloc(10 + strlen(comp));
+        strcpy(compName, ".");
+        compName = strcat(compName, comp);
+    } else {
+        compName = (char *) comp;
+    }
+    prevLevel = getLevel(compName);
+    // Add the new component to the component tree.
+    if ( !componentAdd(compName, level) ) {
+        psError(PS_ERR_UNKNOWN, false,
+                _("Failed to set trace level (%d) to '%s'."),
+                level,
+                compName);
+
+        if (comp[0] != '.') {
+            psFree(compName);
+        }
+        //        return false;
+        return -1;
+    }
+
+    if (comp[0] != '.') {
+        psFree(compName);
+    }
+
+    //    return true;
+    return prevLevel;
+}
+
+/*****************************************************************************
+    doGetTraceLevel()
+ This function recursively searches the root component tree for the
+ component named "name", which is supplied by a parameter.  If it
+ finds that component, it returns the level of that component.
+ Otherwise, it returns ???.
+ 
+    NOTE: We modified this so that the user may omit the leading "," in a
+    component name.  Since the code was already implemented assuming the "."
+    was required, rather than change all that code, in this function, I
+    simply add a leading "." to the component name if there is none.
+ 
+    Inputs:
+ name:
+    Outputs:
+ none
+    Returns:
+ The trace level of the "name" component.
+ *****************************************************************************/
+static psS32 doGetTraceLevel(const char *aname)
+{
+    assert(aname);
+    char name[strlen(aname) + 1];       // need a writeable copy: for strsep()
+    char *pname = name;
+    char *firstComponent = NULL;        // first component of name
+    p_psComponent* currentNode = cRoot;
+    psS32 i = 0;
+    psS32 defaultLevel = 0;
+
+    if (NULL == currentNode) {
+        return (PS_UNKNOWN_TRACE_LEVEL);
+    }
+
+    if (strcmp(".", aname) == 0) {
+        return (cRoot->level);
+    }
+
+    if (aname[0] != '.') {
+        return (PS_UNKNOWN_TRACE_LEVEL);
+    }
+
+    defaultLevel = cRoot->level;
+    strcpy(name, aname);
+    pname = name+1;
+    while (pname != NULL) {
+        firstComponent = pname;
+        pname = strchr(firstComponent, '.');
+        if (pname != NULL) {
+            *pname = '\0';
+            pname++;
+        }
+        for (i = 0; i < currentNode->n; i++) {
+            if (NULL == currentNode->subcomp[i]) {
+                psLogMsg("p_psTraceReset", PS_LOG_WARN,
+                         _("Sub-component %d of node %s in trace tree is NULL."),
+                         i, currentNode->name);
+            }
+
+            if (strcmp(currentNode->subcomp[i]->name, firstComponent) == 0) {
+                currentNode = currentNode->subcomp[i];
+                // For level inheritance purpose, we save the level of this
+                // component if it is not DEFAULT.
+                if (currentNode->level != PS_DEFAULT_TRACE_LEVEL) {
+                    defaultLevel = currentNode->level;
+                }
+                // Determine if this is the last component:
+                if (pname == NULL) {
+                    if (currentNode->level != PS_DEFAULT_TRACE_LEVEL) {
+                        return (currentNode->level);
+                    } else {
+                        return(defaultLevel);
+                    }
+                }
+            }
+        }
+    }
+    return(defaultLevel);
+}
+
+
+/*****************************************************************************
+    getLevel()
+ Return a trace level of "name" in the root component tree.  If the
+ exact string of components in "name" does not exist in the root
+ tree, we return the deepest level of the match.
+ *****************************************************************************/
+static int getLevel(const char *name)
+{
+    if (cRoot == NULL) {
+        return (PS_UNKNOWN_TRACE_LEVEL);
+    }
+
+    psS32 traceLevel;
+
+    // If the component name has no leading dot, then supply it.
+    if (name[0] != '.') {
+        char compName[strlen(name) + 2];
+        compName[0] = '.';
+        strcpy(&compName[1], name);
+
+        traceLevel = doGetTraceLevel(compName);
+    } else {
+        // Search the component root tree, determine the trace level.
+        traceLevel = doGetTraceLevel(name);
+    }
+
+    // XXX: The default trace level is currently set at -1, which is not a
+    // valid trace level.  This is convenient in determining whether or not
+    // a component should inherit the trace level from parent nodes.  However,
+    // it's not clear that -1 should ever be returned by this function.
+    // The SDR is unclear on this point and we should probably request IfA
+    // comment.
+    if (traceLevel == PS_DEFAULT_TRACE_LEVEL) {
+        traceLevel = PS_THE_OTHER_DEFAULT_TRACE_LEVEL;
+    }
+
+    return(traceLevel);
+}
+
+int p_psTraceGetLevel(const char *file,
+                      int lineno,
+                      const char *func,
+                      const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(name, 0);
+    PS_ASSERT_PTR_NON_NULL(func, 0);
+
+    FACILITY(facility, func, name);
+    return getLevel(facility);
+}
+
+/*****************************************************************************
+    doPrintTraceLevels()
+ This function recursively searches the component tree supplied by the
+ parameter "comp" and prints the name and level of each component.
+    Inputs:
+ comp: a node in the component tree.
+ level: the level of that node
+    Outputs:
+ none
+    Returns:
+ null
+ *****************************************************************************/
+static void doPrintTraceLevels(const p_psComponent* comp,
+                               psS32 depth,
+                               psS32 defLevel)
+{
+    assert(comp);
+
+    char line[1024];
+    psS32 i = 0;
+
+    // XXX EAM : probably should just return if traceFD < 1
+    if (traceFD < 1)
+        return;
+
+    if (comp->name[0] == '\0') {
+        return;
+    } else {
+        if (comp->level == PS_DEFAULT_TRACE_LEVEL) {
+            sprintf(line,"%*s%-*s %d\n", depth, "", 20 - depth, comp->name, defLevel);
+            write (traceFD, line, strlen(line));
+        } else {
+            sprintf(line, "%*s%-*s %d\n", depth, "", 20 - depth, comp->name, comp->level);
+            write (traceFD, line, strlen(line));
+        }
+    }
+
+    for (i = 0; i < comp->n; i++) {
+        if (comp->level == PS_DEFAULT_TRACE_LEVEL) {
+            doPrintTraceLevels(comp->subcomp[i], depth + 1, defLevel);
+        } else {
+            doPrintTraceLevels(comp->subcomp[i], depth + 1, comp->level);
+        }
+    }
+}
+
+
+/*****************************************************************************
+psPrintTraceLevels(): Simply print all the trace levels in the trace level
+component tree.
+Inputs:
+ none
+Outputs:
+ none
+Returns:
+ null
+*****************************************************************************/
+void psTracePrintLevels(void)
+{
+    if (cRoot == NULL) {
+        return;
+    }
+
+    doPrintTraceLevels(cRoot, 0, PS_THE_OTHER_DEFAULT_TRACE_LEVEL);
+}
+
+void psTraceV(const char *comp,
+              int level,
+              const char *format,
+              va_list ap)
+{
+    PS_ASSERT_PTR_NON_NULL(comp, );
+    PS_ASSERT_PTR_NON_NULL(format, );
+
+    // XXX EAM : fd < 1 does not print messages
+    if (traceFD < 1) {
+        return;
+    }
+
+    static bool first = true;           // First time we've been called?
+    static char hostname[MAX_HOSTNAME_LENGTH + 1]; // Host name
+    if (first) {
+        first = false;
+        gethostname(hostname, MAX_HOSTNAME_LENGTH);
+    }
+
+    // Only display this message if it's trace level is less than the level
+    // of it's associatedcomponent.
+    if (level <= getLevel(comp)) {
+
+        char clevel = 0;                    // letter-name for level
+        switch (level) {
+        case PS_LOG_ABORT:
+            clevel = 'A';
+            break;
+        case PS_LOG_ERROR:
+            clevel = 'E';
+            break;
+        case PS_LOG_WARN:
+            clevel = 'W';
+            break;
+        case PS_LOG_INFO:
+            clevel = 'I';
+            break;
+        default:
+            if (level >= 4) {
+                clevel = level + '0';
+            } else {
+                psTrace("psLib.sys", 2, "Invalid logMsg level: %d (%s)\n", level, format);
+                level = (level < 0) ? 0 : 9;
+                clevel = level + '0';
+            }
+        }
+
+        int maxLength = MAX_HEADER_LENGTH; // Maximum length of header string
+        char head[maxLength + 2];       // the added two are for the ending | and \0
+        char *head_ptr = head;          // where we've got to in head
+
+        // Create the various log fields...
+        if (traceTime) {
+            time_t clock = time(NULL);  // The current time.
+            struct tm *utc = gmtime(&clock);    // The current gm time.
+            maxLength -= snprintf(head_ptr, maxLength, "%4d:%02d:%02d %02d:%02d:%02dZ",
+                                  utc->tm_year + 1900, utc->tm_mon + 1, utc->tm_mday,
+                                  utc->tm_hour, utc->tm_min, utc->tm_sec) - 1;
+            head_ptr += strlen(head_ptr);
+        }
+        // Hostname should be 20 characters.
+        if (traceHost) {
+            if (head_ptr > head) {
+                *head_ptr++ = '|';
+            }
+            maxLength -= snprintf(head_ptr, maxLength, "%-20s", hostname);
+            head_ptr += strlen(head_ptr);
+        }
+        if (traceLevel) {
+            if (head_ptr > head) {
+                *head_ptr++ = '|';
+            }
+            maxLength -= snprintf(head_ptr, maxLength, "%c", clevel);
+            head_ptr += strlen(head_ptr);
+        }
+        if (traceName) {
+            if (head_ptr > head) {
+                *head_ptr++ = '|';
+            }
+            maxLength -= snprintf(head_ptr, maxLength, "%s", comp);
+
+            head_ptr += strlen(head_ptr);
+        }
+
+        if (head_ptr > head) {
+            *head_ptr++ = '\n';
+        } else if (!traceMsg) {                  // no output desired
+            return;
+        }
+        *head_ptr = '\0';
+
+        write(traceFD, head, strlen(head));
+
+        if (traceMsg) {
+            // We indent each message one space for each level of the message.
+            for (int i = 0; i < level; i++) {
+                write (traceFD, " ", 1);
+            }
+            psString line = NULL;       // Line to print
+            psStringAppendV(&line, format, ap);
+            write (traceFD, line, strlen(line));
+            if (line[strlen(line) - 1] != '\n') {
+                write(traceFD, "\n", 1);
+            }
+            psFree(line);
+        } else {
+            write(traceFD, "\n", 1);
+        }
+
+        // XXX: what is fd-appropriate equivalent of fflush?
+    }
+}
+
+/*****************************************************************************
+p_psTrace(): we display the trace message to standard output if the trace
+level of that message, supplied by the parameter "level" is higher than the
+trace level that is currently associated with the component named by the
+parameter "comp".
+Input:
+ comp
+ level
+ ...  a printf-style output string.
+Output:
+ none
+Return:
+ null
+ *****************************************************************************/
+void p_psTrace(
+    const char* file,                  ///< file name
+    int lineno,                        ///< line number in file
+    const char* func,                  ///< function name
+    const char *facil,                 ///< facilty of interest
+    psS32 level,                       ///< desired trace level
+    const char *format,                ///< printf-style format command
+    ...                                ///< trace message arguments
+)
+{
+    PS_ASSERT_PTR_NON_NULL(file, );
+    PS_ASSERT_PTR_NON_NULL(func, );
+    PS_ASSERT_PTR_NON_NULL(facil, );
+    PS_ASSERT_PTR_NON_NULL(format, );
+
+    FACILITY(name, func, facil);
+
+    va_list ap;
+    va_start(ap, format);
+    psTraceV(name, level, format, ap);
+    va_end(ap);
+}
+
+bool psTraceSetDestination(int fd)
+{
+    if (fd < 0) {
+        return false;
+    }
+
+    if (traceFD > STDERR_FILENO) {
+        close(traceFD);
+    }
+    traceFD = fd;
+    return true;
+}
+
+int psTraceGetDestination()
+{
+    return traceFD;
+}
+
+/*****************************************************************************
+psTraceSetFormat(): Set the format of psTrace output.  More precisely,
+    provide a string consisting of the letters {H (host), L (level), M
+    (message), N (name), T (time)}.  The default is "HLMNT".  This string
+    determines whether or not they associated type of information will be
+    included in message traces.  It does not determine the order in which that
+    information will appear (that order is fixed).
+ 
+Input:
+    fmt: a string specifying the format.
+Return:
+    NULL.
+ *****************************************************************************/
+bool psTraceSetFormat(const char *format)
+{
+    // assume none.
+    traceHost = false;
+    traceLevel = false;
+    traceMsg = false;
+    traceName = false;
+    traceTime = false;
+
+    // if fmt is NULL, no logging is desired.
+    if (format == NULL) {
+        return false;
+    }
+
+    // XXX: What is the purpose of this conditional.
+    if (strlen(format) == 0) {
+        format = "THLNM";
+    }
+    // Step through each character in the format string.  For each letter
+    // in that string, set the appropriate logging.
+
+    for (const char *ptr = format; *ptr != '\0'; ptr++) {
+        switch (*ptr) {
+        case 'H':
+        case 'h':
+            traceHost = true;
+            break;
+        case 'L':
+        case 'l':
+            traceLevel = true;
+            break;
+        case 'M':
+        case 'm':
+            traceMsg = true;
+            break;
+        case 'N':
+        case 'n':
+            traceName = true;
+            break;
+        case 'T':
+        case 't':
+            traceTime = true;
+            break;
+        default:
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                    _("Unknown logging keyword %c."), *ptr);
+            return false;
+        }
+    }
+
+    // XXX: If one must at least log error messages, why don't we set logMsg = true here?
+    if (!traceMsg) {
+        psTrace("psLib.sys", 1,
+                "You must at least trace error messages (You chose \"%s\")", format);
+
+    }
+    return true;
+}
+
+
+
+#endif // #ifndef PS_NO_TRACE
Index: /branches/jch-memory/psLib/src/sys/psType.h
===================================================================
--- /branches/jch-memory/psLib/src/sys/psType.h	(revision 10811)
+++ /branches/jch-memory/psLib/src/sys/psType.h	(revision 10811)
@@ -0,0 +1,304 @@
+/** @file  psType.h
+*
+*  @brief Contains support for basic types
+*
+*  This file defines common datatypes used throughout psLib.
+*
+*  @ingroup DataContainer
+*
+*  @author Robert DeSonia, MHPCC
+*  @author Ross Harman, MHPCC
+*
+*  @version $Revision: 1.52 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-10-14 00:02:31 $
+*
+*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+*/
+
+#ifndef PS_TYPE_H
+#define PS_TYPE_H
+
+#include <complex.h>
+#include <stdint.h>
+#include <float.h>
+#include <stdbool.h>
+
+/// @addtogroup DataContainer
+/// @{
+
+/******************************************************************************/
+
+/*  TYPE DEFINITIONS                                                          */
+
+/******************************************************************************/
+
+/** Basic data types used by the containers.
+ *
+ * The basic types of the primitives used by psLib are defined within this enum. This enum is in turn used by
+ * the psType struct.
+ *
+ */
+
+typedef uint8_t psU8;                  ///< 8-bit unsigned int
+typedef uint16_t psU16;                ///< 16-bit unsigned int
+typedef uint32_t psU32;                ///< 32-bit unsigned int
+typedef uint64_t psU64;                ///< 64-bit unsigned int
+typedef int8_t psS8;                   ///< 8-bit signed int
+typedef int16_t psS16;                 ///< 16-bit signed int
+typedef int32_t psS32;                 ///< 32-bit signed int
+typedef int64_t psS64;                 ///< 64-bit signed int
+typedef float psF32;                   ///< 32-bit floating point
+typedef double psF64;                  ///< 64-bit floating point
+
+#ifdef SWIG
+/** 32-bit complex value */
+typedef struct
+{
+    float re, im;
+}
+psC32;
+
+/** 64-bit complex value */
+typedef struct
+{
+    double re,im;
+}
+psC64;
+
+#else // SWIG
+typedef float complex psC32;          ///< complex with 32-bit floating point Real and Imagary numbers
+typedef double complex psC64;         ///< complex with 64-bit floating point Real and Imagary numbers
+#endif // !SWIG
+
+typedef char* psString;                ///< string value
+typedef void* psPtr;                   ///< void pointer
+typedef bool psBool;                   ///< boolean value
+
+/** Enumeration of data types for function elements.
+ *  Contains replacements for native types.
+ */
+typedef enum {
+    PS_TYPE_S8   = 0x0101,             ///< Character.
+    PS_TYPE_S16  = 0x0102,             ///< Short integer.
+    PS_TYPE_S32  = 0x0104,             ///< Integer.
+    PS_TYPE_S64  = 0x0108,             ///< Long integer.
+    PS_TYPE_U8   = 0x0301,             ///< Unsigned character.
+    PS_TYPE_U16  = 0x0302,             ///< Unsigned psS16 integer.
+    PS_TYPE_U32  = 0x0304,             ///< Unsigned integer.
+    PS_TYPE_U64  = 0x0308,             ///< Unsigned psS64 integer.
+    PS_TYPE_F32  = 0x0404,             ///< Single-precision Floating point.
+    PS_TYPE_F64  = 0x0408,             ///< Double-precision floating point.
+    PS_TYPE_C32  = 0x0808,             ///< Complex numbers consisting of single-precision floating point.
+    PS_TYPE_C64  = 0x0810,             ///< Complex numbers consisting of double-precision floating point.
+    PS_TYPE_BOOL = 0x1301              ///< Boolean.
+} psElemType;
+
+/** Enumeration primarily used with metadata which defines a data structure
+ *  e.g., list, array, FITS file, etc.
+*/
+typedef enum {
+    PS_DATA_S8   = PS_TYPE_S8,         ///< psS8
+    PS_DATA_S16  = PS_TYPE_S16,        ///< psS16
+    PS_DATA_S32  = PS_TYPE_S32,        ///< psS32
+    PS_DATA_S64  = PS_TYPE_S64,        ///< psS64
+    PS_DATA_U8   = PS_TYPE_U8,         ///< psU8
+    PS_DATA_U16  = PS_TYPE_U16,        ///< psU16
+    PS_DATA_U32  = PS_TYPE_U32,        ///< psU32
+    PS_DATA_U64  = PS_TYPE_U64,        ///< psU64
+    PS_DATA_F32  = PS_TYPE_F32,        ///< psF32
+    PS_DATA_F64  = PS_TYPE_F64,        ///< psF64
+    PS_DATA_BOOL = PS_TYPE_BOOL,       ///< psBool
+    PS_DATA_STRING = 0x10000,          ///< psString (char *)
+    PS_DATA_ARRAY,                     ///< psArray
+    PS_DATA_BITSET,                    ///< psBitSet
+    PS_DATA_CUBE,                      ///< psCube
+    PS_DATA_FITS,                      ///< psFits
+    PS_DATA_HASH,                      ///< psHash
+    PS_DATA_HISTOGRAM,                 ///< psHistogram
+    PS_DATA_IMAGE,                     ///< psImage
+    PS_DATA_KERNEL,                    ///< psKernel
+    PS_DATA_LINE,                      ///< psLine
+    PS_DATA_LIST,                      ///< psList
+    PS_DATA_LOOKUPTABLE,               ///< psLookupTable
+    PS_DATA_METADATA,                  ///< psMetadata
+    PS_DATA_METADATAITEM,              ///< psMetadataItem
+    PS_DATA_MINIMIZATION,              ///< psMinimization
+    PS_DATA_PIXELS,                    ///< psPixels
+    PS_DATA_PLANE,                     ///< psPlane
+    PS_DATA_PLANEDISTORT,              ///< psPlaneDistort
+    PS_DATA_PLANETRANSFORM,            ///< psPlaneTransform
+    PS_DATA_POLYNOMIAL1D,              ///< psPolynomial1D
+    PS_DATA_POLYNOMIAL2D,              ///< psPolynomial2D
+    PS_DATA_POLYNOMIAL3D,              ///< psPolynomial3D
+    PS_DATA_POLYNOMIAL4D,              ///< psPolynomial4D
+    PS_DATA_PROJECTION,                ///< psProjection
+    PS_DATA_REGION,                    ///< psRegion
+    PS_DATA_SCALAR,                    ///< psScalar
+    PS_DATA_SPHERE,                    ///< psSphere
+    PS_DATA_SPHEREROT,                 ///< psSphereTransform
+    PS_DATA_SPLINE1D,                  ///< psSpline1D
+    PS_DATA_STATS,                     ///< psStats
+    PS_DATA_TIME,                      ///< psTime
+    PS_DATA_VECTOR,                    ///< psVector
+    PS_DATA_UNKNOWN,                   ///< Other data of an unknown type
+    PS_DATA_METADATA_MULTI             ///< Used internally for metadata; not a 'real' type
+} psDataType;
+
+#define PS_TYPE_MASK PS_TYPE_U8        /**< the psElemType to use for mask image */
+#define PS_TYPE_MASK_DATA U8           /**< the data member to use for mask image */
+#define PS_TYPE_MASK_NAME "psU8"       /**< the data type for mask as a string */
+
+typedef psU8 psMaskType;               ///< the C datatype for a mask image
+typedef psBool psBOOL;                 ///< allow psBOOL to be used instead of psBool (for macros)
+
+#define PS_MIN_S8        INT8_MIN      /**< minimum valid psS8 value */
+#define PS_MIN_S16       INT16_MIN     /**< minimum valid psS16 value */
+#define PS_MIN_S32       INT32_MIN     /**< minimum valid psS32 value */
+#define PS_MIN_S64       INT64_MIN     /**< minimum valid psS64 value */
+#define PS_MIN_U8        0             /**< minimum valid psU8 value */
+#define PS_MIN_U16       0             /**< minimum valid psU16 value */
+#define PS_MIN_U32       0             /**< minimum valid psU32 value */
+#define PS_MIN_U64       0             /**< minimum valid psU64 value */
+#define PS_MIN_F32       -FLT_MAX      /**< minimum valid psF32 value */
+#define PS_MIN_F64       -DBL_MAX      /**< minimum valid psF64 value */
+#define PS_MIN_C32       -FLT_MAX      /**< minimum valid real or imaginary psC32 value */
+#define PS_MIN_C64       -DBL_MAX      /**< minimum valid real or imaginary psC32 value */
+
+#define PS_MAX_S8        INT8_MAX      /**< maximum valid psS8 value */
+#define PS_MAX_S16       INT16_MAX     /**< maximum valid psS16 value */
+#define PS_MAX_S32       INT32_MAX     /**< maximum valid psS32 value */
+#define PS_MAX_S64       INT64_MAX     /**< maximum valid psS64 value */
+#define PS_MAX_U8        UINT8_MAX     /**< maximum valid psU8 value */
+#define PS_MAX_U16       UINT16_MAX    /**< maximum valid psU16 value */
+#define PS_MAX_U32       UINT32_MAX    /**< maximum valid psU32 value */
+#define PS_MAX_U64       UINT64_MAX    /**< maximum valid psU64 value */
+#define PS_MAX_F32       FLT_MAX       /**< maximum valid psF32 value */
+#define PS_MAX_F64       DBL_MAX       /**< maximum valid psF64 value */
+#define PS_MAX_C32       FLT_MAX       /**< maximum valid real or imaginary psC32 value */
+#define PS_MAX_C64       DBL_MAX       /**< maximum valid real or imaginary psC32 value */
+
+#define PS_TYPE_BOOL_NAME "psBool"
+#define PS_TYPE_S8_NAME   "psS8"
+#define PS_TYPE_S16_NAME  "psS16"
+#define PS_TYPE_S32_NAME  "psS32"
+#define PS_TYPE_S64_NAME  "psS64"
+#define PS_TYPE_U8_NAME   "psU8"
+#define PS_TYPE_U16_NAME  "psU16"
+#define PS_TYPE_U32_NAME  "psU32"
+#define PS_TYPE_U64_NAME  "psU64"
+#define PS_TYPE_F32_NAME  "psF32"
+#define PS_TYPE_F64_NAME  "psF64"
+#define PS_TYPE_C32_NAME  "psC32"
+#define PS_TYPE_C64_NAME  "psC64"
+
+#define PS_TYPE_NAME(value,type) \
+switch(type) { \
+case PS_TYPE_BOOL: \
+    value = PS_TYPE_BOOL_NAME; \
+    break; \
+case PS_TYPE_S8: \
+    value = PS_TYPE_S8_NAME; \
+    break; \
+case PS_TYPE_S16: \
+    value = PS_TYPE_S16_NAME; \
+    break; \
+case PS_TYPE_S32: \
+    value = PS_TYPE_S32_NAME; \
+    break; \
+case PS_TYPE_S64: \
+    value = PS_TYPE_S64_NAME; \
+    break; \
+case PS_TYPE_U8: \
+    value = PS_TYPE_U8_NAME; \
+    break; \
+case PS_TYPE_U16: \
+    value = PS_TYPE_U16_NAME; \
+    break; \
+case PS_TYPE_U32: \
+    value = PS_TYPE_U32_NAME; \
+    break; \
+case PS_TYPE_U64: \
+    value = PS_TYPE_U64_NAME; \
+    break; \
+case PS_TYPE_F32: \
+    value = PS_TYPE_F32_NAME; \
+    break; \
+case PS_TYPE_F64: \
+    value = PS_TYPE_F64_NAME; \
+    break; \
+case PS_TYPE_C32: \
+    value = PS_TYPE_C32_NAME; \
+    break; \
+case PS_TYPE_C64: \
+    value = PS_TYPE_C64_NAME; \
+    break; \
+default: \
+    value = "unknown"; \
+};
+
+/// Macro to get the bad pixel reason code (stored as part of mask value)
+#define PS_BADPIXEL_BITMASK 0x0f
+#define PS_GET_BADPIXEL(maskValue) (maskValue & PS_BADPIXEL_BITMASK)
+
+#define PS_IS_BADPIXEL(maskValue) (PS_GET_BADPIXEL(maskValue) != 0)
+
+/// Macro to apply a bad pixel reason code to mask image
+#define PS_SET_BADPIXEL(maskValue, reasonCode) \
+{ \
+    maskValue = (psMaskType)((reasonCode & PS_BADPIXEL_BITMASK) | (maskValue & ~PS_BADPIXEL_BITMASK)); \
+}
+
+/// Macro to determine if the psElemType is an integer.
+#define PS_IS_PSELEMTYPE_INT(x) ((x & 0x100) == 0x100)
+/// Macro to determine if the psElemType is unsigned.
+#define PS_IS_PSELEMTYPE_UNSIGNED(x) ((x & 0x200) == 0x200)
+/// Macro to determine if the psElemType is a real (non-complex) floating-point type.
+#define PS_IS_PSELEMTYPE_REAL(x) ((x & 0x400) == 0x400)
+/// Macro to determine if the psElemType is complex number type.
+#define PS_IS_PSELEMTYPE_COMPLEX(x) ((x & 0x800) == 0x800)
+/// Macro to determine if the psElemType is boolean type.
+#define PS_IS_PSELEMTYPE_BOOL(x) ((x & 0x1000) == 0x1000)
+/// Macro to determine the storage size, in bytes, of the psElemType.
+#define PSELEMTYPE_SIZEOF(x) (x & 0xFF)
+
+/** Dimensions of a data type.
+ *
+ * The dimensions of containers used by psLib are defined within this enum. This enum is used by the psType
+struct. *
+ */
+typedef enum {
+    PS_DIMEN_SCALAR,            ///< Scalar.
+    PS_DIMEN_VECTOR,            ///< Vector.
+    PS_DIMEN_TRANSV,            ///< Transposed vector.
+    PS_DIMEN_IMAGE,             ///< Image.
+    PS_DIMEN_OTHER              ///< Something else that's not supported for arithmetic.
+} psDimen;
+
+/** The type of a data type.
+ *
+ * All psLib complex types consist of primitive components. This struct provides the description of those
+ * primitives.
+ *
+ */
+typedef struct
+{
+    psElemType type;                   ///< The type
+    psDimen dimen;                     ///< The dimensionality.
+}
+psMathType;
+
+/** The type of a basic data type
+ *
+ *  All psLib complex types consist of primitive components.  This structure provides the ability to cast
+ *  an unknown data structure to safely test the underlining data type.
+ *
+ */
+typedef struct
+{
+    psMathType type;              ///< Data type information
+}
+psMath;
+
+/// @}
+
+#endif // #ifndef PS_TYPE_H
Index: /branches/jch-memory/psLib/test/sys/tap_psMemory.c
===================================================================
--- /branches/jch-memory/psLib/test/sys/tap_psMemory.c	(revision 10811)
+++ /branches/jch-memory/psLib/test/sys/tap_psMemory.c	(revision 10811)
@@ -0,0 +1,789 @@
+/** @file  tst_psMemory.c
+*
+*  @brief Contains the tests for psMemory.[ch]
+*
+*
+*  @author Robert DeSonia, MHPCC
+*
+*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-12-18 19:18:46 $
+*
+*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
+*/
+
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <stdlib.h>
+
+
+#include "pslib.h" // need to allow malloc for callback use
+#include "tap.h"
+#include "pstap.h"
+
+static psS32 problemCallbackCalled = 0;
+static psS32 allocCallbackCalled = 0;
+static psS32 freeCallbackCalled = 0;
+static psS32 exhaustedCallbackCalled = 0;
+
+psMemId memAllocCallback( const psMemBlock *ptr );
+psMemId memFreeCallback( const psMemBlock *ptr );
+psS32 memCheckTypes( void );
+void memProblemCallback( psMemBlock *ptr, const char *filename, unsigned int lineno );
+psPtr TPOutOfMemoryExhaustedCallback( size_t size );
+
+
+psS32 main(psS32 argc, char* argv[])
+{
+    plan_tests(1);
+
+    void TPFreeReferencedMemory( void );
+    TPFreeReferencedMemory();
+
+    void TPOutOfMemory( void );
+    TPOutOfMemory();
+
+    void TPReallocOutOfMemory( void );
+    TPReallocOutOfMemory();
+
+    void TPCheckBufferPositive( void );
+    TPCheckBufferPositive();
+
+    void TPrealloc( void );
+    TPrealloc();
+
+    void TPallocCallback( void );
+    TPallocCallback();
+
+    void TPcheckLeaks( void );
+    TPcheckLeaks();
+
+    void TPmemCorruption( void );
+    TPmemCorruption();
+
+    void TPmultipleFree( void );
+    TPmultipleFree();
+}
+
+
+// Testpoint #449, psAlloc shall allocate memory blocks writeable by caller.
+void TPCheckBufferPositive( void )
+{
+    diag("TPCheckBufferPositive");
+
+    psS32 * mem;
+    const psS32 size = 100;
+    psS32 failed = 0;
+
+    mem = ( psS32* ) psAlloc( size * sizeof( psS32 ) );
+    ok ( mem != NULL, "psAlloc returned non-NULL value" );
+
+    for ( psS32 index = 0;index < size;index++ ) {
+        mem[ index ] = index;
+    }
+
+    for ( psS32 index = 0;index < size;index++ ) {
+        if ( mem[ index ] != index ) {
+            failed++;
+        }
+    }
+    ok( failed == 0, "mem legit" );
+
+    psFree( mem );
+}
+
+void TPFreeReferencedMemory( void )
+{
+    diag("TPFreeReferencedMemory");
+
+    // create memory
+    psS32 * mem;
+    psS32 ref = 0;
+
+    mem = ( psS32* ) psAlloc( 100 * sizeof( psS32 ) );
+
+    ref = psMemGetRefCounter( mem );
+    ok ( ref == 1, "buffer reference count %d.", ref );
+    skip_start ( ref != 1, 3, "buffer reference count %d.", ref );
+
+    psMemIncrRefCounter( mem );
+    psMemIncrRefCounter( mem );
+    psMemIncrRefCounter( mem );
+
+    ref = psMemGetRefCounter( mem );
+    ok ( ref == 4, "buffer reference count was %d.", ref );
+    skip_start ( ref != 4, 2, "buffer reference count was %d.", ref );
+
+    psMemDecrRefCounter( mem );
+    psMemDecrRefCounter( mem );
+
+    ref = psMemGetRefCounter( mem );
+    ok ( ref == 2, "Found buffer reference count to be %d.", ref );
+    skip_start ( ref != 2, 1, "Found buffer reference count to be %d.", ref );
+
+    psMemDecrRefCounter( mem );
+
+    ref = psMemGetRefCounter( mem );
+    ok ( ref == 1, "Found buffer reference count to be %d.", ref );
+
+    skip_end();
+    skip_end();
+    skip_end();
+
+    psFree( mem );
+}
+
+// Bug/Task #562 regression test.  Upon requesting more memory than is available, psRealloc shall call
+// the psMemExhaustedCallback.
+void TPReallocOutOfMemory( void )
+{
+    diag("TPReallocOutOfMemory");
+
+    psS32 * mem[ 100 ];
+    psMemExhaustedCallback cb;
+
+    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
+        mem[ lcv ] = NULL;
+    }
+
+    exhaustedCallbackCalled = 0;
+
+    cb = psMemExhaustedCallbackSet( TPOutOfMemoryExhaustedCallback );
+
+    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
+        mem[ lcv ] = ( psS32* ) psAlloc( 10 );
+    }
+
+    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
+        mem[ lcv ] = ( psS32* ) psRealloc( mem[ lcv ], SIZE_MAX/2 - 1000 );
+    }
+
+    psMemExhaustedCallbackSet( cb );
+
+    ok ( exhaustedCallbackCalled != 0,
+         "Called psRealloc with HUGE memory requirement and survived in %s!", __func__ );
+
+    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
+        psFree( mem[ lcv ] );
+    }
+}
+
+
+// Testpoint #450,  Upon requesting more memory than is available, psalloc shall call
+// the psMemExhaustedCallback.
+void TPOutOfMemory( void )
+{
+    diag("TPOutOfMemory");
+
+    psS32 * mem[ 100 ];
+    psMemExhaustedCallback cb;
+
+    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
+        mem[ lcv ] = NULL;
+    }
+
+    exhaustedCallbackCalled = 0;
+    cb = psMemExhaustedCallbackSet( TPOutOfMemoryExhaustedCallback );
+
+    #ifdef COMMENTED_OUT
+    // Don't include since intentionally aborts
+
+    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
+        mem[ lcv ] = ( psS32* ) psAlloc( SIZE_MAX/2 - 1000 );
+    }
+
+    psMemExhaustedCallbackSet( cb );
+
+    ok ( exhaustedCallbackCalled != 0,
+         "Called psAlloc with HUGE memory requirement and survived!");
+
+    for ( psS32 lcv = 0; lcv < 100; lcv++ ) {
+        psFree( mem[ lcv ] );
+    }
+    #endif
+}
+
+
+// Testpoint #451,  psRealloc shall increase/decrease memory buffer while preserving contents
+void TPrealloc( void )
+{
+    diag("TPrealloc");
+
+    psS32 * mem1;
+    psS32* mem2;
+    psS32* mem3;
+    const psS32 initialSize = 100;
+
+    // allocate buffer with known values.
+    mem1 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
+    mem2 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
+    mem3 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
+    for ( psS32 lcv = 0;lcv < initialSize;lcv++ ) {
+        mem1[ lcv ] = mem2[ lcv ] = mem3[ lcv ] = lcv;
+    }
+
+    psMemCheckCorruption( 1 );
+
+    // realloc to 2x
+    mem1 = ( psS32* ) psRealloc( mem1, 2 * initialSize * sizeof( psS32 ) );
+    mem2 = ( psS32* ) psRealloc( mem2, 2 * initialSize * sizeof( psS32 ) );
+    mem3 = ( psS32* ) psRealloc( mem3, 2 * initialSize * sizeof( psS32 ) );
+
+    // check values of initial block
+    int error = 0;
+    for ( psS32 i = 0;i < initialSize;i++ ) {
+        if ( mem1[ i ] != i || mem2[ i ] != i || mem3[ i ] != i ) {
+            error = 1;
+            break;
+        }
+    }
+    ok(error==0, "Realloc preserve the contents with expanding buffer");
+
+    psMemCheckCorruption( 1 );
+
+    // realloc to 1/2 initial value.
+    mem1 = ( psS32* ) psRealloc( mem1, ( initialSize / 2 ) * sizeof( psS32 ) );
+    mem2 = ( psS32* ) psRealloc( mem2, ( initialSize / 2 ) * sizeof( psS32 ) );
+    mem3 = ( psS32* ) psRealloc( mem3, ( initialSize / 2 ) * sizeof( psS32 ) );
+
+    // check values of initial block
+    error = 0;
+    for ( psS32 i = 0;i < initialSize / 2;i++ ) {
+        if ( mem1[ i ] != i || mem2[ i ] != i || mem3[ i ] != i ) {
+            error = 1;
+            break;
+        }
+    }
+    ok(error==0, "Realloc preserved the contents with shrinking buffer");
+
+    psFree( mem1 );
+    psFree( mem2 );
+    psFree( mem3 );
+}
+
+
+void TPallocCallback( void )
+{
+    diag("TPallocCallback");
+
+    psS32 * mem1;
+    psS32* mem2;
+    psS32* mem3;
+    psS32 currentId = psMemGetId();
+    const psS32 initialSize = 100;
+    psS32 mark;
+
+    allocCallbackCalled = 0;
+    freeCallbackCalled = 0;
+    psMemAllocCallbackSet( memAllocCallback );
+    psMemFreeCallbackSet( memFreeCallback );
+
+    psMemAllocCallbackSetID( currentId + 1 );
+    psMemFreeCallbackSetID( currentId + 1 );
+
+    // allocate buffer with known values.
+    mem1 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
+    mem2 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
+    mem3 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
+
+    psFree( mem1 );
+    psFree( mem2 );
+    psFree( mem3 );
+
+    ok( allocCallbackCalled == 2 && freeCallbackCalled == 2,
+        "alloc/free callbacks called the proper number of times" );
+    skip_start( allocCallbackCalled != 2 || freeCallbackCalled != 2,
+                1, "alloc/free callbacks called the proper number of times" );
+
+    allocCallbackCalled = 0;
+    freeCallbackCalled = 0;
+
+    mark = psMemGetId();
+
+    mem1 = ( psS32* ) psAlloc( initialSize * sizeof( psS32 ) );
+
+    psMemAllocCallbackSetID( mark );
+
+    mem1 = ( psS32* ) psRealloc( mem1, initialSize * 2 * sizeof( psS32 ) );
+
+    psFree( mem1 );
+
+    ok ( allocCallbackCalled == 2,
+         "realloc callbacks were called the proper number of times" );
+
+    skip_end();
+}
+
+
+void TPcheckLeaks( void )
+{
+    const psS32 numBuffers = 5;
+    psS32* buffers[ 5 ];
+    psS32 lcv;
+    psS32 currentId = psMemGetId();
+    psMemBlock** blks;
+    psS32 nLeaks = 0;
+    psS32 lineMark = 0;
+
+    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
+        lineMark = __LINE__ + 1;
+        buffers[ lcv ] = psAlloc( sizeof( psS32 ) );
+    }
+
+    for ( lcv = 1;lcv < numBuffers;lcv++ ) {
+        psFree( buffers[ lcv ] );
+    }
+
+    nLeaks = psMemCheckLeaks( currentId, &blks, stderr, false );
+
+    ok ( nLeaks == 1, "psMemCheckLeaks found %d leaks", nLeaks );
+    skip_start ( nLeaks != 1, 5, "psMemCheckLeaks found %d leaks", nLeaks );
+
+    ok ( blks[ 0 ] ->lineno == lineMark,
+         "psMemCheckLeaks found a leak other than the expected one (line %d vs %d)", lineMark, blks[ 0 ] ->lineno );
+    skip_start ( blks[ 0 ] ->lineno != lineMark,
+                 4,"psMemCheckLeaks found a leak other than the expected one (line %d vs %d)", lineMark, blks[ 0 ] ->lineno );
+
+    psFree( buffers[ 0 ] );
+    psFree( blks );
+
+    psMemCheckLeaks(currentId,NULL,stderr, false);
+
+    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
+        lineMark = __LINE__ + 1;
+        buffers[ lcv ] = psAlloc( sizeof( psS32 ) );
+    }
+
+    for ( lcv = 0;lcv < numBuffers - 1;lcv++ ) {
+        psFree( buffers[ lcv ] );
+    }
+
+    nLeaks = psMemCheckLeaks( currentId, &blks, stderr, false );
+
+    ok ( nLeaks == 1, "psMemCheckLeaks found %d leaks.", nLeaks );
+    skip_start ( nLeaks != 1, 3, "psMemCheckLeaks found %d leaks.", nLeaks );
+
+    ok ( blks[ 0 ] ->lineno == lineMark, "psMemCheckLeaks found leaks");
+    skip_start ( blks[ 0 ] ->lineno==lineMark,2,"psMemCheckLeaks found leaks");
+
+    psFree( buffers[ 4 ] );
+    psFree( blks );
+
+    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
+        lineMark = __LINE__ + 1;
+        buffers[ lcv ] = psAlloc( sizeof( psS32 ) );
+    }
+
+    for ( lcv = 0;lcv < numBuffers;lcv++ ) {
+        if ( lcv % 2 == 0 ) {
+            psFree( buffers[ lcv ] );
+        }
+    }
+
+    nLeaks = psMemCheckLeaks( currentId, &blks, stderr, false );
+
+    ok ( nLeaks == 2, "psMemCheckLeaks found %d leaks.", nLeaks);
+    skip_start ( nLeaks != 2, 1, "psMemCheckLeaks found %d leaks.", nLeaks);
+
+    ok ( blks[ 0 ] ->lineno == lineMark,
+         "psMemCheckLeaks found a leak other than the expected." );
+
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+
+    psFree( blks );
+    psFree( buffers[ 1 ] );
+    psFree( buffers[ 3 ] );
+}
+
+
+void TPmemCorruption( void )
+{
+    diag("TPmemCorruption");
+
+    psS32 * buffer = NULL;
+    psS32 oldValue = 0;
+    psS32 corruptions = 0;
+    psMemProblemCallback cb;
+
+    buffer = psAlloc( sizeof( psS32 ) );
+
+    // cause memory corruption via buffer underflow
+    *buffer = 1;
+    buffer--;
+    oldValue = *buffer;
+    *buffer = 2;
+
+    problemCallbackCalled = 0;
+    cb = psMemProblemCallbackSet( memProblemCallback );
+
+    corruptions = psMemCheckCorruption( 0 );
+
+    // restore the memory problem callback
+    psMemProblemCallbackSet( cb );
+
+    // restore the value, 'uncorrupting' the buffer
+    *buffer = oldValue;
+    buffer++;
+
+    psFree( buffer );
+
+    ok ( corruptions == 1,
+         "Expected one memory corruption but found %d", corruptions );
+    skip_start ( corruptions != 1,
+                 1, "Expected one memory corruption but found %d", corruptions );
+
+    ok ( problemCallbackCalled == 1, "The memProblemCallback was invoked" );
+
+    skip_end();
+}
+
+
+void memProblemCallback( psMemBlock *ptr, const char *file, unsigned int lineno )
+{
+    problemCallbackCalled++;
+}
+
+
+psMemId memAllocCallback( const psMemBlock *ptr )
+{
+    allocCallbackCalled++;
+    return 1;
+}
+
+psMemId memFreeCallback( const psMemBlock *ptr )
+{
+    freeCallbackCalled++;
+    return 1;
+}
+
+psPtr TPOutOfMemoryExhaustedCallback( size_t size )
+{
+    exhaustedCallbackCalled++;
+    return NULL;
+}
+
+void TPmultipleFree( void )
+{
+    psPtr buffer = psAlloc( 1024 );
+    psPtr buffer2 = buffer;
+
+    psFree( buffer );
+    psFree( buffer2 );
+}
+
+psS32 memCheckTypes( void )
+{
+    psArray *negative;
+    negative = psArrayAlloc(2);
+    psMetadata *neg;
+    neg = psMetadataAlloc();
+
+    psArray *array;
+    array = psArrayAlloc(100);
+    int okay = psMemCheckType(PS_DATA_ARRAY,array);
+    if ( ! okay )
+        psFree(array);
+    ok ( okay, "psMemCheckArray in memCheckType");
+    skip_start( ! okay, 28, "psMemCheckArray in memCheckType");
+
+    ok ( psMemCheckType(PS_DATA_ARRAY, neg), "psMemCheckArray in memCheckType");
+    psFree(array);
+
+    psBitSet *bits;
+    bits = psBitSetAlloc(100);
+    okay = psMemCheckType(PS_DATA_BITSET, bits);
+    if ( ! okay )
+        psFree(bits);
+    ok ( okay, "psMemCheckBitSet in memCheckType");
+    skip_start ( !okay, 27, "psMemCheckBitSet in memCheckType");
+
+    ok ( psMemCheckType(PS_DATA_BITSET, negative),
+         "psMemCheckBitSet in memCheckType");
+    psFree(bits);
+
+    psCube *cube;
+    cube = psCubeAlloc();
+    okay = psMemCheckType(PS_DATA_CUBE, cube);
+    if ( ! okay )
+        psFree(cube);
+    ok ( okay, "psMemCheckCube in memCheckType");
+    skip_start ( !okay, 26, "psMemCheckCube in memCheckType");
+    psFree(cube);
+
+    psFits *fits;
+    fits = psFitsOpen("test.fits","w");
+    psImage* img = psImageAlloc(16,16,PS_TYPE_F32);
+    psFitsWriteImage(fits,NULL,img,1,NULL);
+    psFree(img);
+    okay = psMemCheckType(PS_DATA_FITS, fits);
+    if ( ! okay )
+        psFree(fits);
+    ok ( okay, "psMemCheckFits in memCheckType");
+    skip_start ( !okay, 25,"psMemCheckFits in memCheckType");
+    psFitsClose(fits);
+
+    psHash *hash;
+    hash = psHashAlloc(100);
+    okay = psMemCheckType(PS_DATA_HASH, hash);
+    if ( ! okay )
+        psFree(hash);
+    ok ( okay, "psMemCheckHash in memCheckType");
+    skip_start ( !okay, 24, "psMemCheckHash in memCheckType");
+    psFree(hash);
+
+    psHistogram *histogram;
+    histogram = psHistogramAlloc(1.1, 2.2, 2);
+    okay = psMemCheckType(PS_DATA_HISTOGRAM, histogram);
+    if ( ! okay )
+        psFree(histogram);
+    ok ( okay, "psMemCheckHistogram in memCheckType");
+    skip_start ( !okay, 23, "psMemCheckHistogram in memCheckType");
+    psFree(histogram);
+
+    psImage *image;
+    image = psImageAlloc(5, 5, PS_TYPE_F32);
+    okay = psMemCheckType(PS_DATA_IMAGE, image);
+    if ( ! okay )
+        psFree(image);
+    ok ( okay, "psMemCheckImage in memCheckType");
+    skip_start ( !okay, 22, "psMemCheckImage in memCheckType");
+    psFree(image);
+
+    psKernel *kernel;
+    kernel = psKernelAlloc(0, 1, 0, 1);
+    okay = psMemCheckType(PS_DATA_KERNEL, kernel);
+    if ( ! okay )
+        psFree(kernel);
+    ok ( okay, "psMemCheckKernel in memCheckType");
+    skip_start ( !okay, 21, "psMemCheckKernel in memCheckType");
+    psFree(kernel);
+
+    psList *list;
+    list = psListAlloc(NULL);
+    okay = psMemCheckType(PS_DATA_LIST, list);
+    if ( ! okay )
+        psFree(list);
+    ok ( okay, "psMemCheckList in memCheckType");
+    skip_start ( !okay, 20, "psMemCheckList in memCheckType");
+    psFree(list);
+
+    psLookupTable *lookup;
+    char *file = "tableF32.dat";
+    char *format = "\%f \%lf \%d \%ld";
+    lookup = psLookupTableAlloc(file, format, 10);
+    okay = psMemCheckType(PS_DATA_LOOKUPTABLE, lookup);
+    if ( ! okay )
+        psFree(lookup);
+    ok ( okay, "psMemCheckLookupTable in memCheckType");
+    skip_start ( !okay, 19, "psMemCheckLookupTable in memCheckType");
+    psFree(lookup);
+
+    psMetadata *metadata;
+    metadata = psMetadataAlloc();
+    okay = psMemCheckType(PS_DATA_METADATA, metadata);
+    if ( ! okay )
+        psFree(metadata);
+    ok ( okay, "psMemCheckMetadata in memCheckType");
+    skip_start ( !okay, 18, "psMemCheckMetadata in memCheckType");
+    psFree(metadata);
+
+    psMetadataItem *metaItem;
+    metaItem = psMetadataItemAlloc("name", PS_DATA_S32, "COMMENT", 1);
+    okay = psMemCheckType(PS_DATA_METADATAITEM, metaItem);
+    if ( ! okay )
+        psFree(metaItem);
+    ok ( okay, "psMemCheckMetadataItem in memCheckType");
+    skip_start ( !okay, 17, "psMemCheckMetadataItem in memCheckType");
+    psFree(metaItem);
+
+    psMinimization *min;
+    min = psMinimizationAlloc(3, 0.1);
+    okay = psMemCheckType(PS_DATA_MINIMIZATION, min);
+    if ( ! okay )
+        psFree(min);
+    ok ( okay, "psMemCheckMinimization in memCheckType");
+    skip_start ( !okay, 16, "psMemCheckMinimization in memCheckType");
+    psFree(min);
+
+    psPixels *pixels;
+    pixels = psPixelsAlloc(100);
+    okay = psMemCheckType(PS_DATA_PIXELS, pixels);
+    if ( ! okay )
+        psFree(pixels);
+    ok ( okay, "psMemCheckPixels in memCheckType");
+    skip_start ( !okay, 15, "psMemCheckPixels in memCheckType");
+    psFree(pixels);
+
+    psPlane *plane;
+    plane = psPlaneAlloc();
+    okay = psMemCheckType(PS_DATA_PLANE, plane);
+    if ( ! okay )
+        psFree(plane);
+    ok ( okay, "psMemCheckPlane in memCheckType.");
+    skip_start ( !okay, 14, "psMemCheckPlane in memCheckType.");
+    psFree(plane);
+
+    psPlaneDistort *planeDistort;
+    planeDistort = psPlaneDistortAlloc(1, 1, 1, 1);
+    okay =  psMemCheckType(PS_DATA_PLANEDISTORT, planeDistort);
+    if ( ! okay )
+        psFree(planeDistort);
+    ok ( okay, "psMemCheckPlaneDistort in memCheckType.");
+    skip_start ( !okay, 13, "psMemCheckPlaneDistort in memCheckType.");
+    psFree(planeDistort);
+
+    psPlaneTransform *planeTransform;
+    planeTransform = psPlaneTransformAlloc(1, 1);
+    okay = psMemCheckType(PS_DATA_PLANETRANSFORM, planeTransform);
+    if ( ! okay )
+        psFree(planeTransform);
+    ok ( okay, "psMemCheckPlaneTransform in memCheckType");
+    skip_start ( !okay, 12, "psMemCheckPlaneTransform in memCheckType");
+    psFree(planeTransform);
+
+    psPolynomial1D *poly1;
+    poly1 = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 2);
+    okay = psMemCheckType(PS_DATA_POLYNOMIAL1D, poly1);
+    if ( ! okay )
+        psFree(poly1);
+    ok ( okay, "psMemCheckPolynomial1D in memCheckType");
+    skip_start ( !okay, 11, "psMemCheckPolynomial1D in memCheckType");
+    psFree(poly1);
+
+    psPolynomial2D *poly2;
+    poly2 = psPolynomial2DAlloc(PS_POLYNOMIAL_ORD, 2, 1);
+    okay = psMemCheckType(PS_DATA_POLYNOMIAL2D, poly2);
+    if ( ! okay )
+        psFree(poly2);
+    ok ( okay, "psMemCheckPolynomial2D in memCheckType");
+    skip_start ( !okay, 10, "psMemCheckPolynomial2D in memCheckType");
+    psFree(poly2);
+
+    psPolynomial3D *poly3;
+    poly3 = psPolynomial3DAlloc(PS_POLYNOMIAL_ORD, 2, 1, 1);
+    okay = psMemCheckType(PS_DATA_POLYNOMIAL3D, poly3);
+    if ( ! okay )
+        psFree(poly3);
+    ok ( okay, "psMemCheckPolynomial3D in memCheckType");
+    skip_start ( !okay, 9, "psMemCheckPolynomial3D in memCheckType");
+    psFree(poly3);
+
+    psPolynomial4D *poly4;
+    poly4 = psPolynomial4DAlloc(PS_POLYNOMIAL_ORD, 2, 1, 2, 1);
+    okay = psMemCheckType(PS_DATA_POLYNOMIAL4D, poly4);
+    if ( ! okay )
+        psFree(poly4);
+    ok ( okay, "psMemCheckPolynomial4D in memCheckType");
+    skip_start ( !okay, 8, "psMemCheckPolynomial4D in memCheckType");
+    psFree(poly4);
+
+    psProjection *proj;
+    proj = psProjectionAlloc(1, 1, 2.1, 2.1, PS_PROJ_TAN);
+    okay = psMemCheckType(PS_DATA_PROJECTION, proj);
+    if ( ! okay )
+        psFree(proj);
+    ok ( okay, "psMemCheckProjection in memCheckType.");
+    skip_start ( !okay, 7, "psMemCheckProjection in memCheckType.");
+    psFree(proj);
+
+    psScalar *scalar;
+    psC64 c64 = 1.1 + 7I;
+    scalar = psScalarAlloc(c64, PS_TYPE_F64);
+    okay = psMemCheckType(PS_DATA_SCALAR, scalar);
+    if ( ! okay )
+        psFree(scalar);
+    ok ( okay, "psMemCheckScalar in memCheckType");
+    skip_start ( !okay, 6, "psMemCheckScalar in memCheckType");
+    psFree(scalar);
+
+    psSphere *sphere;
+    sphere = psSphereAlloc();
+    okay = psMemCheckType(PS_DATA_SPHERE, sphere);
+    if ( ! okay )
+        psFree(sphere);
+    ok ( okay, "psMemCheckSphere in memCheckType");
+    skip_start ( !okay, 5, "psMemCheckSphere in memCheckType");
+    psFree(sphere);
+
+    psSphereRot *sphereRot;
+    sphereRot = psSphereRotAlloc(0, 0, 20);
+    okay = psMemCheckType(PS_DATA_SPHEREROT, sphereRot);
+    if ( ! okay )
+        psFree(sphereRot);
+    ok( okay, "psMemCheckSphereRot in memCheckType");
+    skip_start( !okay, 4, "psMemCheckSphereRot in memCheckType");
+    psFree(sphereRot);
+
+    psSpline1D *spline;
+    spline = psSpline1DAlloc(2, 1, 0, 2);
+    okay = psMemCheckType(PS_DATA_SPLINE1D, spline);
+    if ( ! okay )
+        psFree(spline);
+    ok( okay, "psMemCheckSpline1D in memCheckType");
+    skip_start( !okay, 3, "psMemCheckSpline1D in memCheckType");
+    psFree(spline);
+
+    psStats *stats;
+    stats = psStatsAlloc(PS_STAT_MAX);
+    okay = psMemCheckType(PS_DATA_STATS, stats);
+    if ( ! okay )
+        psFree(stats);
+    ok( okay, "psMemCheckStats in memCheckType");
+    skip_start( !okay, 2, "psMemCheckStats in memCheckType");
+    psFree(stats);
+
+    psTime *time;
+    time = psTimeAlloc(PS_TIME_UT1);
+    okay = psMemCheckType(PS_DATA_TIME, time);
+    if ( ! okay )
+        psFree(time);
+    ok( okay, "psMemCheckTime in memCheckType");
+    skip_start( !okay, 1, "psMemCheckTime in memCheckType");
+    psFree(time);
+
+    psVector *vector;
+    vector = psVectorAlloc(100, PS_TYPE_F32);
+    okay = psMemCheckType(PS_DATA_VECTOR, vector);
+    ok( okay, "psMemCheckVector in memCheckType");
+    psFree(vector);
+
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+    skip_end();
+
+    psFree(negative);
+    psFree(neg);
+
+    return 0;
+}
