Index: /trunk/psModules/src/camera/pmFPAview.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAview.c	(revision 18904)
+++ /trunk/psModules/src/camera/pmFPAview.c	(revision 18905)
@@ -3,6 +3,6 @@
  *  @author EAM, IfA
  *
- *  @version $Revision: 1.14 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-01-02 20:33:14 $
+ *  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-08-05 02:16:06 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -374,2 +374,48 @@
 }
 
+pmFPAview *pmFPAviewTop(const pmFPA *fpa)
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, NULL);
+
+    pmFPAview *view = pmFPAviewAlloc(0);// View to top
+
+    int numChips = 0;                   // Number of active chips
+    psArray *chips = fpa->chips;        // Chips of interest
+    for (int i = 0; i < chips->n; i++) {
+        pmChip *chip = chips->data[i];  // Chip of interest
+        if (!chip || !chip->file_exists) {
+            continue;
+        }
+        numChips++;
+        view->chip = i;
+
+        int numCells = 0;               // Number of active cells
+        psArray *cells = chip->cells;   // Cells of interest
+        for (int j = 0; j < cells->n; j++) {
+            pmCell *cell = cells->data[j]; // Cell of interest
+            if (!cell || !cell->file_exists) {
+                continue;
+            }
+            numCells++;
+            view->cell = j;
+        }
+
+        if (numCells > 1) {
+            if (numCells != cells->n) {
+                psWarning("More than one, but not all cells are active.");
+            }
+            view->cell = -1;
+        }
+    }
+
+    if (numChips > 1) {
+        if (numChips != chips->n) {
+            psWarning("More than one, but not all chips are active.");
+        }
+        view->chip = -1;
+        view->cell = -1;
+    }
+
+    return view;
+}
+
Index: /trunk/psModules/src/camera/pmFPAview.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAview.h	(revision 18904)
+++ /trunk/psModules/src/camera/pmFPAview.h	(revision 18905)
@@ -4,6 +4,6 @@
  * @author Eugene Magnier, IfA
  *
- * @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
- * @date $Date: 2008-01-02 20:33:14 $
+ * @version $Revision: 1.11 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2008-08-05 02:16:06 $
  * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -124,4 +124,8 @@
 
 
+/// Determine the view suitable for the top level of the provided FPA
+pmFPAview *pmFPAviewTop(const pmFPA *fpa ///< FPA of interest
+    );
+
 /// @}
 #endif
Index: /trunk/psModules/src/config/Makefile.am
===================================================================
--- /trunk/psModules/src/config/Makefile.am	(revision 18904)
+++ /trunk/psModules/src/config/Makefile.am	(revision 18905)
@@ -4,20 +4,22 @@
 libpsmodulesconfig_la_LDFLAGS  = -release $(PACKAGE_VERSION)
 libpsmodulesconfig_la_SOURCES  = \
-    pmConfig.c \
-    pmConfigRecipes.c \
-    pmConfigCamera.c \
-    pmConfigCommand.c \
-    pmConfigMask.c \
-    pmVersion.c \
-    pmErrorCodes.c
+	pmConfig.c \
+	pmConfigRecipes.c \
+	pmConfigCamera.c \
+	pmConfigCommand.c \
+	pmConfigMask.c \
+	pmConfigDump.c \
+	pmVersion.c \
+	pmErrorCodes.c
 
 pkginclude_HEADERS = \
-    pmConfig.h \
-    pmConfigRecipes.h \
-    pmConfigCamera.h \
-    pmConfigCommand.h \
-    pmConfigMask.h \
-    pmVersion.h \
-    pmErrorCodes.h
+	pmConfig.h \
+	pmConfigRecipes.h \
+	pmConfigCamera.h \
+	pmConfigCommand.h \
+	pmConfigMask.h \
+	pmConfigDump.h \
+	pmVersion.h \
+	pmErrorCodes.h
 
 # Error codes.
Index: /trunk/psModules/src/config/pmConfig.c
===================================================================
--- /trunk/psModules/src/config/pmConfig.c	(revision 18904)
+++ /trunk/psModules/src/config/pmConfig.c	(revision 18905)
@@ -68,4 +68,5 @@
     psFree(config->arguments);
     psFree(config->database);
+    psFree(config->program);
 
     // Close log and trace files
@@ -150,4 +151,5 @@
     config->database = NULL;
     config->defaultRecipe = NULL;
+    config->program = NULL;
 
     config->traceFD = DEFAULT_TRACE;
@@ -442,4 +444,5 @@
 
     pmConfig *config = pmConfigAlloc(); // The configuration, containing site, camera and recipes
+    config->program = psStringCopy(argv[0]);
     config->defaultRecipe = defaultRecipe;
 
@@ -1745,24 +1748,2 @@
 }
 
