Index: /trunk/psModules/src/config/pmConfig.c
===================================================================
--- /trunk/psModules/src/config/pmConfig.c	(revision 9893)
+++ /trunk/psModules/src/config/pmConfig.c	(revision 9894)
@@ -4,6 +4,6 @@
  *  @author EAM (IfA)
  *
- *  @version $Revision: 1.51 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-10-27 02:22:03 $
+ *  @version $Revision: 1.52 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-11-07 22:30:33 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -65,4 +65,44 @@
 }
 
+// Resolve environment variables within a directory name; returns the resolved directory string.
+// The returned string is likely a new pointer; the old pointer should be freed by psStringSubstitute.
+static psString resolveEnvVar(psString dir // Directory to check for environment variables
+                             )
+{
+    char *envStart;                     // Start of any environment variable
+    while ((envStart = strchr(dir, '$'))) {
+        char *envName = envStart + 1;   // Start of the environment variable name
+        if (envName[0] == '\0') {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Path %s contains a bad environment variable.\n", dir);
+            return NULL;
+        }
+        if (envName[0] == '{') {
+            envName++;
+            if (envName[0] == '\0') {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                        "Path %s contains a bad environment variable.\n", dir);
+                return NULL;
+            }
+        }
+        char *envStop = strpbrk(envStart, "}/"); // End of the environment variable
+        ssize_t nameLength = envStop ? envStop - envName : strlen(envName); // Length of the name
+        psString name = psStringNCopy(envName, nameLength); // The environment variable name
+        char *value = getenv(name);     // Value of the environment variable
+        psFree(name);
+        psString valueSlash = NULL;    // Value with appended slash
+        psStringAppend(&valueSlash, "%s/", value);
+
+        ssize_t envvarLength = envStop ? envStop - envStart : strlen(envStart); // Length, w/o '}'
+        psString envvar = psStringNCopy(envStart, envvarLength + 1);  // Environment variable, with $, {, }
+
+        psTrace("psModules.config", 7, "Replacing %s with %s in directory %s\n", envvar, valueSlash, dir);
+        dir = psStringSubstitute(dir, valueSlash, envvar);
+        psFree(envvar);
+        psFree(valueSlash);
+    }
+
+    return dir;
+}
+
 void pmConfigSet(const char *path)
 {
@@ -71,4 +111,9 @@
     psList *list = psStringSplit(path, ":", false);
     configPath = psListToArray(list);
+    // Resolve environment variables
+    for (long i = 0; i < configPath->n; i++) {
+        configPath->data[i] = resolveEnvVar(configPath->data[i]);
+        psTrace("psModules.config", 4, "Path %ld: %s\n", i, (char*)configPath->data[i]);
+    }
     psFree(list);
 }
@@ -220,4 +265,120 @@
     }
 
