Index: trunk/psModules/src/config/pmConfig.c
===================================================================
--- trunk/psModules/src/config/pmConfig.c	(revision 18905)
+++ trunk/psModules/src/config/pmConfig.c	(revision 18908)
@@ -57,5 +57,4 @@
     psFree(config->site);
     psFree(config->system);
-    psFree(config->complete);
     psFree(config->files);
     psFree(config->camera);
@@ -139,5 +138,4 @@
     config->site = NULL;
     config->system = NULL;
-    config->complete = NULL;
     config->camera = NULL;
     config->cameraName = NULL;
@@ -232,7 +230,7 @@
 bool pmConfigFileRead(psMetadata **config, const char *name, const char *description)
 {
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_STRING_NON_EMPTY(name, false);
-    PS_ASSERT_STRING_NON_EMPTY(description, false);
+    assert(config);
+    assert(name);
+    assert(description);
 
     char *realName = NULL;
@@ -313,11 +311,8 @@
 }
 
-// Read a file into a metadataItem, if required
-static bool metadataItemReadFile(psMetadataItem *item, // Item into which to read file
-                                 const char *description // Description, for error messages
-    )
-{
-    assert(item);
-    assert(description);
+bool pmConfigFileIngest(psMetadataItem *item, const char *description)
+{
+    PS_ASSERT_METADATA_ITEM_NON_NULL(item, false);
+    PS_ASSERT_STRING_NON_EMPTY(description, false);
 
     if (item->type == PS_DATA_METADATA) {
@@ -357,5 +352,5 @@
     psMetadataItem *item;               // Item from iteration
     while ((item = psMetadataGetAndIncrement(iter))) {
-        if (!metadataItemReadFile(item, description)) {
+        if (!pmConfigFileIngest(item, description)) {
             psError(PM_ERR_CONFIG, false, "Unable to read %s %s.", description, item->name);
             psFree(iter);
@@ -400,23 +395,6 @@
     psMetadataItem *darkNorm = psMetadataLookup(camera, "DARK.NORM"); // The dark normalisation calibration
     if (darkNorm) {
-        if (darkNorm->type == PS_DATA_STRING) {
-            const char *darkNormName = darkNorm->data.str; // The file name
-            psTrace("config", 2, "Reading %s dark normalisation: %s\n", cameraName, darkNormName);
-            psMetadata *new = NULL;         // New metadata
-            if (!pmConfigFileRead(&new, darkNormName, "Dark normalisation")) {
-                psError(PM_ERR_CONFIG, false, "Trouble reading reading %s dark normalisation %s --- "
-                        "ignored.\n", cameraName, darkNormName);
-                psFree(new);
-                return false;
-            }
-
-            // Muck around under the hood to replace the filename with the metadata;
-            // don't try this at home, kids
-            darkNorm->type = PS_DATA_METADATA;
-            psFree(darkNorm->data.str);
-            darkNorm->data.md = new;
-        } else if (darkNorm->type != PS_DATA_METADATA) {
-            psWarning("DARK.NORM in camera %s is not of type STR or METADATA (%x)",
-                      cameraName, darkNorm->type);
+        if (!pmConfigFileIngest(darkNorm, "dark normalisation")) {
+            psWarning("Unable to ingest DARK.NORM in camera %s", cameraName);
         }
     } else {
@@ -505,21 +483,30 @@
 
     // read the SITE file
-    psString siteFile = psMetadataLookupStr(NULL, config->user, "SITE");
-    if (!pmConfigFileRead(&config->site, siteFile, "site")) {
+    psMetadataItem *siteItem = psMetadataLookup(config->user, "SITE");
+    if (!siteItem) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find SITE in user configuration.");
         psFree(config);
         return NULL;
     }
-
-    // load the SYSTEM file
-    psString systemFile = psMetadataLookupStr(NULL, config->user, "SYSTEM");
-    if (!pmConfigFileRead(&config->system, systemFile, "system")) {
+    if (!pmConfigFileIngest(siteItem, "site configuration")) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read site configuration");
         psFree(config);
         return NULL;
     }
-
-    // interpolate USER, SITE and SYSTEM into the config->complete metadata
-    config->complete = psMetadataCopy (NULL,             config->user);
-    config->complete = psMetadataCopy (config->complete, config->site);
-    config->complete = psMetadataCopy (config->complete, config->system);
+    config->site = psMemIncrRefCounter(siteItem->data.md);
+
+    // load the SYSTEM file
+    psMetadataItem *systemItem = psMetadataLookup(config->user, "SYSTEM");
+    if (!systemItem) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find SYSTEM in user configuration.");
+        psFree(config);
+        return NULL;
+    }
+    if (!pmConfigFileIngest(systemItem, "system configuration")) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to read system configuration");
+        psFree(config);
+        return NULL;
+    }
+    config->system = psMemIncrRefCounter(systemItem->data.md);
 
     // Set LOG and TRACE options based on the user configuration.  These must be set AFTER
@@ -651,7 +638,6 @@
         // Initialise the psLib time handling
         // XXX is this still needed / desired?
-        psString timeName = psMetadataLookupStr(&mdok, config->complete, "TIME");
-        if (mdok && timeName)
-        {
+        psString timeName = psMetadataLookupStr(&mdok, config->system, "TIME");
+        if (mdok && timeName) {
             psTrace("psModules.config", 7, "Initialising psTime with file %s\n", timeName);
             psTimeInit(timeName);
@@ -671,6 +657,6 @@
             char *cameraName = argv[argNum]; // symbolic name of the camera
 
-            // look for the CAMERAS list in config->complete
-            psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS");
+            // look for the CAMERAS list in config->system
+            psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->system, "CAMERAS");
             if (!cameras) {
                 psError(PS_ERR_IO, false, "Unable to find CAMERAS in site configuration.\n");
@@ -718,5 +704,5 @@
                                   "Camera specified on command line", config->camera);
 
-            if (!pmConfigCameraSkycellVersion(config->complete, cameraName)) {
+            if (!pmConfigCameraSkycellVersion(config->system, cameraName)) {
                 psError(PS_ERR_UNKNOWN, false,
                         "Unable to generate skycell versions of specified camera %s.\n",
@@ -726,5 +712,5 @@
             }
 
-            if (!pmConfigCameraMosaickedVersions(config->complete, cameraName)) {
+            if (!pmConfigCameraMosaickedVersions(config->system, cameraName)) {
                 psError(PS_ERR_UNKNOWN, false,
                         "Unable to generate mosaicked versions of specified camera %s.\n",
@@ -739,5 +725,5 @@
     if (!config->camera && readCameraConfig) {
         bool mdok;                      // Status of MD lookup
-        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS"); // List of cameras
+        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->system, "CAMERAS"); // List of cameras
         if (!mdok || !cameras) {
             psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");
@@ -773,10 +759,10 @@
         psFree(iter);
 
-        if (!pmConfigCameraSkycellVersionsAll(config->complete)) {
+        if (!pmConfigCameraSkycellVersionsAll(config->system)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to generate skycell versions of cameras.\n");
             psFree(config);
             return NULL;
         }
-        if (!pmConfigCameraMosaickedVersionsAll(config->complete)) {
+        if (!pmConfigCameraMosaickedVersionsAll(config->system)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to generate mosaicked versions of cameras.\n");
             psFree(config);
@@ -817,5 +803,5 @@
         psArgumentRemove(argNum, argc, argv);
 
-        psMetadata *cameras = psMetadataLookupMetadata(NULL, config->complete, "CAMERAS"); // List of cameras
+        psMetadata *cameras = psMetadataLookupMetadata(NULL, config->system, "CAMERAS"); // List of cameras
         if (!cameras) {
             psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find CAMERAS in the site configuration.\n");
@@ -865,5 +851,5 @@
         } else {
             char *dbserver = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBSERVER", PS_META_REPLACE,
+            if (!psMetadataAddStr(config->user, PS_LIST_TAIL, "DBSERVER", PS_META_REPLACE,
                                   NULL, dbserver)) {
                 psWarning("Failed to overwrite .ipprc DBSERVER value");
@@ -881,5 +867,5 @@
         } else {
             char *dbname = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBNAME", PS_META_REPLACE, NULL, dbname)) {
+            if (!psMetadataAddStr(config->user, PS_LIST_TAIL, "DBNAME", PS_META_REPLACE, NULL, dbname)) {
                 psWarning("Failed to overwrite .ipprc DBNAME value");
             }
@@ -896,5 +882,5 @@
         } else {
             char *dbuser = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBUSER", PS_META_REPLACE, NULL, dbuser)) {
+            if (!psMetadataAddStr(config->user, PS_LIST_TAIL, "DBUSER", PS_META_REPLACE, NULL, dbuser)) {
                 psWarning("Failed to overwrite .ipprc DBUSER value");
             }
@@ -911,5 +897,5 @@
         } else {
             char *dbpassword = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddStr(config->complete, PS_LIST_TAIL, "DBPASSWORD", PS_META_REPLACE,
+            if (!psMetadataAddStr(config->user, PS_LIST_TAIL, "DBPASSWORD", PS_META_REPLACE,
                                   NULL, dbpassword)) {
                 psWarning("Failed to overwrite .ipprc DBPASSWORD value");
@@ -927,5 +913,5 @@
         } else {
             char *dbport = argv[argNum]; // The camera configuration file to read
-            if (!psMetadataAddS32(config->complete, PS_LIST_TAIL, "DBPORT", PS_META_REPLACE, NULL,
+            if (!psMetadataAddS32(config->user, PS_LIST_TAIL, "DBPORT", PS_META_REPLACE, NULL,
                                   (psS32)atoi(dbport))) {
                 psWarning("Failed to overwrite .ipprc DBPORT value");
@@ -1113,5 +1099,5 @@
 
         bool mdok;                      // Metadata lookup status
-        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->complete, "CAMERAS");
+        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->system, "CAMERAS");
         if (! mdok || !cameras) {
             psError(PS_ERR_IO, true, "Unable to find CAMERAS in the configuration.");
@@ -1183,5 +1169,5 @@
     char *testName = NULL;
 
-    psMetadata *cameras = psMetadataLookupMetadata (NULL, config->complete, "CAMERAS");
+    psMetadata *cameras = psMetadataLookupMetadata (NULL, config->system, "CAMERAS");
     psAssert (cameras, "missing CAMERAS in complete metadata");
 
@@ -1263,5 +1249,5 @@
     PS_ASSERT_STRING_NON_EMPTY(cameraName, NULL);
 
-    psMetadata *cameras = psMetadataLookupMetadata(NULL, config->complete, "CAMERAS");
+    psMetadata *cameras = psMetadataLookupMetadata(NULL, config->system, "CAMERAS");
     if (!cameras) {
         psError(PS_ERR_IO, true, "Unable to find CAMERAS in the configuration.");
@@ -1269,19 +1255,11 @@
     }
 
-    char *cameraPath = psMetadataLookupStr(NULL, cameras, cameraName);
-    if (!cameraPath) {
-        psError(PS_ERR_IO, true, "Unable to find requested CAMERA in the configuration.");
+    psMetadataItem *item = psMetadataLookup(cameras, cameraName); // Item with camera of interest
+    if (!pmConfigFileIngest(item, "camera configuration")) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to ingest camera configuration.");
         return NULL;
     }
 
-    psMetadata *camera = NULL; // Camera to test against what we've got:
-
-    if (!pmConfigFileRead(&camera, cameraPath, cameraName)) {
-        psWarning("Trouble reading reading camera configuration %s", cameraName);
-        psFree(camera);
-        return NULL;
-    }
-
-    return camera;
+    return psMemIncrRefCounter(item->data.md);
 }
 
@@ -1289,5 +1267,5 @@
 {
     PS_ASSERT_PTR_NON_NULL(config, NULL);
-    PS_ASSERT_PTR_NON_NULL(config->complete, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->user, NULL);
 
     #ifndef HAVE_PSDB
@@ -1310,9 +1288,9 @@
 
     // XXX leaky strings
-    psString dbServer = psMetadataLookupStr(&mdStatus01, config->complete, "DBSERVER");
-    psString dbUsername = psMetadataLookupStr(&mdStatus02, config->complete, "DBUSER");
-    psString dbPassword = psMetadataLookupStr(&mdStatus03, config->complete, "DBPASSWORD");
-    psString dbName = psMetadataLookupStr(&mdStatus04, config->complete, "DBNAME");
-    psS32 dbPort = psMetadataLookupS32(&mdStatus05, config->complete, "DBPORT");
+    psString dbServer = psMetadataLookupStr(&mdStatus01, config->user, "DBSERVER");
+    psString dbUsername = psMetadataLookupStr(&mdStatus02, config->user, "DBUSER");
+    psString dbPassword = psMetadataLookupStr(&mdStatus03, config->user, "DBPASSWORD");
+    psString dbName = psMetadataLookupStr(&mdStatus04, config->user, "DBNAME");
+    psS32 dbPort = psMetadataLookupS32(&mdStatus05, config->user, "DBPORT");
     if (!mdStatus05) {
         dbPort = 0;
@@ -1527,11 +1505,11 @@
     // replace path://PATH with matched datapath
     if (!strncasecmp(filename, "path://", strlen("path://"))) {
-        PS_ASSERT_METADATA_NON_NULL(config->complete, NULL);
+        PS_ASSERT_METADATA_NON_NULL(config->site, NULL);
 
         psString newName = psStringCopy(filename);
 
         // filename should be of the form: path://PATH/rest/of/file
-        // replace PATH with matching name from config->complete:DATAPATH
-        psMetadata *datapath = psMetadataLookupPtr (NULL, config->complete, "DATAPATH");
+        // replace PATH with matching name from config->site:DATAPATH
+        psMetadata *datapath = psMetadataLookupPtr (NULL, config->site, "DATAPATH");
         if (datapath == NULL) {
             psError(PS_ERR_UNKNOWN, true, "DATAPATH is not defined in config.site");
@@ -1586,5 +1564,5 @@
         // if env isn't set, check the config system
         if (!neb_server) {
-            neb_server = psMetadataLookupStr(&status, config->complete, "NEB_SERVER");
+            neb_server = psMetadataLookupStr(&status, config->site, "NEB_SERVER");
             if (!status) {
                 psError(PM_ERR_CONFIG, true, "failed to lookup config value for NEB_SERVER.");
@@ -1662,5 +1640,5 @@
     }
 
-    if (!metadataItemReadFile(item, "file rules ")) {
+    if (!pmConfigFileIngest(item, "file rules ")) {
         psError(PM_ERR_CONFIG, false, "Unable to read file rules for camera.");
         return NULL;
@@ -1695,5 +1673,5 @@
     }
 
-    if (!metadataItemReadFile(item, "FITS Types")) {
+    if (!pmConfigFileIngest(item, "FITS Types")) {
         psError(PM_ERR_CONFIG, false, "Unable to read fits types for camera.");
         return NULL;
