Index: /trunk/psLib/src/sys/psTrace.c
===================================================================
--- /trunk/psLib/src/sys/psTrace.c	(revision 459)
+++ /trunk/psLib/src/sys/psTrace.c	(revision 459)
@@ -0,0 +1,445 @@
+/*****************************************************************************
+    A simple implementation of a tracing facility for Pan-STARRS
+ 
+    Tracing is controlled on a per "component" basis, where a "component" is
+    a name of the form aaa.bbb.ccc where aaa is the most significant part.
+    For example, the utilities library might be called "utils", the
+    doubly-linked list "utils.dlist", and the code to destroy a list
+    "utils.dlist.del".
+ 
+    NOTES:
+ In the SRD, higher trace levels correspond to a numerically lower
+ trace value in the code.  This is a bit confusing.
+ 
+ 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 should probably rename some variables.
+ *****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+/* #include "psLib.h" */
+#include "psMemory.h"
+#include "psTrace.h"
+
+#define CACHE_NAME_LEN 50
+#define NO_CACHE "\a"                     // no name is cached
+#define UNKNOWN_LEVEL -9999               // we don't know this name's level
+/*****************************************************************************
+    A component is a string of the form aaa.bbb.ccc, and may itself contain
+    further subcomponents.  The Component structure doesn't in fact contain
+    it's full name, but only the last part.
+ *****************************************************************************/
+typedef struct Component
+{
+    const char *name;                     // last part of name of component
+    int level;                            // trace level for this component
+    int dimen;                            // dimension of subcomponents
+    int n;                                // number of subcomponents
+    struct Component **subcomp;           // next level of subcomponents
+}
+Component;
+
+static Component *croot = NULL;           // The root of the trace component
+// tree.
+
+// NOTE: the next tree globals exist
+// for optimization purposes only.
+// Consider removing them.
+static int highest_level = 0;             // Highest level requested.  Defining
+// this variable allows us to reduce
+// component-tree searches that tell
+// us if a message should be printed.
+static char cachedName[CACHE_NAME_LEN + 1] = NO_CACHE;
+// last name looked up
+static int cachedLevel;                   // level of last looked up name
+
+
+/*****************************************************************************
+    componentAlloc(): allocate memory for a new node, and initialize members.
+ *****************************************************************************/
+static Component *componentAlloc(const char *name,
+                                 int level)
+{
+    Component *comp = psAlloc(sizeof(Component));
+    comp->name = psStringCopy(name);
+    comp->level = level;
+    comp->dimen = comp->n = 0;
+    comp->subcomp = NULL;
+
+    return comp;
+}
+
+
+/*****************************************************************************
+    componentFree(): free the current node in the root tree, and all
+ children nodes as well.
+ *****************************************************************************/
+static void componentFree(Component *comp)
+{
+    if (comp == NULL) {
+        return;
+    }
+
+    if (comp->subcomp != NULL) {
+        for (int i = 0; i < comp->n; i++) {
+            componentFree(comp->subcomp[i]);
+        }
+        psFree(comp->subcomp);
+    }
+
+    psFree((char *)comp->name);
+    psFree(comp);
+}
+
+
+/*****************************************************************************
+    initTrace(): simply initialize the component root tree.
+*****************************************************************************/
+static void initTrace(void)
+{
+    if (croot == NULL) {
+        croot = componentAlloc("", UNKNOWN_LEVEL);
+    }
+}
+
+
+/*****************************************************************************
+    Free the trace tree information
+ *****************************************************************************/
+void psTraceReset(void)
+{
+    componentFree(croot);
+    croot = NULL;
+}
+
+
+/*****************************************************************************
+    Add a new component to the tree
+ 
+    NOTE: replace the call to strsep() with a call to strtok(), which conforms
+    to ANSI-C.
+ 
+    NOTE: Should we check in comp == NULL?
+ *****************************************************************************/
+static void componentAdd(Component  *comp,
+                         const char *aname,
+                         int         level)
+{
+    char name[strlen(aname) + 1];      // need a writeable copy
+    strcpy(name, aname);
+    int i = 0;
+    int j = 0;
+    char *firstComponent = NULL;       // first component of name
+    char *rest = name;                 // rest of name
+
+    firstComponent = strsep(&rest, ".");
+    // After this call, firstComponent
+    // points to the first component of the
+    // name, rest points to everything else.
+
+    // Does firstComponent match this level?
+    if (strcmp(comp->name, firstComponent) == 0) {
+        if (rest == NULL) {
+            comp->level = level;
+        } else {
+            componentAdd(comp, rest, level);
+        }
+        return;
+    }
+
+    // Look for a match for firstComponent in this level's subcomps
+    for (i = 0; i < comp->n; i++) {
+        if (strcmp(comp->subcomp[i]->name, firstComponent) == 0) {
+            if (rest == NULL) {
+                comp->subcomp[i]->level = level;
+            } else {
+                componentAdd(comp->subcomp[i], rest, level);
+            }
+
+            return;
+        }
+    }
+
+    // No match; add firstComponent to this level.  Ensure that subcomp is
+    // sorted.
+    if (comp->n >= comp->dimen - 1) {
+        comp->dimen += 5;
+
+        comp->subcomp = psRealloc(comp->subcomp,
+                                  comp->dimen*sizeof(Component *));
+    }
+
+    Component *firstComponent2 = componentAlloc(firstComponent, UNKNOWN_LEVEL);
+    for (i = 0; i < comp->n; i++) {
+        if (strcmp(firstComponent, comp->subcomp[i]->name) > 0) {
+            for (j = comp->n; j > i; j--) {
+                comp->subcomp[j] = comp->subcomp[j - 1];
+            }
+            break;
+        }
+    }
+    comp->subcomp[i] = firstComponent2;
+    comp->n++;
+
+    if (rest == NULL) {
+        firstComponent2->level = level;
+    } else {
+        componentAdd(firstComponent2, rest, level);
+    }
+}
+
+
+/*****************************************************************************
+    setHighestLevel(): traverse the component tree recursively.  For each
+ node encountered, if it's trace level is higher than the global
+ variable highest_level, then set highest_level to that nodes trace
+ level.
+    Input:
+ comp
+    Output:
+ none
+    Returns:
+ NULL
+ *****************************************************************************/
+static void setHighestLevel(const Component *comp)
+{
+    // If this nodes trace level is the max so far, save it in highest_level
+    if (comp->level > highest_level) {
+        highest_level = comp->level;
+    }
+
+    // Do the same for all children nodes.
+    for (int i = 0; i < comp->n; i++) {
+        setHighestLevel(comp->subcomp[i]);
+    }
+}
+
+
+/*****************************************************************************
+    psSetTraceLevel(): add the component named "comp" to the component tree,
+ if it is not already there, and set it's trace level to "level".
+    Input:
+ comp
+ level
+    Output:
+ none
+    Returns:
+ zero
+*****************************************************************************/
+int psSetTraceLevel(const char *comp,   // component of interest
+                    int level)          // desired trace level
+{
+    // If the root component tree does not exist, then initialize it.
+    if (croot == NULL) {
+        initTrace();
+    }
+
+    // invalidate cache
+    strncpy(cachedName, NO_CACHE, CACHE_NAME_LEN);
+
+    // Add the new component to the component tree.
+    componentAdd(croot, comp, level);
+
+    // Save this search info in our depth-one cache.
+    if (level > highest_level) {
+        highest_level = level;
+    } else {
+        highest_level = UNKNOWN_LEVEL;
+        setHighestLevel(croot);
+    }
+
+    // return 0 on success.
+    return 0;
+}
+
+
+/*****************************************************************************
+    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 ???.
+ 
+    Inputs:
+ name: 
+    Outputs:
+ none
+    Returns:
+ The trace level of the "name" component.
+ *****************************************************************************/
+static int doGetTraceLevel(const Component *comp, // the component to search
+                           const char *aname)     // the name to find
+{
+    char name[strlen(aname) + 1];       // need a writeable copy: for strsep()
+    strcpy(name, aname);
+    char *firstComponent;               // first component of name
+    char *rest = name;                  // rest of name
+    int level = -1;
+
+    firstComponent = strsep(&rest, ".");
+
+    // Look for a match for firstComponent in this level's subcomps
+    for (int i = 0; i < comp->n; i++) {
+        if (strcmp(comp->subcomp[i]->name, firstComponent) == 0) {
+            if (rest == NULL) {
+                // Cool.  We have matched the full name.
+                level = comp->subcomp[i]->level;
+                return (level == UNKNOWN_LEVEL) ? comp->level : level;
+            } else {
+                // We have matched this component.  Now we must recurse a
+                // level deeper and match the next component.
+
+                return doGetTraceLevel(comp->subcomp[i], rest);
+            }
+        }
+    }
+
+    // There was no exact match.  We return the level of the deepest
+    // component that has matched.
+    return comp->level;
+}
+
+
+/*****************************************************************************
+    psGetTraceLevel()
+ 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.
+    Input:
+ name
+    Output:
+ none
+    Return:
+ The level of "name" in the root component tree.
+ *****************************************************************************/
+int psGetTraceLevel(const char *name)
+{
+    int level = -1;
+
+    // If the root component tree does not exist, then initialize it.
+    if (croot == NULL) {
+        initTrace();
+    }
+
+    // Before we traverse the component tree, check if we just searched for
+    // this name, and if so, return that level.
+    if (strcmp(name, cachedName) == 0) {
+        return cachedLevel;
+    }
+
+    // Search the component root tree, determine the trace level.
+    level = doGetTraceLevel(croot, name);
+
+    // Save this search info in our depth-one cache.
+    strncpy(cachedName, name, CACHE_NAME_LEN);
+    cachedLevel = level;
+
+    return level;
+}
+
+
+/*****************************************************************************
+    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 Component *comp,
+                               int depth)
+{
+    int i = 0;
+
+    if (comp->name[0] == '\0') {
+        printf("%*s%-*s %d\n", depth, "", 20 - depth,
+               "(root)", (comp->level == UNKNOWN_LEVEL) ? 0 : comp->level);
+    } else {
+        if (comp->level == UNKNOWN_LEVEL) {
+            printf("%*s%-*s %s\n", depth, "", 20 - depth,
+                   comp->name, ".");
+        } else {
+            printf("%*s%-*s %d\n", depth, "", 20 - depth,
+                   comp->name, comp->level);
+        }
+    }
+
+    for (i = 0; i < comp->n; i++) {
+        doPrintTraceLevels(comp->subcomp[i], depth+1);
+    }
+}
+
+
+/*****************************************************************************
+    psPrintTraceLevels()
+ Simply print all the trace levels in the trace level component tree.
+    Inputs:
+ none
+    Outputs:
+ none
+    Returns:
+ null
+*****************************************************************************/
+void psPrintTraceLevels(void)
+{
+    // If the root component tree does not exist, then initialize it.
+    if (croot == NULL) {
+        initTrace();
+    }
+
+    doPrintTraceLevels(croot, 0);
+}
+
+
+/*****************************************************************************
+    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 *comp,        // component being traced
+               int level,               // desired trace level
+               ...)                     // arguments
+{
+    char *fmt = NULL;
+    va_list ap;
+    int i = 0;
+
+    // We first check if the level of this message is less than the highest
+    // level in the tree.  If so, we don't go any further.  If not, we need
+    // to determine the trace level of comp, and then display the message if
+    // the comp's trace level is high enough.
+
+    if ((level <= highest_level) &&
+            (psGetTraceLevel(comp) >= level)) {
+        va_start(ap, level);
+
+        // We indent each message one space foe each level of the message.
+        for (i = 0; i < level; i++) {
+            putchar(' ');
+        }
+
+        // The following functions get the variable list of parameters with
+        // which this function was called, and print them to the standard
+        // output.
+        fmt = va_arg(ap, char *);
+        vprintf(fmt, ap);
+        va_end(ap);
+    }
+    // NOTE: should we free *fmt as well?  Read the man page.
+}
Index: /trunk/psLib/src/sys/psTrace.h
===================================================================
--- /trunk/psLib/src/sys/psTrace.h	(revision 459)
+++ /trunk/psLib/src/sys/psTrace.h	(revision 459)
@@ -0,0 +1,48 @@
+#if !defined(PS_TRACE_H)
+#define PS_TRACE_H 1
+
+/** \file psTrace.h
+ *  \brief basic run-time trace facilities
+ *  \ingroup SystemGroup
+ */
+
+/** Functions **************************************************************/
+/** \addtogroup SystemGroup System Utilities
+ *  \{
+ */
+
+/// Send a trace message
+void p_psTrace(const char *facil,  ///< facilty of interest
+               int myLevel,  ///< desired trace level
+               ...)   ///< trace message arguments
+;
+
+/// Set trace level
+int psSetTraceLevel(const char *facil, ///< facilty of interest
+                    int level)  ///< desired trace level
+;
+
+/// Get the trace level
+int psGetTraceLevel(const char *facil) ///< facilty of interest
+;
+
+/// turn off all tracing, and free trace's allocated memory
+void psTraceReset(void)
+;
+
+/// print trace levels
+void psPrintTraceLevels(void)
+;
+
+/* \} */ // End of SystemGroup Functions
+
+//#define PS_NO_TRACE 1   ///< to turn off all tracing
+
+#if defined(PS_NO_TRACE)
+#  define psTrace(facil, level, ...) /* do nothing */
+#else
+#  define psTrace(facil, level, ...) \
+p_psTrace(facil, level, __VA_ARGS__)
+#endif
+
+#endif
Index: /trunk/psLib/src/sysUtils/psTrace.c
===================================================================
--- /trunk/psLib/src/sysUtils/psTrace.c	(revision 459)
+++ /trunk/psLib/src/sysUtils/psTrace.c	(revision 459)
@@ -0,0 +1,445 @@
+/*****************************************************************************
+    A simple implementation of a tracing facility for Pan-STARRS
+ 
+    Tracing is controlled on a per "component" basis, where a "component" is
+    a name of the form aaa.bbb.ccc where aaa is the most significant part.
+    For example, the utilities library might be called "utils", the
+    doubly-linked list "utils.dlist", and the code to destroy a list
+    "utils.dlist.del".
+ 
+    NOTES:
+ In the SRD, higher trace levels correspond to a numerically lower
+ trace value in the code.  This is a bit confusing.
+ 
+ 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 should probably rename some variables.
+ *****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+/* #include "psLib.h" */
+#include "psMemory.h"
+#include "psTrace.h"
+
+#define CACHE_NAME_LEN 50
+#define NO_CACHE "\a"                     // no name is cached
+#define UNKNOWN_LEVEL -9999               // we don't know this name's level
+/*****************************************************************************
+    A component is a string of the form aaa.bbb.ccc, and may itself contain
+    further subcomponents.  The Component structure doesn't in fact contain
+    it's full name, but only the last part.
+ *****************************************************************************/
+typedef struct Component
+{
+    const char *name;                     // last part of name of component
+    int level;                            // trace level for this component
+    int dimen;                            // dimension of subcomponents
+    int n;                                // number of subcomponents
+    struct Component **subcomp;           // next level of subcomponents
+}
+Component;
+
+static Component *croot = NULL;           // The root of the trace component
+// tree.
+
+// NOTE: the next tree globals exist
+// for optimization purposes only.
+// Consider removing them.
+static int highest_level = 0;             // Highest level requested.  Defining
+// this variable allows us to reduce
+// component-tree searches that tell
+// us if a message should be printed.
+static char cachedName[CACHE_NAME_LEN + 1] = NO_CACHE;
+// last name looked up
+static int cachedLevel;                   // level of last looked up name
+
+
+/*****************************************************************************
+    componentAlloc(): allocate memory for a new node, and initialize members.
+ *****************************************************************************/
+static Component *componentAlloc(const char *name,
+                                 int level)
+{
+    Component *comp = psAlloc(sizeof(Component));
+    comp->name = psStringCopy(name);
+    comp->level = level;
+    comp->dimen = comp->n = 0;
+    comp->subcomp = NULL;
+
+    return comp;
+}
+
+
+/*****************************************************************************
+    componentFree(): free the current node in the root tree, and all
+ children nodes as well.
+ *****************************************************************************/
+static void componentFree(Component *comp)
+{
+    if (comp == NULL) {
+        return;
+    }
+
+    if (comp->subcomp != NULL) {
+        for (int i = 0; i < comp->n; i++) {
+            componentFree(comp->subcomp[i]);
+        }
+        psFree(comp->subcomp);
+    }
+
+    psFree((char *)comp->name);
+    psFree(comp);
+}
+
+
+/*****************************************************************************
+    initTrace(): simply initialize the component root tree.
+*****************************************************************************/
+static void initTrace(void)
+{
+    if (croot == NULL) {
+        croot = componentAlloc("", UNKNOWN_LEVEL);
+    }
+}
+
+
+/*****************************************************************************
+    Free the trace tree information
+ *****************************************************************************/
+void psTraceReset(void)
+{
+    componentFree(croot);
+    croot = NULL;
+}
+
+
+/*****************************************************************************
+    Add a new component to the tree
+ 
+    NOTE: replace the call to strsep() with a call to strtok(), which conforms
+    to ANSI-C.
+ 
+    NOTE: Should we check in comp == NULL?
+ *****************************************************************************/
+static void componentAdd(Component  *comp,
+                         const char *aname,
+                         int         level)
+{
+    char name[strlen(aname) + 1];      // need a writeable copy
+    strcpy(name, aname);
+    int i = 0;
+    int j = 0;
+    char *firstComponent = NULL;       // first component of name
+    char *rest = name;                 // rest of name
+
+    firstComponent = strsep(&rest, ".");
+    // After this call, firstComponent
+    // points to the first component of the
+    // name, rest points to everything else.
+
+    // Does firstComponent match this level?
+    if (strcmp(comp->name, firstComponent) == 0) {
+        if (rest == NULL) {
+            comp->level = level;
+        } else {
+            componentAdd(comp, rest, level);
+        }
+        return;
+    }
+
+    // Look for a match for firstComponent in this level's subcomps
+    for (i = 0; i < comp->n; i++) {
+        if (strcmp(comp->subcomp[i]->name, firstComponent) == 0) {
+            if (rest == NULL) {
+                comp->subcomp[i]->level = level;
+            } else {
+                componentAdd(comp->subcomp[i], rest, level);
+            }
+
+            return;
+        }
+    }
+
+    // No match; add firstComponent to this level.  Ensure that subcomp is
+    // sorted.
+    if (comp->n >= comp->dimen - 1) {
+        comp->dimen += 5;
+
+        comp->subcomp = psRealloc(comp->subcomp,
+                                  comp->dimen*sizeof(Component *));
+    }
+
+    Component *firstComponent2 = componentAlloc(firstComponent, UNKNOWN_LEVEL);
+    for (i = 0; i < comp->n; i++) {
+        if (strcmp(firstComponent, comp->subcomp[i]->name) > 0) {
+            for (j = comp->n; j > i; j--) {
+                comp->subcomp[j] = comp->subcomp[j - 1];
+            }
+            break;
+        }
+    }
+    comp->subcomp[i] = firstComponent2;
+    comp->n++;
+
+    if (rest == NULL) {
+        firstComponent2->level = level;
+    } else {
+        componentAdd(firstComponent2, rest, level);
+    }
+}
+
+
+/*****************************************************************************
+    setHighestLevel(): traverse the component tree recursively.  For each
+ node encountered, if it's trace level is higher than the global
+ variable highest_level, then set highest_level to that nodes trace
+ level.
+    Input:
+ comp
+    Output:
+ none
+    Returns:
+ NULL
+ *****************************************************************************/
+static void setHighestLevel(const Component *comp)
+{
+    // If this nodes trace level is the max so far, save it in highest_level
+    if (comp->level > highest_level) {
+        highest_level = comp->level;
+    }
+
+    // Do the same for all children nodes.
+    for (int i = 0; i < comp->n; i++) {
+        setHighestLevel(comp->subcomp[i]);
+    }
+}
+
+
+/*****************************************************************************
+    psSetTraceLevel(): add the component named "comp" to the component tree,
+ if it is not already there, and set it's trace level to "level".
+    Input:
+ comp
+ level
+    Output:
+ none
+    Returns:
+ zero
+*****************************************************************************/
+int psSetTraceLevel(const char *comp,   // component of interest
+                    int level)          // desired trace level
+{
+    // If the root component tree does not exist, then initialize it.
+    if (croot == NULL) {
+        initTrace();
+    }
+
+    // invalidate cache
+    strncpy(cachedName, NO_CACHE, CACHE_NAME_LEN);
+
+    // Add the new component to the component tree.
+    componentAdd(croot, comp, level);
+
+    // Save this search info in our depth-one cache.
+    if (level > highest_level) {
+        highest_level = level;
+    } else {
+        highest_level = UNKNOWN_LEVEL;
+        setHighestLevel(croot);
+    }
+
+    // return 0 on success.
+    return 0;
+}
+
+
+/*****************************************************************************
+    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 ???.
+ 
+    Inputs:
+ name: 
+    Outputs:
+ none
+    Returns:
+ The trace level of the "name" component.
+ *****************************************************************************/
+static int doGetTraceLevel(const Component *comp, // the component to search
+                           const char *aname)     // the name to find
+{
+    char name[strlen(aname) + 1];       // need a writeable copy: for strsep()
+    strcpy(name, aname);
+    char *firstComponent;               // first component of name
+    char *rest = name;                  // rest of name
+    int level = -1;
+
+    firstComponent = strsep(&rest, ".");
+
+    // Look for a match for firstComponent in this level's subcomps
+    for (int i = 0; i < comp->n; i++) {
+        if (strcmp(comp->subcomp[i]->name, firstComponent) == 0) {
+            if (rest == NULL) {
+                // Cool.  We have matched the full name.
+                level = comp->subcomp[i]->level;
+                return (level == UNKNOWN_LEVEL) ? comp->level : level;
+            } else {
+                // We have matched this component.  Now we must recurse a
+                // level deeper and match the next component.
+
+                return doGetTraceLevel(comp->subcomp[i], rest);
+            }
+        }
+    }
+
+    // There was no exact match.  We return the level of the deepest
+    // component that has matched.
+    return comp->level;
+}
+
+
+/*****************************************************************************
+    psGetTraceLevel()
+ 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.
+    Input:
+ name
+    Output:
+ none
+    Return:
+ The level of "name" in the root component tree.
+ *****************************************************************************/
+int psGetTraceLevel(const char *name)
+{
+    int level = -1;
+
+    // If the root component tree does not exist, then initialize it.
+    if (croot == NULL) {
+        initTrace();
+    }
+
+    // Before we traverse the component tree, check if we just searched for
+    // this name, and if so, return that level.
+    if (strcmp(name, cachedName) == 0) {
+        return cachedLevel;
+    }
+
+    // Search the component root tree, determine the trace level.
+    level = doGetTraceLevel(croot, name);
+
+    // Save this search info in our depth-one cache.
+    strncpy(cachedName, name, CACHE_NAME_LEN);
+    cachedLevel = level;
+
+    return level;
+}
+
+
+/*****************************************************************************
+    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 Component *comp,
+                               int depth)
+{
+    int i = 0;
+
+    if (comp->name[0] == '\0') {
+        printf("%*s%-*s %d\n", depth, "", 20 - depth,
+               "(root)", (comp->level == UNKNOWN_LEVEL) ? 0 : comp->level);
+    } else {
+        if (comp->level == UNKNOWN_LEVEL) {
+            printf("%*s%-*s %s\n", depth, "", 20 - depth,
+                   comp->name, ".");
+        } else {
+            printf("%*s%-*s %d\n", depth, "", 20 - depth,
+                   comp->name, comp->level);
+        }
+    }
+
+    for (i = 0; i < comp->n; i++) {
+        doPrintTraceLevels(comp->subcomp[i], depth+1);
+    }
+}
+
+
+/*****************************************************************************
+    psPrintTraceLevels()
+ Simply print all the trace levels in the trace level component tree.
+    Inputs:
+ none
+    Outputs:
+ none
+    Returns:
+ null
+*****************************************************************************/
+void psPrintTraceLevels(void)
+{
+    // If the root component tree does not exist, then initialize it.
+    if (croot == NULL) {
+        initTrace();
+    }
+
+    doPrintTraceLevels(croot, 0);
+}
+
+
+/*****************************************************************************
+    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 *comp,        // component being traced
+               int level,               // desired trace level
+               ...)                     // arguments
+{
+    char *fmt = NULL;
+    va_list ap;
+    int i = 0;
+
+    // We first check if the level of this message is less than the highest
+    // level in the tree.  If so, we don't go any further.  If not, we need
+    // to determine the trace level of comp, and then display the message if
+    // the comp's trace level is high enough.
+
+    if ((level <= highest_level) &&
+            (psGetTraceLevel(comp) >= level)) {
+        va_start(ap, level);
+
+        // We indent each message one space foe each level of the message.
+        for (i = 0; i < level; i++) {
+            putchar(' ');
+        }
+
+        // The following functions get the variable list of parameters with
+        // which this function was called, and print them to the standard
+        // output.
+        fmt = va_arg(ap, char *);
+        vprintf(fmt, ap);
+        va_end(ap);
+    }
+    // NOTE: should we free *fmt as well?  Read the man page.
+}
Index: /trunk/psLib/src/sysUtils/psTrace.h
===================================================================
--- /trunk/psLib/src/sysUtils/psTrace.h	(revision 459)
+++ /trunk/psLib/src/sysUtils/psTrace.h	(revision 459)
@@ -0,0 +1,48 @@
+#if !defined(PS_TRACE_H)
+#define PS_TRACE_H 1
+
+/** \file psTrace.h
+ *  \brief basic run-time trace facilities
+ *  \ingroup SystemGroup
+ */
+
+/** Functions **************************************************************/
+/** \addtogroup SystemGroup System Utilities
+ *  \{
+ */
+
+/// Send a trace message
+void p_psTrace(const char *facil,  ///< facilty of interest
+               int myLevel,  ///< desired trace level
+               ...)   ///< trace message arguments
+;
+
+/// Set trace level
+int psSetTraceLevel(const char *facil, ///< facilty of interest
+                    int level)  ///< desired trace level
+;
+
+/// Get the trace level
+int psGetTraceLevel(const char *facil) ///< facilty of interest
+;
+
+/// turn off all tracing, and free trace's allocated memory
+void psTraceReset(void)
+;
+
+/// print trace levels
+void psPrintTraceLevels(void)
+;
+
+/* \} */ // End of SystemGroup Functions
+
+//#define PS_NO_TRACE 1   ///< to turn off all tracing
+
+#if defined(PS_NO_TRACE)
+#  define psTrace(facil, level, ...) /* do nothing */
+#else
+#  define psTrace(facil, level, ...) \
+p_psTrace(facil, level, __VA_ARGS__)
+#endif
+
+#endif