+
+
+    // Set options based on the site configuration.
+    {
+        bool mdok = true;   // Status of MD lookup result
+
+        // Initialise the psLib time handling
+        psString timeName = psMetadataLookupStr(&mdok, config->site, "TIME");
+        if (mdok && timeName)
+        {
+            psTrace("psModules.config", 7, "Initialising psTime with file %s\n", timeName);
+            // XXX: PAP had a call to psLibInit is PRODUCTION not set.  Why?
+            psTimeInitialize(timeName);
+        }
+
+
+        // Set logging level
+        int logLevel = psMetadataLookupS32(&mdok, config->site, "LOGLEVEL");
+        if (mdok && logLevel >= 0)
+        {
+            psTrace("psModules.config", 7, "Setting log level to %d\n", logLevel);
+            psLogSetLevel(logLevel);
+        }
+
+
+        // Set logging format
+        psString logFormat = psMetadataLookupStr(&mdok, config->site, "LOGFORMAT");
+        if (mdok && logFormat)
+        {
+            psTrace("psModules.config", 7, "Setting log format to %s\n", logFormat);
+            psLogSetFormat(logFormat);
+        }
+
+        argNum = psArgumentGet(*config->argc, config->argv, "-log");
+        if (argNum > 0)
+        {
+            psArgumentRemove(argNum, config->argc, config->argv);
+            if (argNum >= *config->argc) {
+                psLogMsg(__func__, PS_LOG_WARN, "-log command-line switch provided without the "
+                         "required log destination --- ignored.\n");
+            } else {
+                if (!psLogSetDestination(psMessageDestination(config->argv[argNum]))) {
+                    psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n",
+                             config->argv[argNum]);
+                }
+                psArgumentRemove(argNum, config->argc, config->argv);
+            }
+        } else
+        {
+            // Set logging destination
+            psString logDest = psMetadataLookupStr(&mdok, config->site, "LOGDEST");
+            if (mdok && logDest && strlen(logDest) > 0) {
+                // XXX: Only stdout and stderr are provided for now; this section should be
+                // expanded in the future to do files, and perhaps even sockets.
+                if (!psLogSetDestination(psMessageDestination(logDest))) {
+                    psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n",
+                             config->argv[argNum]);
+                }
+            }
+        }
+
+        // Set trace levels
+        psMetadata *trace = psMetadataLookupMetadata(&mdok, config->site, "TRACE");
+        if (mdok && trace)
+        {
+            psMetadataIterator *traceIter = psMetadataIteratorAlloc(trace, PS_LIST_HEAD, NULL); // Iterator
+            psMetadataItem *traceItem = NULL; // Item from MD iteration
+            while ((traceItem = psMetadataGetAndIncrement(traceIter))) {
+                if (traceItem->type != PS_DATA_S32) {
+                    psLogMsg(__func__, PS_LOG_WARN,
+                             "The level for trace component %s is not of type S32 (%x)\n",
+                             traceItem->name, traceItem->type);
+                    continue;
+                }
+                psTrace("psModules.config", 7, "Setting trace level for %s to %d\n", traceItem->name,
+                        traceItem->data.S32);
+                psTraceSetLevel(traceItem->name, traceItem->data.S32);
+            }
+            psFree(traceIter);
+        }
+
+        // Set trace formats
+        psString traceFormat = psMetadataLookupStr(&mdok, config->site, "TRACEFORMAT");
+        if (mdok && traceFormat)
+        {
+            psTrace("psModules.config", 7, "Setting trace format to %s\n", traceFormat);
+            psTraceSetFormat(traceFormat);
+        }
+
+        // Set trace destinations
+        psString traceDest = psMetadataLookupStr(&mdok, config->site, "TRACEDEST");
+        if (mdok && traceDest && strlen(traceDest) > 0)
+        {
+            psTrace("psModules.config", 7, "Setting trace destination to %s\n", traceDest);
+            // XXX: Only stdout and stderr are provided for now; this section should be
+            // expanded in the future to do files, and perhaps even sockets.
+            if (!psTraceSetDestination(psMessageDestination(traceDest))) {
+                psLogMsg(__func__, PS_LOG_WARN, "Unable to set trace destination to %s\n",
+                         config->argv[argNum]);
+            }
+        }
+
+        // Allow command line options to override defaults for logging.
+        // XXX: Is it appropriate to use the ArgVerbosity function for this?
+        //   A: it removes the options from the command line.
+        //   B: will the pmConfigRead function always be called on initialization.
+        //
+        psS32 saveLogLevel = psLogGetLevel();
+        psArgumentVerbosity(config->argc, config->argv);
+        // XXX: substitute the string for the default log level for "2".
+        if (2 == psLogGetLevel())
+        {
+            psLogSetLevel(saveLogLevel);
+        }
+    }
+
     // define the config-file search path (configPath).  Ensure that
     // it contains the directory where we found the config file in
@@ -278,135 +439,4 @@
         psFree(config);
         return NULL;