-
-#if 0
-bool pmConfigDump(const pmConfig *config, const pmFPA *source, const char *outroot)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_STRING_NON_EMPTY(outroot, false);
-
-    pmFPAview *view = source ? pmFPAviewTop(source) : pmFPAviewAlloc(0);// View to top level
-    if (!view) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to determine top view for FPA.");
-        return false;
-    }
-
-    psMetadata *dumpRules = psMetadataLookupMetadata(NULL, config->system, "CONFIG.RULES"); // Name rules
-    if (!dumpRules) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to find CONFIG.RULES in system configuration");
-        psFree(view);
-        return false;
-    }
-
-    const char *name =
-#endif
Index: /trunk/psModules/src/config/pmConfig.h
===================================================================
--- /trunk/psModules/src/config/pmConfig.h	(revision 18904)
+++ /trunk/psModules/src/config/pmConfig.h	(revision 18905)
@@ -5,6 +5,6 @@
  *  @author Eugene Magnier, IfA
  *
- *  @version $Revision: 1.38 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-06-10 21:53:09 $
+ *  @version $Revision: 1.39 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-08-05 02:16:06 $
  *  Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -37,7 +37,7 @@
 /// command-line arguments, the pmFPAfiles used, and the database handle.
 typedef struct {
-    psMetadata *user;                 	///< User configuration
-    psMetadata *site;                 	///< Site configuration
-    psMetadata *system;               	///< System configuration
+    psMetadata *user;                   ///< User configuration
+    psMetadata *site;                   ///< Site configuration
+    psMetadata *system;                 ///< System configuration
     psMetadata *complete;               ///< Full merged configuration
     psMetadata *camera;                 ///< Camera specification
@@ -51,4 +51,5 @@
     psDB *database;                     ///< Database handle
     const char *defaultRecipe;          ///< name of top-level recipe for this program
+    psString program;                   ///< Name of program
     // Private members
     pmRecipeSource recipesRead;         ///< Which recipe sources have been read
@@ -108,6 +109,6 @@
 /// configuration.  The accepted format is returned.
 psMetadata *pmConfigCameraFormatFromHeader(psMetadata **camera, // selected camera (or meta-camera)
-					   psString *formatName, // selected format name
-					   pmConfig *config, ///< The configuration
+                                           psString *formatName, // selected format name
+                                           pmConfig *config, ///< The configuration
                                            const psMetadata *header, ///< The FITS header
                                            bool readRecipes ///< optionally read the recipes as well as the format
Index: /trunk/psModules/src/config/pmConfigDump.c
===================================================================
--- /trunk/psModules/src/config/pmConfigDump.c	(revision 18905)
+++ /trunk/psModules/src/config/pmConfigDump.c	(revision 18905)
@@ -0,0 +1,156 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <pslib.h>
+
+#include "pmConfig.h"
+#include "pmFPALevel.h"
+#include "pmFPA.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+
+#include "pmConfigDump.h"
+
+// Cull entries in the metadata, ignoring the ones listed.
+static bool configCull(psMetadata *md,  // Configuration metadata from which to cull
+                       const char *list // List of items NOT to cull
+    )
+{
+    PS_ASSERT_METADATA_NON_NULL(md, false);
+
+    if (!list || strlen(list) == 0) {
+        // Save everything if nothing is listed
+        return true;
+    }
+
+    psArray *keepList = psStringSplitArray(list, " ,;", false); // List of items to keep
+    psHash *keep = psHashAlloc(keepList->n); // Hash with strings to keep
+    for (int i = 0; i < keep->n; i++) {
+        psHashAdd(keep, keepList->data[i], keepList->data[i]);
+    }
+    psFree(keepList);
+
+    psMetadataIterator *iter = psMetadataIteratorAlloc(md, PS_LIST_HEAD, NULL); // Iterator
+    psMetadataItem *item;               // Item from iteration
+    while ((item = psMetadataGetAndIncrement(iter))) {
+        if (!psHashLookup(keep, item->name)) {
+            psMetadataRemoveKey(md, item->name);
+        }
+    }
+    psFree(iter);
+
+    psFree(keep);
+
+    return true;
+}
+
+bool pmConfigRecipesCull(pmConfig *config, const char *save)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    if (!save || strlen(save) == 0) {
+        return true;
+    }
+
+    return configCull(config->recipes, save);
+}
+
+bool pmConfigCamerasCull(pmConfig *config)
+{
+      PS_ASSERT_PTR_NON_NULL(config, false);
+
+      psMetadata *cameras = psMetadataLookupMetadata(NULL, config->complete, "CAMERAS"); // Known cameras
+      if (!cameras) {
+          psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find CAMERAS in the system configuration.\n");
+          return NULL;
+      }
+
+      return configCull(cameras, config->cameraName);
+}
+
+
+bool pmConfigDump(const pmConfig *config, const pmFPA *source, const char *outroot)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_STRING_NON_EMPTY(outroot, false);
+
+    pmFPAview *view = source ? pmFPAviewTop(source) : pmFPAviewAlloc(0);// View to top level
+    if (!view) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to determine top view for FPA.");
+        return false;
+    }
+
+    pmFPALevel level = pmFPAviewLevel(view); // Level for view
+    const char *levelString;    // String for level
+    switch (level) {
+      case PM_FPA_LEVEL_FPA:
+        levelString = "FPA";
+        break;
+      case PM_FPA_LEVEL_CHIP:
+        levelString = "CHIP";
+        break;
+      case PM_FPA_LEVEL_CELL:
+        levelString = "CELL";
+        break;
+      default:
+        psError(PS_ERR_UNKNOWN, false, "Bad FPA level: %x", level);
+        psFree(view);
+        return false;
+    }
+
+    psMetadata *dumpRules = psMetadataLookupMetadata(NULL, config->system, "CONFIG.DUMP"); // Name rules
+    if (!dumpRules) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to find CONFIG.DUMP in system configuration");
+        psFree(view);
+        return false;
+    }
+
+    const char *rule = psMetadataLookupStr(NULL, dumpRules, levelString); // Rule for output file name
+    if (!rule) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to find %s in CONFIG.DUMP in system configuration",
+                levelString);
+        psFree(view);
+        return false;
+    }
+
+    psString ruleCopy = psStringCopy(rule); // Copy of rule, so we can have our way with it
+
+    psStringSubstitute(&ruleCopy, outroot, "{OUTPUT}");
+
+    if (strstr(ruleCopy, "{PROGRAM}")) {
+        // basename() is allowed to muck with the values, so need to copy
+        psString program = psStringCopy(config->program); // Copy of program name
+        const char *progName = basename(program); // Basename of program
+        psStringSubstitute(&ruleCopy, progName, "{PROGRAM}");
+        psFree(program);
+    }
+
+    if (strstr(ruleCopy, "{TIMESTAMP}")) {
+        psTime *time = psTimeGetNow(PS_TIME_UTC); // Current time
+        psString timeString = psTimeToISO(time); // ISO-formatted time
+        psFree(time);
+        psStringSubstitute(&ruleCopy, timeString, "{TIMESTAMP}");
+        psFree(timeString);
+    }
+
+    psString filename = pmFPANameFromRule(ruleCopy, source, view); // Filename for dump
+    psFree(ruleCopy);
+    psFree(view);
+    if (!filename) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to determine dump filename");
+        return false;
+    }
+
+    if (!psMetadataConfigWrite(config->complete, filename)) {
+        psError(PS_ERR_IO, false, "Unable to dump configuration to %s", filename);
+        psFree(filename);
+        return false;
+    }
+
+    psFree(filename);
+    return true;
+}
Index: /trunk/psModules/src/config/pmConfigDump.h
===================================================================
--- /trunk/psModules/src/config/pmConfigDump.h	(revision 18905)
+++ /trunk/psModules/src/config/pmConfigDump.h	(revision 18905)
@@ -0,0 +1,43 @@
+/*  @file pmConfigDump.h
+ *  @brief Configuration dumping function
+ *
+ *  @author Paul Price, IfA
+ *
+ *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-08-05 02:16:06 $
+ *  Copyright 2005-2006 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef PM_CONFIG_DUMP_H
+#define PM_CONFIG_DUMP_H
+
+#include <pmConfig.h>
+#include <pmFPA.h>
+
+/// @addtogroup Config Configuration System
+/// @{
+
+/// Cull recipes from the configuration file, apart from the ones listed
+bool pmConfigRecipesCull(pmConfig *config, ///< Configuration
+                         const char *save ///< List of recipes to save, comma-separated
+    );
+
+/// Cull cameras from the configuration file, apart from the one in use
+bool pmConfigCamerasCull(pmConfig *config ///< Configuration
+    );
+
+/// Dump the configuration to a file
+///
+/// The output file is designated by the CONFIG.DUMP metadata in the system configuration, keyed by the FPA
+/// level of the supplied source.  In addition to the standard concept interpolation, additional
+/// interpolations are defined: "{PROGRAM}" is interpolated to the program name, "{TIMESTAMP}" is interpolated
+/// to the current time (ISO format).
+bool pmConfigDump(const pmConfig *config, ///< Configuration to dump
+                  const pmFPA *source,  ///< Source FPA, defines the level for the file rule
+                  const char *outroot   ///< Output root name
+    );
+
+
+
+/// @}
+#endif
Index: /trunk/psModules/src/psmodules.h
===================================================================
--- /trunk/psModules/src/psmodules.h	(revision 18904)
+++ /trunk/psModules/src/psmodules.h	(revision 18905)
@@ -26,4 +26,5 @@
 #include <pmConfigCommand.h>
 #include <pmConfigMask.h>
+#include <pmConfigDump.h>
 #include <pmVersion.h>
 