-    }
-
-    //
-    // We now have the config, camera, and recipe files parsed and stored in
-    // metadata.  Now, we can look into the site configuration and do
-    // the required stuff.
-    //
-    bool mdok = true;   // Status of MD lookup result
-
-    //
-    // If TIME is specified in the configuration file, then we must initialize
-    // with a call to psTimeInitialize.
-    //
-    psString timeName = psMetadataLookupStr(&mdok, config->site, "TIME");
-    if (mdok && timeName) {
-        psTrace("psModules.config", 7, "Initialising psTime with file %s\n", timeName);
-        // XXX: PAP had a call to psLibInit is PRODUCTION not set.  Why?
-        psTimeInitialize(timeName);
-    }
-
-
-    //
-    // If LOGLEVEL is specified in the configuration file, then we must initialize
-    // with a call to psLogSetLevel().
-    //
-    int logLevel = psMetadataLookupS32(&mdok, config->site, "LOGLEVEL");
-    if (mdok && logLevel >= 0) {
-        psTrace("psModules.config", 7, "Setting log level to %d\n", logLevel);
-        psLogSetLevel(logLevel);
-    }
-
-
-    //
-    // If LOGFORMAT is specified in the configuration file, then we must initialize
-    // with a call to psLogSetFormat().
-    //
-    psString logFormat = psMetadataLookupStr(&mdok, config->site, "LOGFORMAT");
-    if (mdok && logFormat) {
-        psTrace("psModules.config", 7, "Setting log format to %s\n", logFormat);
-        psLogSetFormat(logFormat);
-    }
-
-
-    argNum = psArgumentGet(*config->argc, config->argv, "-log");
-    if (argNum > 0) {
-        psArgumentRemove(argNum, config->argc, config->argv);
-        if (argNum >= *config->argc) {
-            psLogMsg(__func__, PS_LOG_WARN,
-                     "-log command-line switch provided without the required log destination --- ignored.\n");
-        } else {
-            if (!psLogSetDestination(psMessageDestination(config->argv[argNum]))) {
-                psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n",
-                         config->argv[argNum]);
-            }
-            psArgumentRemove(argNum, config->argc, config->argv);
-        }
-    } else {
-        //
-        // If LOGDEST is specified in the configuration file, then we must initialize
-        // with a call to psLogSetDestination().
-        // XXX: This is not spec'ed in the SDRS.
-        //
-        psString logDest = psMetadataLookupStr(&mdok, config->site, "LOGDEST");
-        if (mdok && logDest && strlen(logDest) > 0) {
-            // XXX: Only stdout and stderr are provided for now; this section should be
-            // expanded in the future to do files, and perhaps even sockets.
-            if (!psLogSetDestination(psMessageDestination(logDest))) {
-                psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n",
-                         config->argv[argNum]);
-            }
-        }
-    }
-
-    //
-    // If TRACE is specified in the configuration file, then we must initialize
-    // with a call to psTraceSetLevel().
-    // XXX: This is not spec'ed in the SDRS.
-    //
-    psMetadata *trace = psMetadataLookupMetadata(&mdok, config->site, "TRACE");
-    if (mdok && trace) {
-        psMetadataIterator *traceIter = psMetadataIteratorAlloc(trace, PS_LIST_HEAD, NULL); // Iterator
-        psMetadataItem *traceItem = NULL; // Item from MD iteration
-        while ((traceItem = psMetadataGetAndIncrement(traceIter))) {
-            if (traceItem->type != PS_DATA_S32) {
-                psLogMsg(__func__, PS_LOG_WARN, "The level for trace component %s is not of type S32 (%x)\n",
-                         traceItem->name, traceItem->type);
-                continue;
-            }
-            psTrace("psModules.config", 7, "Setting trace level for %s to %d\n", traceItem->name,
-                    traceItem->data.S32);
-            psTraceSetLevel(traceItem->name, traceItem->data.S32);
-        }
-        psFree(traceIter);
-    }
-    //
-    // If TRACEFORMAT is specified in the configuration file, then we must
-    // initialize with a call to psTraceSetFormat().
-    //
-    psString traceFormat = psMetadataLookupStr(&mdok, config->site, "TRACEFORMAT");
-    if (mdok && traceFormat) {
-        psTrace("psModules.config", 7, "Setting trace format to %s\n", traceFormat);
-        psTraceSetFormat(traceFormat);
-    }
-
-    //
-    // If TRACEDEST is specified in the configuration file, then we must initialize
-    // with a call to psLogSetDestination().
-    // XXX: This is not spec'ed in the SDRS.
-    //
-    psString traceDest = psMetadataLookupStr(&mdok, config->site, "TRACEDEST");
-    if (mdok && traceDest && strlen(traceDest) > 0) {
-        psTrace("psModules.config", 7, "Setting trace destination to %s\n", traceDest);
-        // XXX: Only stdout and stderr are provided for now; this section should be
-        // expanded in the future to do files, and perhaps even sockets.
-        if (!psTraceSetDestination(psMessageDestination(traceDest))) {
-            psLogMsg(__func__, PS_LOG_WARN, "Unable to set trace destination to %s\n",
-                     config->argv[argNum]);
-        }
-    }
-
-    //
-    // Allow command line options to override defaults for logging.
-    // XXX: Is it appropriate to use the ArgVerbosity function for this?
-    //   A: it removes the options from the command line.
-    //   B: will the pmConfigRead function always be called on initialization.
-    //
-    psS32 saveLogLevel = psLogGetLevel();
-    psArgumentVerbosity(config->argc, config->argv);
-    // XXX: substitute the string for the default log level for "2".
-    if (2 == psLogGetLevel()) {
-        psLogSetLevel(saveLogLevel);
     }
 
