Index: trunk/psModules/src/camera/Makefile.am
===================================================================
--- trunk/psModules/src/camera/Makefile.am	(revision 7555)
+++ trunk/psModules/src/camera/Makefile.am	(revision 7589)
@@ -18,5 +18,8 @@
 	pmFPA_JPEG.c \
 	pmFPAview.c \
-	pmFPAfile.c
+	pmFPAfile.c \
+	pmFPAfileDefine.c \
+	pmFPAfileIO.c \
+	pmFPAfileFitsIO.c
 
 psmoduleincludedir = $(includedir)
@@ -36,5 +39,8 @@
 	pmFPA_JPEG.h \
 	pmFPAview.h \
-	pmFPAfile.h
+	pmFPAfile.h \
+	pmFPAfileDefine.h \
+	pmFPAfileIO.h \
+	pmFPAfileFitsIO.h
 
 CLEANFILES = *~
Index: trunk/psModules/src/camera/pmFPA.c
===================================================================
--- trunk/psModules/src/camera/pmFPA.c	(revision 7555)
+++ trunk/psModules/src/camera/pmFPA.c	(revision 7589)
@@ -12,6 +12,6 @@
 * XXX: Should we implement non-linear cell->chip transforms?
 *
-*  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-06-02 00:55:22 $
+*  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-06-17 01:50:43 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -619,3 +619,49 @@
 }
 
-
+static char *NameNONE = "NONE";
+static char *NameFPA = "FPA";
+static char *NameCHIP = "CHIP";
+static char *NameCELL = "CELL";
+static char *NameREADOUT = "READOUT";
+
+char *pmFPALevelToName(pmFPALevel level)
+{
+
+    switch (level) {
+    case PM_FPA_LEVEL_NONE:
+        return NameNONE;
+    case PM_FPA_LEVEL_FPA:
+        return NameFPA;
+    case PM_FPA_LEVEL_CHIP:
+        return NameCHIP;
+    case PM_FPA_LEVEL_CELL:
+        return NameCELL;
+    case PM_FPA_LEVEL_READOUT:
+        return NameREADOUT;
+    default:
+        psAbort(PS_FILE_LINE, "You can't get here; level = %d", level);
+    }
+    return NULL;
+}
+
+pmFPALevel pmFPALevelFromName(const char *name)
+{
+    pmFPALevel val;
+
+    if (name == NULL) {
+        val = PM_FPA_LEVEL_NONE;
+    } else if (!strcasecmp(name, "FPA"))     {
+        val = PM_FPA_LEVEL_FPA;
+    } else if (!strcasecmp(name, "CHIP"))    {
+        val = PM_FPA_LEVEL_CHIP;
+    } else if (!strcasecmp(name, "CELL"))    {
+        val = PM_FPA_LEVEL_CELL;
+    } else if (!strcasecmp(name, "READOUT")) {
+        val = PM_FPA_LEVEL_READOUT;
+    } else {
+        val = PM_FPA_LEVEL_NONE;
+    }
+
+    return val;
+}
+
Index: trunk/psModules/src/camera/pmFPA.h
===================================================================
--- trunk/psModules/src/camera/pmFPA.h	(revision 7555)
+++ trunk/psModules/src/camera/pmFPA.h	(revision 7589)
@@ -7,6 +7,6 @@
 *  @author GLG, MHPCC
 *
-*  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-06-02 02:16:12 $
+*  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-06-17 01:50:43 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -286,4 +286,6 @@
 
 
+char *pmFPALevelToName(pmFPALevel level);
+pmFPALevel pmFPALevelFromName(const char *name);
 
 #endif // #ifndef PM_FPA_H
Index: trunk/psModules/src/camera/pmFPAConstruct.c
===================================================================
--- trunk/psModules/src/camera/pmFPAConstruct.c	(revision 7555)
+++ trunk/psModules/src/camera/pmFPAConstruct.c	(revision 7589)
@@ -200,44 +200,58 @@
 
 
-// Looks up the particular content based on the header
-static const char *getContent(psMetadata *fileInfo, // The FILE from the camera format configuration
-                              psMetadata *contents, // The CONTENTS from the camera format configuration
-                              psMetadata *header // The (primary) header
+// Looks up the particular content, based on the chip and cell
+static const char *getContent(const psMetadata *fileInfo, // The FILE from the camera format configuration
+                              const psMetadata *contents, // The CONTENTS from the camera format configuration
+                              const pmChip *chip, // The chip of interest
+                              const pmCell *cell // The cell of interest
                              )
 {
     assert(fileInfo);
     assert(contents);
-    assert(header);
+    assert(chip);
 
     bool mdok = true;                   // Status of MD lookup
-    const char *contentHeaders = psMetadataLookupStr(&mdok, fileInfo, "CONTENT"); // Headers for content
-    if (!mdok || !contentHeaders || strlen(contentHeaders) == 0) {
+    char *contentKey = psMetadataLookupStr(&mdok, fileInfo, "CONTENT"); // Key for CONTENTS
+    if (!mdok || !contentKey || strlen(contentKey) == 0) {
         psError(PS_ERR_IO, true, "Unable to find CONTENT in FILE within camera format configuration.\n");
         return NULL;
     }
 
-    psList *keywords = psStringSplit(contentHeaders, " ,;", true); // List of keywords
-    psListIterator *keywordsIter = psListIteratorAlloc(keywords, PS_LIST_HEAD, false); // Iterator
-    psString keyword = NULL;        // Keyword, from iteration
-    psString contentsKey = NULL;    // Key to the CONTENTS menu
-    bool first = true;              // Is it the first value?
-    while ((keyword = psListGetAndIncrement(keywordsIter))) {
-        const char *value = psMetadataLookupStr(&mdok, header, keyword);
-        if (first) {
-            psStringAppend(&contentsKey, "%s", value);
-            first = false;
-        } else {
-            psStringAppend(&contentsKey, "_%s", value);
-        }
-    }
-    psFree(keywordsIter);
-    psFree(keywords);
-    psTrace(__func__, 5, "Looking up %s in the CONTENTS.\n", contentsKey);
-    const char *content = psMetadataLookupStr(&mdok, contents, contentsKey);
+    contentKey = psStringCopy(contentKey); // So that we're not altering something someone else might use...
+
+    // Replace some concept names
+    if (strstr(contentKey, "{CHIP.NAME}")) {
+        if (!chip) {
+            psError(PS_ERR_IO, true, "CONTENT in FILE refers to CHIP.NAME, but no chip was provided.\n");
+            psFree(contentKey);
+            return NULL;
+        }
+        const char *name = psMetadataLookupStr(&mdok, chip->concepts, "CHIP.NAME");
+        if (mdok && name && strlen(name) > 0) {
+            contentKey = psStringSubstitute(contentKey, name, "{CHIP.NAME}");
+        }
+    }
+
+    if (strstr(contentKey, "{CELL.NAME}")) {
+        if (!chip) {
+            psError(PS_ERR_IO, true, "CONTENT in FILE refers to CELL.NAME, but no chip was provided.\n");
+            psFree(contentKey);
+            return NULL;
+        }
+        const char *name = psMetadataLookupStr(&mdok, cell->concepts, "CELL.NAME");
+        if (mdok && name && strlen(name) > 0) {
+            contentKey = psStringSubstitute(contentKey, name, "{CELL.NAME}");
+        }
+    }
+
+    psTrace(__func__, 5, "Looking up %s in the CONTENTS.\n", contentKey);
+    const char *content = psMetadataLookupStr(&mdok, contents, contentKey);
     if (!mdok || !content || strlen(content) == 0) {
-        psError(PS_ERR_IO, true, "Unable to find %s in the CONTENTS.\n", contentsKey);
-        return NULL;
-    }
-    psFree(contentsKey);
+        psFree(contentKey);
+        psError(PS_ERR_IO, true, "Unable to find %s in the CONTENTS.\n", contentKey);
+        return NULL;
+    }
+
+    psFree(contentKey);
 
     return content;
@@ -253,5 +267,5 @@
                            pmFPALevel level, // The level at which to add the HDU
                            const char *contents, // The contents line, consisting of a list of chip:cell
-                           psMetadata *format // Camera format configuration
+                           const psMetadata *format // Camera format configuration
                           )
 {
@@ -364,5 +378,5 @@
 }
 
-static pmFPALevel hduLevel(psMetadata *format // The camera format configuration
+static pmFPALevel hduLevel(const psMetadata *format // The camera format configuration
                           )
 {
@@ -442,125 +456,16 @@
 }
 
-bool pmFPAAddSourceFromView(pmFPA *fpa,   // The FPA
-                            const pmFPAview *phuView, // The view, corresponding to the PHU
-                            psMetadata *format // Format of file
+
+// This is the engine for the pmFPAAddSourceFrom{Header,View} functions
+// It returns a view corresponding to the PHU
+static pmFPAview *addSource(pmFPA *fpa,       // The FPA
+                            const pmFPAview *phuView, // The view corresponding to the PHU, or NULL
+                            const psMetadata *header, // The PHU header, or NULL
+                            const psMetadata *format // Format of file
                            )
 {
-    PS_ASSERT_PTR_NON_NULL(fpa, false);
-    PS_ASSERT_PTR_NON_NULL(phuView, false);
-    PS_ASSERT_PTR_NON_NULL(format, false);
-
-    // Where does the PHU go?
-    bool mdok = true;                   // Status of MD lookup
-    psMetadata *fileInfo = psMetadataLookupMD(&mdok, format, "FILE"); // File information from the format
-    if (!mdok || !fileInfo) {
-        psError(PS_ERR_IO, false, "Unable to find FILE information in the camera format configuration.\n");
-        return false;
-    }
-    const char *phuType = psMetadataLookupStr(&mdok, fileInfo, "PHU"); // What is the PHU?
-    if (!mdok || strlen(phuType) == 0) {
-        psError(PS_ERR_IO, false, "Unable to find PHU in the FILE information of the camera format.\n");
-        return false;
-    }
-
-    // Generate the PHU
-    pmHDU *phdu = pmHDUAlloc("PHU");    // The primary header data unit
-    phdu->format = psMemIncrRefCounter(format);
-
-    // Put in the PHU
-    pmChip *chip = NULL;                // The chip that corresponds to the PHU
-    pmCell *cell = NULL;                // The cell that corresponds to the PHU
-    if (strcasecmp(phuType, "FPA") == 0) {
-        addHDUtoFPA(fpa, phdu);
-        psFree(phdu);
-    } else {
-        psArray *chips = fpa->chips;    // Array of chips
-        if (phuView->chip < 0 || phuView->chip > chips->n) {
-            psError(PS_ERR_IO, true, "PHU specified by the camera format requires specification of a "
-                    "particular chip, which cannot be determined from the view (%d).\n", phuView->chip);
-            psFree(phdu);
-            return false;
-        }
-        chip = chips->data[phuView->chip];
-        if (strcasecmp(phuType, "CHIP") == 0) {
-            addHDUtoChip(chip, phdu);
-            psFree(phdu);
-        } else if (strcasecmp(phuType, "CELL") == 0) {
-            psArray *cells = chip->cells; // Array of cells
-            if (phuView->cell < 0 || phuView->cell > cells->n) {
-                psError(PS_ERR_IO, true, "PHU specified by the camera format requires specification of a "
-                        "particular cell, which cannot be determined from the view (%d).\n", phuView->cell);
-                psFree(phdu);
-                return false;
-            }
-            addHDUtoCell(cell, phdu);
-            psFree(phdu);
-        } else {
-            psError(PS_ERR_IO, true, "PHU in the camera configuration format is not FPA, CHIP or CELL.\n");
-            psFree(phdu);
-            return false;
-        }
-    }
-
-    // Put in the extensions
-    pmFPALevel level = hduLevel(format);// The level for the HDUs to go
-    if (level == PM_FPA_LEVEL_NONE) {
-        // No extensions.  We're done unless PHU == FPA, in which case we need to process the contents
-        if (strcasecmp(phuType, "FPA") == 0) {
-            const char *content = psMetadataLookupStr(&mdok, format, "CONTENTS"); // Contents of the FITS file
-            if (!mdok || !content || strlen(content) == 0) {
-                psError(PS_ERR_IO, true, "Unable to find CONTENTS of type STR in the camera "
-                        "format configuration.\n");
-                return false;
-            }
-            if (processContents(fpa, chip, cell, phdu, level, content, format) < 0) {
-                psError(PS_ERR_IO, false, "Error setting contents.\n");
-                return false;
-            }
-        }
-        return true;
-    }
-    psMetadata *contents = psMetadataLookupMD(&mdok, format, "CONTENTS"); // The contents of the FITS file
-    if (!mdok || !contents) {
-        psError(PS_ERR_IO, false, "Unable to find CONTENTS in the camera format configuration.\n");
-        return false;
-    }
-
-    psMetadataIterator *contentsIter = psMetadataIteratorAlloc(contents, PS_LIST_HEAD, NULL); // Iterator
-    psMetadataItem *contentsItem = NULL;// Item from the contents iteration
-    while ((contentsItem = psMetadataGetAndIncrement(contentsIter))) {
-        if (contentsItem->type != PS_DATA_STRING) {
-            psLogMsg(__func__, PS_LOG_WARN, "Content item %s is not of type STR --- ignored.\n",
-                     contentsItem->name);
-            continue;
-        }
-        pmHDU *hdu = pmHDUAlloc(contentsItem->name); // HDU to add
-        hdu->format = psMemIncrRefCounter(format);
-        const char *content = contentsItem->data.V; // The content data
-        if (processContents(fpa, chip, cell, hdu, level, content, format) < 0) {
-            psError(PS_ERR_IO, false, "Error setting contents for %s", contentsItem->name);
-            psFree(hdu);
-            psFree(contentsIter);
-
-            return false;
-        }
-        psFree(hdu);
-    }
-    psFree(contentsIter);
-
-    return true;
-}
-
-
-
-// Add an input file to the FPA
-pmFPAview *pmFPAAddSourceFromHeader(pmFPA *fpa, // The FPA
-                                    psMetadata *phu, // Primary header of file
-                                    psMetadata *format // Format of file
-                                   )
-{
-    PS_ASSERT_PTR_NON_NULL(fpa, NULL);
-    PS_ASSERT_PTR_NON_NULL(phu, NULL);
-    PS_ASSERT_PTR_NON_NULL(format, NULL);
+    assert(fpa);
+    assert(phuView || header);
+    assert(format);
 
     bool mdok = true;                   // Status from metadata lookups
@@ -571,22 +476,5 @@
     }
 
-    // Check the name of the FPA
-    psString newFPAname = phuNameFromHeader("FPA.NAME", fileInfo, phu); // New name for the FPA
-    if (!newFPAname) {
-        psError(PS_ERR_IO, true, "Unable to determine FPA.NAME");
-        return NULL;
-    }
-
-    // is FPAname already defined, new name must match it
-    // XXX if not, is it an error?
-    const char *currentFPAname = psMetadataLookupStr(&mdok, fpa->concepts, "FPA.NAME"); // Current name
-    if (mdok && currentFPAname && strlen(currentFPAname) > 0 && strcmp(currentFPAname, newFPAname) != 0) {
-        psLogMsg(__func__, PS_LOG_WARN, "FPA.NAME for new source (%s) doesn't match FPA.NAME for current "
-                 "fpa (%s).\n", newFPAname, currentFPAname);
-    }
-    psMetadataAddStr(fpa->concepts, PS_LIST_HEAD, "FPA.NAME", PS_META_REPLACE, "Name of FPA", newFPAname);
-    psFree(newFPAname);                 // Drop reference
-
-    // Where does the PHU go?
+    // At what level does the PHU go?
     const char *phuType = psMetadataLookupStr(&mdok, fileInfo, "PHU"); // What is the PHU?
     if (!mdok || strlen(phuType) == 0) {
@@ -594,14 +482,18 @@
         return NULL;
     }
+
+    // Prepare the PHU to be placed in the camera hierarchy
     pmHDU *phdu = pmHDUAlloc("PHU");    // The primary header data unit
-    phdu->header = psMemIncrRefCounter(phu);
-    phdu->format = psMemIncrRefCounter(format);
-    // Generate the view
-    pmFPAview *view = pmFPAviewAlloc(0); // The FPA view corresponding to the PHU, to be returned
-    view->chip = -1;
-    view->cell = -1;
-    view->readout = -1;
-
-    // And what are the individual extensions?
+    // Casting to psPtr to avoide "warning: passing arg 1 of `p_psMemIncrRefCounter' discards qualifiers from
+    // pointer target type"
+    phdu->header = psMemIncrRefCounter((const psPtr)header);
+    phdu->format = psMemIncrRefCounter((const psPtr)format);
+    pmFPAview *view = pmFPAviewAlloc(0); // View, to be returned
+    if (phuView) {
+        // Copy the view, for the case where we're given a header.
+        *view = *phuView;
+    }
+
+    // And at what level do the individual extensions go?
     const char *extType = psMetadataLookupStr(&mdok, fileInfo, "EXTENSIONS"); // What's in the extns?
     if (!mdok || strlen(extType) == 0) {
@@ -611,8 +503,23 @@
     }
 
-
-    // This is a special case: PHU=FPA and EXTENSIONS=NONE.  The only reason to do this is in the case of
-    // single CCD imagers, where the entire FPA is in the PHU image.  In this case, the CONTENTS is of type
-    // STR (rather than METADATA), and has the usual chip:cell.
+    // Now, there are a few cases:
+
+    // 1. PHU=FPA and EXTENSIONS=NONE.  This is a single CCD imager, where the entire FPA is in the PHU image.
+    // In this case, the CONTENTS is of type STR (rather than METADATA), and has the usual chip:cell:cellType.
+    //
+    // 2. PHU=CHIP or PHU=CELL, and EXTENSIONS=NONE.  This is a single chip or cell from a mosaic camera in
+    // its own file (e.g., Megacam split).  In this case, the CONTENTS is of type METADATA, and consists of a
+    // menu of choices for the contents of the file.  This is because we need to work out which chip and/or
+    // cell it comes from.
+    //
+    // 3. EXTENSIONS=CHIP or EXTENSIONS=CELL.  This is a mosaic camera, with multiple extensions.  In this
+    // case, the CONTENTS is of type METADATA, and consists of a list of contents of the file.
+    //
+    // In all of the above cases, the contents are specified by chip:cell:cellType triples.  It's just how the
+    // contents as a *whole* are collected that changes, and what that collection means.
+    //
+    // We deal with each of these cases in turn.
+
+    // Case 1: PHU=FPA and EXTENSIONS=NONE.  We need to parse the single list of chip:cell:cellType entries.
     if (strcasecmp(phuType, "FPA") == 0 && strcasecmp(extType, "NONE") == 0) {
         const char *contents = psMetadataLookupStr(&mdok, format, "CONTENTS"); // The contents of the file
@@ -628,14 +535,13 @@
             psFree(phdu);
             psFree(view);
-
             return NULL;
         }
-
         psFree(phdu);
+
         return view;
     }
 
-    // In all other cases, the CONTENTS is of type METADATA, and is either a menu if EXTENSIONS=NONE, or
-    // a list of extensions otherwise.
+    // In cases 2 and 3, the CONTENTS is of type METADATA, and is either a menu (if EXTENSIONS=NONE), or a
+    // list of extensions otherwise.
     psMetadata *contents = psMetadataLookupMD(&mdok, format, "CONTENTS"); // The contents of the FITS file
     if (!mdok || !contents) {
@@ -649,18 +555,109 @@
             }
         }
-
+        psFree(phdu);
         psFree(view);
         return NULL;
     }
 
-    // No extensions --- only have the PHU.  In this case, the CONTENTS is a menu, with CONTENT indicating
-    // header keywords that provides a key to the CONTENTS menu.
+    // Case 2: EXTENSIONS=NONE.  We only have the PHU.  The value of CONTENT tells us a header keyword, which
+    // gives us the key to the CONTENTS menu.  Or, if we've got the view specifying the PHU, we can get the
+    // chip/cell directly from that.
     if (strcasecmp(extType, "NONE") == 0) {
-        // We have already dealt with the case PHU=FPA, in a special case, above.
-        const char *content = getContent(fileInfo, contents, phu); // The content: string of chip:cell pairs
-
-        // Need to look up what chip we have.
-        psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, phu);
-        psTrace(__func__, 5, "This is chip %s\n", chipName);
+        pmChip *chip = NULL;        // The chip of interest
+        pmCell *cell = NULL;        // The cell of interest
+        pmFPALevel level = PM_FPA_LEVEL_NONE; // Level for HDU to be added
+
+        if (phuView) {
+            // We can get the chip/cell from the view
+            if (phuView->chip != -1 && phuView->chip < fpa->chips->n) {
+                chip = fpa->chips->data[phuView->chip];
+                level = PM_FPA_LEVEL_CHIP;
+                if (phuView->cell != -1) {
+                    if (phuView->cell < chip->cells->n) {
+                        cell = chip->cells->data[phuView->cell];
+                        level = PM_FPA_LEVEL_CELL;
+                    } else {
+                        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PHU view for cell (%d) does not "
+                                "correspond to camera format.\n", phuView->cell);
+                        psFree(phdu);
+                        return NULL;
+                    }
+                }
+            } else {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PHU view for chip (%d) does not correspond to "
+                        "camera format.\n", phuView->chip);
+                psFree(phdu);
+                return NULL;
+            }
+        } else {
+            // Need to look up what chip we have.
+            psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, header);
+            psTrace(__func__, 5, "This is chip %s\n", chipName);
+            int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
+            if (chipNum == -1) {
+                psError(PS_ERR_IO, true, "Unable to find chip %s in FPA.\n", chipName);
+                psFree(phdu);
+                psFree(view);
+                return NULL;
+            }
+            pmChip *chip = fpa->chips->data[chipNum]; // Chip of interest
+            view->chip = chipNum;
+
+            if (strcasecmp(phuType, "CHIP") == 0) {
+                level = PM_FPA_LEVEL_CHIP;
+            } else if (strcasecmp(phuType, "CELL") == 0) {
+                level = PM_FPA_LEVEL_CELL;
+                // Need to look up what cell we have.
+                psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, header);
+                int cellNum = pmChipFindCell(chip, cellName); // Cell number
+                if (cellNum == -1) {
+                    psError(PS_ERR_IO, true, "Unable to find cell %s in chip %s.\n", cellName, chipName);
+                    psFree(view);
+                    psFree(phdu);
+                    return NULL;
+                }
+                cell = chip->cells->data[cellNum];
+                view->cell = cellNum;
+                psFree(cellName);
+            } else {
+                // We have already dealt with the case PHU=FPA, in a special case above, so if we get here
+                // it's an error.
+                psError(PS_ERR_IO, true, "PHU is not FPA, CHIP or CELL.\n");
+                psFree(phdu);
+                psFree(view);
+                return NULL;
+            }
+            psFree(chipName);
+        }
+
+        const char *content = getContent(fileInfo, contents, chip, cell); // The chip:cell:cellType triples
+        if (!content || strlen(content) == 0) {
+            psError(PS_ERR_IO, false, "Unable to get CONTENTS.\n");
+            psFree(phdu);
+            psFree(view);
+            return NULL;
+        }
+        if (processContents(fpa, chip, cell, phdu, level, content, format) < 0) {
+            psError(PS_ERR_IO, false, "Error setting CONTENTS");
+            psFree(phdu);
+            psFree(view);
+            return NULL;
+        }
+        psFree(phdu);
+
+        return view;
+    }
+
+    // Case 3: EXTENSIONS=CHIP or EXTENSIONS=CELL.  We have extensions that we iterate through.  The CONTENTS
+    // is a list of extensions.
+    pmChip *chip = NULL;                // The chip of interest
+    pmCell *cell = NULL;                // The cell of interest
+
+    // First, put in the PHU
+    if (strcasecmp(phuType, "FPA") == 0) {
+        addHDUtoFPA(fpa, phdu);
+    } else {
+        // Get the chip
+        psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, header); // Name of the chip
         int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
         if (chipNum == -1) {
@@ -669,59 +666,4 @@
             return NULL;
         }
-        pmChip *chip = fpa->chips->data[chipNum]; // Chip of interest
-        view->chip = chipNum;
-
-        pmCell *cell = NULL;            // Cell of interest
-
-        pmFPALevel level = PM_FPA_LEVEL_NONE; // Level for HDU to be added
-        if (strcasecmp(phuType, "CHIP") == 0) {
-            level = PM_FPA_LEVEL_CHIP;
-        } else if (strcasecmp(phuType, "CELL") == 0) {
-            level = PM_FPA_LEVEL_CELL;
-            // Need to look up what cell we have.
-            psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, phu);
-            int cellNum = pmChipFindCell(chip, cellName); // Cell number
-            if (cellNum == -1) {
-                psError(PS_ERR_IO, true, "Unable to find cell %s in chip %s.\n", cellName, chipName);
-                psFree(view);
-                return NULL;
-            }
-            cell = chip->cells->data[cellNum];
-            view->cell = cellNum;
-            psFree(cellName);
-        } else {
-            psError(PS_ERR_IO, true, "PHU is not FPA, CHIP or CELL.\n");
-            psFree(view);
-            return NULL;
-        }
-        psFree(chipName);
-
-        if (processContents(fpa, chip, cell, phdu, level, content, format) < 0) {
-            psError(PS_ERR_IO, false, "Error setting CONTENTS");
-            psFree(phdu);
-            psFree(view);
-            return NULL;
-        }
-        psFree(phdu);
-        return view;
-    }
-
-
-    // From here on, we have extensions that we iterate through.  The CONTENTS is a list of extensions.
-    pmChip *chip = NULL;                // The chip of interest
-    pmCell *cell = NULL;                // The cell of interest
-
-    // First, put in the PHU
-    if (strcasecmp(phuType, "FPA") == 0) {
-        addHDUtoFPA(fpa, phdu);
-    } else {
-        // Get the chip
-        psString chipName = phuNameFromHeader("CHIP.NAME", fileInfo, phu); // Name of the chip
-        int chipNum = pmFPAFindChip(fpa, chipName); // Chip number
-        if (chipNum == -1) {
-            psError(PS_ERR_IO, true, "Unable to find chip %s in FPA.\n", chipName);
-            psFree(view);
-            return NULL;
-        }
         chip = fpa->chips->data[chipNum]; // The specified chip
         view->chip = chipNum;
@@ -730,5 +672,5 @@
             addHDUtoChip(chip, phdu);
         } else if (strcasecmp(phuType, "CELL") == 0) {
-            psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, phu); // Name of the cell
+            psString cellName = phuNameFromHeader("CELL.NAME", fileInfo, header); // Name of the cell
             int cellNum = pmChipFindCell(chip, cellName); // Cell number
             if (cellNum == -1) {
@@ -764,5 +706,7 @@
 
         pmHDU *hdu = pmHDUAlloc(extName); // The extension
-        hdu->format = psMemIncrRefCounter(format);
+        // Casting to avoid "warning: passing arg 1 of `p_psMemIncrRefCounter' discards qualifiers from
+        // pointer target type"
+        hdu->format = psMemIncrRefCounter((const psPtr)format);
 
         if (processContents(fpa, chip, cell, hdu, level, contentsItem->data.V, format) < 0) {
@@ -778,9 +722,62 @@
 
     if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_DEFAULTS, true, NULL)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to read concepts from defaults for FPA %s.  Attempting to "
-                "proceed anyway.\n", currentFPAname);
+        psLogMsg(__func__, PS_LOG_WARN, "Unable to read concepts from defaults for FPA.  Attempting to "
+                 "proceed anyway.\n");
     }
 
     return view;
+
+}
+
+
+bool pmFPAAddSourceFromView(pmFPA *fpa,   // The FPA
+                            const pmFPAview *phuView, // The view, corresponding to the PHU
+                            const psMetadata *format // Format of file
+                           )
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, false);
+    PS_ASSERT_PTR_NON_NULL(phuView, false);
+    PS_ASSERT_PTR_NON_NULL(format, false);
+
+    return addSource(fpa, phuView, NULL, format) ? true : false;
+}
+
+
+
+// Add an input file to the FPA
+pmFPAview *pmFPAAddSourceFromHeader(pmFPA *fpa, // The FPA
+                                    psMetadata *phu, // Primary header of file
+                                    const psMetadata *format // Format of file
+                                   )
+{
+    PS_ASSERT_PTR_NON_NULL(fpa, NULL);
+    PS_ASSERT_PTR_NON_NULL(phu, NULL);
+    PS_ASSERT_PTR_NON_NULL(format, NULL);
+
+    bool mdok = true;                   // Status from metadata lookups
+    psMetadata *fileInfo = psMetadataLookupMD(&mdok, format, "FILE"); // The file information
+    if (!mdok || !fileInfo) {
+        psError(PS_ERR_IO, false, "Unable to find FILE in the camera format configuration.\n");
+        return NULL;
+    }
+
+    // Check the name of the FPA
+    psString newFPAname = phuNameFromHeader("FPA.NAME", fileInfo, phu); // New name for the FPA
+    if (!newFPAname) {
+        psError(PS_ERR_IO, true, "Unable to determine FPA.NAME");
+        return NULL;
+    }
+
+    // is FPAname already defined, new name must match it; otherwise, warn the user that something potentially
+    // bad is happening.
+    const char *currentFPAname = psMetadataLookupStr(&mdok, fpa->concepts, "FPA.NAME"); // Current name
+    if (mdok && currentFPAname && strlen(currentFPAname) > 0 && strcmp(currentFPAname, newFPAname) != 0) {
+        psLogMsg(__func__, PS_LOG_WARN, "FPA.NAME for new source (%s) doesn't match FPA.NAME for current "
+                 "fpa (%s).\n", newFPAname, currentFPAname);
+    }
+    psMetadataAddStr(fpa->concepts, PS_LIST_HEAD, "FPA.NAME", PS_META_REPLACE, "Name of FPA", newFPAname);
+    psFree(newFPAname);                 // Drop reference
+
+    return addSource(fpa, NULL, phu, format);
 }
 
Index: trunk/psModules/src/camera/pmFPAConstruct.h
===================================================================
--- trunk/psModules/src/camera/pmFPAConstruct.h	(revision 7555)
+++ trunk/psModules/src/camera/pmFPAConstruct.h	(revision 7589)
@@ -12,10 +12,10 @@
 bool pmFPAAddSourceFromView(pmFPA *fpa,   // The FPA
                             const pmFPAview *phuView, // The view, corresponding to the PHU
-                            psMetadata *format // Format of file
+                            const psMetadata *format // Format of file
                            );
 
 pmFPAview *pmFPAAddSourceFromHeader(pmFPA *fpa, // The FPA
                                     psMetadata *phu, // Primary header of file
-                                    psMetadata *format // Format of file
+                                    const psMetadata *format // Format of file
                                    );
 
Index: trunk/psModules/src/camera/pmFPAWrite.c
===================================================================
--- trunk/psModules/src/camera/pmFPAWrite.c	(revision 7555)
+++ trunk/psModules/src/camera/pmFPAWrite.c	(revision 7589)
@@ -101,4 +101,5 @@
     if ((!pixels && hdu->phu && !hdu->images) || // Data-less PHU
             (pixels && (hdu->images || (!hdu->images && pmHDUGenerateForCell(cell) && hdu->images)))) { // Data
+        psMetadataPrint (stdout, cell->concepts, 0);
         success &= pmConceptsWriteCell(cell, PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CAMERA |
                                        PM_CONCEPT_SOURCE_DEFAULTS, false, NULL);
@@ -151,4 +152,8 @@
         if (blankSegment || imageSegment) {
             pmConceptSource source = PM_CONCEPT_SOURCE_HEADER | PM_CONCEPT_SOURCE_CAMERA | PM_CONCEPT_SOURCE_DEFAULTS;
+            for (int i = 0; i < chip->cells->n; i++) {
+                pmCell *cell = chip->cells->data[i];
+                psMetadataPrint (stdout, cell->concepts, 0);
+            }
             if (!pmConceptsWriteChip(chip, source, false, true, NULL)) {
                 psError(PS_ERR_IO, false, "Unable to write Concepts for Chip.\n");
Index: trunk/psModules/src/camera/pmFPAfile.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.c	(revision 7555)
+++ trunk/psModules/src/camera/pmFPAfile.c	(revision 7589)
@@ -5,20 +5,20 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
-#include "pmFPAMaskWeight.h"
+// #include "pmFPAMaskWeight.h"
 #include "pmFPAConstruct.h"
 #include "pmFPAview.h"
 #include "pmFPAfile.h"
 #include "pmFPACopy.h"
-#include "pmFPARead.h"
-#include "pmFPAWrite.h"
-#include "pmPeaks.h"
-#include "pmMoments.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmSourceIO.h"
-#include "pmGrowthCurve.h"
-#include "pmPSF.h"
-#include "pmPSF_IO.h"
-#include "pmFPA_JPEG.h"
+// #include "pmFPARead.h"
+// #include "pmFPAWrite.h"
+// #include "pmPeaks.h"
+// #include "pmMoments.h"
+// #include "pmModel.h"
+// #include "pmSource.h"
+// #include "pmSourceIO.h"
+// #include "pmGrowthCurve.h"
+// #include "pmPSF.h"
+// #include "pmPSF_IO.h"
+// #include "pmFPA_JPEG.h"
 
 static void pmFPAfileFree(pmFPAfile *file)
@@ -33,4 +33,5 @@
     psFree (file->names);
 
+    psFree (file->camera);
     psFree (file->format);
     psFree (file->name);
@@ -48,8 +49,4 @@
     psFree (file->extname);
 
-    // these are just views ??
-    // psFree (file->phu);
-    // psFree (file->header);
-
     return;
 }
@@ -68,4 +65,5 @@
     file->names = psMetadataAlloc();
 
+    file->camera = NULL;
     file->format = NULL;
     file->name = NULL;
@@ -86,738 +84,4 @@
 }
 
-static const char *depthEnumToName(pmFPAdepth depth)
-{
-    const char *val = NULL;
-
-    switch (depth) {
-    case PM_FPA_DEPTH_NONE:
-        val = "NONE";
-        break;
-    case PM_FPA_DEPTH_FPA:
-        val = "FPA";
-        break;
-    case PM_FPA_DEPTH_CHIP:
-        val = "CHIP";
-        break;
-    case PM_FPA_DEPTH_CELL:
-        val = "CELL";
-        break;
-    case PM_FPA_DEPTH_READOUT:
-        val = "READOUT";
-        break;
-    default:
-        psAbort(PS_FILE_LINE, "You can't get here; depth = %d", depth);
-    }
-
-    return val;
-}
-
-static pmFPAdepth depthNameToEnum(const char *name)
-{
-    pmFPAdepth val;
-
-    if (name == NULL) {
-        val = PM_FPA_DEPTH_NONE;
-    } else if (!strcasecmp(name, "FPA"))     {
-        val = PM_FPA_DEPTH_FPA;
-    } else if (!strcasecmp(name, "CHIP"))    {
-        val = PM_FPA_DEPTH_CHIP;
-    } else if (!strcasecmp(name, "CELL"))    {
-        val = PM_FPA_DEPTH_CELL;
-    } else if (!strcasecmp(name, "READOUT")) {
-        val = PM_FPA_DEPTH_READOUT;
-    } else {
-        val = PM_FPA_DEPTH_NONE;
-    }
-
-    return val;
-}
-
-// define a pmFPAfile, bind to the optional fpa if supplied
-pmFPAfile *pmFPAfileDefine(psMetadata *files, psMetadata *camera, pmFPA *fpa, char *name)
-{
-    PS_ASSERT_PTR_NON_NULL(files, NULL);
-    PS_ASSERT_PTR_NON_NULL(camera, NULL);
-    PS_ASSERT_PTR_NON_NULL(name, NULL);
-    PS_ASSERT_INT_POSITIVE(strlen(name), NULL);
-
-    bool status;
-    char *type;
-
-    // select the FILERULES from the camera config
-    psMetadata *filerules = psMetadataLookupPtr (&status, camera, "FILERULES");
-    if (filerules == NULL) {
-        psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
-        return NULL;
-    }
-
-    // select the name from the FILERULES
-    // check for alias name (type == STR, name is aliased name)
-    char *realname = psMetadataLookupStr (&status, filerules, name);
-    if (!realname || strlen(realname) == 0) {
-        realname = name;
-    }
-
-    psMetadata *data = psMetadataLookupPtr (&status, filerules, realname);
-    if (data == NULL) {
-        psError(PS_ERR_IO, true, "Can't find file concept %s!", name);
-        return NULL;
-    }
-
-    pmFPAfile *file = pmFPAfileAlloc ();
-
-    // save the name of this pmFPAfile
-    file->name = psStringCopy (name);
-
-    file->filerule = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "FILENAME.RULE"));
-    file->filextra = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "FILENAME.XTRA"));
-    file->extrule  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.RULE"));
-    file->extxtra  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.XTRA"));
-
-    file->fileDepth = depthNameToEnum(psMetadataLookupStr(&status, data, "FILE.DEPTH"));
-    if (file->fileDepth == PM_FPA_DEPTH_NONE) {
-        psError(PS_ERR_IO, true, "FILE.DEPTH is not set for %s\n", name);
-        return NULL;
-    }
-
-    file->dataDepth = depthNameToEnum(psMetadataLookupStr (&status, data, "DATA.DEPTH"));
-    if (file->dataDepth == PM_FPA_DEPTH_NONE) {
-        psError(PS_ERR_IO, true, "DATA.DEPTH is not set for %s\n", name);
-        return NULL;
-    }
-
-    file->type = PM_FPA_FILE_NONE;
-    type = psMetadataLookupStr (&status, data, "FILE.TYPE");
-    if (type != NULL) {
-        if (!strcasecmp (type, "SX"))     {
-            file->type = PM_FPA_FILE_SX;
-        }
-        if (!strcasecmp (type, "OBJ"))     {
-            file->type = PM_FPA_FILE_OBJ;
-        }
-        if (!strcasecmp (type, "CMP"))     {
-            file->type = PM_FPA_FILE_CMP;
-        }
-        if (!strcasecmp (type, "CMF"))     {
-            file->type = PM_FPA_FILE_CMF;
-        }
-        if (!strcasecmp (type, "RAW"))     {
-            file->type = PM_FPA_FILE_RAW;
-        }
-        if (!strcasecmp (type, "IMAGE"))     {
-            file->type = PM_FPA_FILE_IMAGE;
-        }
-        if (!strcasecmp (type, "PSF"))     {
-            file->type = PM_FPA_FILE_PSF;
-        }
-        if (!strcasecmp (type, "JPEG"))     {
-            file->type = PM_FPA_FILE_JPEG;
-        }
-    }
-    if (file->type == PM_FPA_FILE_NONE) {
-        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
-        return NULL;
-    }
-
-    file->mode = PM_FPA_MODE_NONE;
-    type = psMetadataLookupStr (&status, data, "FILE.MODE");
-    if (type != NULL) {
-        if (!strcasecmp (type, "READ"))     {
-            file->mode = PM_FPA_MODE_READ;
-        }
-        if (!strcasecmp (type, "WRITE"))     {
-            file->mode = PM_FPA_MODE_WRITE;
-        }
-    }
-    if (file->mode == PM_FPA_MODE_NONE) {
-        psError(PS_ERR_IO, true, "FILE.MODE is not defined for %s\n", name);
-        return NULL;
-    }
-
-    if (fpa != NULL) {
-        file->fpa = psMemIncrRefCounter(fpa);
-    }
-
-    // for WRITE type of data, the output format needs to be determined
-    // this is only needed if the output file is not identical in structure to the input
-    char *formatName = psMetadataLookupStr (&status, data, "FILE.FORMAT");
-    if (formatName && strcasecmp (formatName, "NONE")) {
-        psMetadata *formats = psMetadataLookupMD(&status, camera, "FORMATS"); // List of formats
-        char *formatFile = psMetadataLookupStr (&status, formats, formatName);
-        if (!formatFile) {
-            psError(PS_ERR_IO, false, "format %s for %s not defined", formatName, name);
-            psFree (file);
-            return NULL;
-        }
-        readConfig (&file->format, formatFile, formatName);
-    }
-
-    psMetadataAddPtr (files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file);
-
-    // we free this copy of file, but 'files' still has a copy
-    psFree (file);
-
-    // the returned value is a view into the version on 'files'
-    return (file);
-}
-
-/*
-pmFPAfile *pmFPAfileConstruct (psMetadata *files, psMetadata *format, psMetadata *camera, char *name)
-{
-    pmFPA *fpa = pmFPAConstruct (camera);
-    pmFPAfile *file = pmFPAfileDefine (files, format, fpa, name);
-    psFree (fpa);
-    if (!file) {
-        psErrorStackPrint(stderr, "file %s not defined\n", name);
-        return NULL;
-    }
-    return file;
-}
-*/
-
-// open file (if not already opened)
-bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    bool status;
-    char *extra;
-    char *mode = NULL;
-    char *readMode = "r";
-    char *writeMode = "w";
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("pmFPAfile", 6, "skip open for %s, files is inactive", file->name);
-        return true;
-    }
-
-    if (file->state == PM_FPA_STATE_OPEN) {
-        return true;
-    }
-
-    if (file->mode == PM_FPA_MODE_NONE) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_NONE");
-        return false;
-    }
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
-    }
-    if (file->mode == PM_FPA_MODE_READ) {
-        mode = readMode;
-    }
-    if (file->mode == PM_FPA_MODE_WRITE) {
-        mode = writeMode;
-    }
-
-    // determine the file name
-    // free a name allocated earlier
-    psFree (file->filename);
-    file->filename = pmFPAfileNameFromRule (file->filerule, file, view);
-    if (file->filename == NULL) {
-        psError(PS_ERR_IO, true, "Filename is NULL");
-        return false;
-    }
-
-    // indirect filenames
-    if (!strcasecmp (file->filename, "@FILES")) {
-        psFree (file->filename);
-        extra = pmFPAfileNameFromRule (file->filextra, file, view);
-        file->filename = psMetadataLookupStr (&status, file->names, extra);
-        psFree (extra);
-        if (file->filename == NULL) {
-            psError(PS_ERR_IO, true, "filename lookup error (@FILES) for %s : %s\n", file->filextra, extra);
-            return false;
-        }
-        // psMetadataLookupStr just returns a view, file->filename must be protected
-        psMemIncrRefCounter (file->filename);
-    }
-    if (!strcasecmp (file->filename, "@DETDB")) {
-        psFree (file->filename);
-        extra = pmFPAfileNameFromRule (file->filextra, file, view);
-        // file->filename = pmDetrendSelect (extra);
-        psFree (extra);
-        if (file->filename == NULL) {
-            psError(PS_ERR_IO, true, "filename lookup error (@DETBD) for %s : %s\n", file->filextra, extra);
-            return false;
-        }
-        psMemIncrRefCounter (file->filename);
-    }
-
-    switch (file->type) {
-        // open the FITS types:
-    case PM_FPA_FILE_IMAGE:
-    case PM_FPA_FILE_CMF:
-        psTrace ("pmFPAfile", 5, "opening %s (type: %d)\n", file->filename, file->type);
-        file->fits = psFitsOpen (file->filename, mode);
-        if (file->fits == NULL) {
-            psError(PS_ERR_IO, false, "error opening file %s\n", file->filename);
-            return false;
-        }
-        file->state = PM_FPA_STATE_OPEN;
-        break;
-
-        // defer opening TEXT types:
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-        psTrace ("pmFPAfile", 5, "defer opening %s\n", file->filename);
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "type mismatch for %s : %d\n", file->filename, file->type);
-        return false;
-    }
-    return true;
-}
-
-bool pmFPAfileRead(pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("pmFPAfile", 6, "skip read for %s, files is inactive", file->name);
-        return true;
-    }
-
-    if (file->mode != PM_FPA_MODE_READ) {
-        psTrace("pmFPAfile", 6, "skip read for %s, mode is not READ", file->name);
-        return true;
-    }
-
-    // get the current depth
-    pmFPAdepth depth = pmFPAviewDepth (view);
-
-    // do we need to open this file?
-    if (depth == file->fileDepth) {
-        if (!pmFPAfileOpen (file, view)) {
-            psError(PS_ERR_IO, false, "failed to open file %s", file->name);
-            return false;
-        }
-    }
-
-    // do we need to read this file?
-    if (depth != file->dataDepth) {
-        psTrace("pmFPAfile", 6, "skip reading of %s at this depth %s: dataDepth is %s",
-                file->name, depthEnumToName(depth), depthEnumToName(file->dataDepth));
-        return true;
-    }
-
-    switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-        if (pmFPAviewReadFitsImage (view, file)) {
-            psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
-            return false;
-        }
-        break;
-
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-        pmFPAviewReadObjects (view, file);
-        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-
-    case PM_FPA_FILE_PSF:
-        pmFPAviewReadPSFmodel (view, file);
-        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-
-    case PM_FPA_FILE_JPEG:
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d", file->type);
-        return false;
-    }
-    return true;
-}
-
-bool pmFPAfileFreeData(pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("pmFPAfile", 6, "skip free for %s, files is inactive", file->name);
-        return true;
-    }
-
-    // get the current depth
-    pmFPAdepth depth = pmFPAviewDepth (view);
-
-    // do we need to read this file?
-    if (depth != file->dataDepth) {
-        psTrace("pmFPAfile", 6, "skip free of %s at this depth %s: dataDepth is %s",
-                file->name, depthEnumToName(depth), depthEnumToName(file->dataDepth));
-        return true;
-    }
-
-    switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-        if (pmFPAviewFreeFitsImage (view, file)) {
-            psTrace ("pmFPAfile", 5, "freed %s (type: %d)\n", file->filename, file->type);
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
-            return false;
-        }
-        break;
-
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-        // pmFPAviewFreeObjects (view, file);
-        psTrace ("pmFPAfile", 5, "NOT freeing %s (type: %d)\n", file->filename, file->type);
-        break;
-
-        // XXX not certain what I need to free here
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d", file->type);
-        return false;
-    }
-    return true;
-}
-
-bool pmFPAfileWrite(pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("pmFPAfile", 6, "skip write for %s, files is inactive", file->name);
-        return true;
-    }
-
-    if (file->mode != PM_FPA_MODE_WRITE) {
-        psTrace("pmFPAfile", 6, "skip write for %s, mode is not WRITE", file->name);
-        return true;
-    }
-
-    // get the current depth
-    pmFPAdepth depth = pmFPAviewDepth (view);
-
-    // do we need to write this file?
-    if (depth != file->dataDepth) {
-        psTrace("pmFPAfile", 6, "skip writing of %s at this depth %s: dataDepth is %s",
-                file->name, depthEnumToName(depth), depthEnumToName(file->dataDepth));
-        return true;
-    }
-
-    // do we need to open this file?
-    if (depth >= file->fileDepth) {
-        if (!pmFPAfileOpen (file, view)) {
-            psError(PS_ERR_IO, false, "failed to open %s", file->filename);
-            return false;
-        }
-    }
-
-    switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-        pmFPAviewWriteFitsImage (view, file);
-        psTrace ("pmFPAfile", 5, "wrote image %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-        psTrace ("pmFPAfile", 5, "writing object %s (fpa: %p)\n", file->filename, file->fpa);
-        if (!pmFPAviewWriteObjects (view, file)) {
-            psError(PS_ERR_IO, false, "Failed to write object %s", file->filename);
-            return false;
-        }
-
-        break;
-
-    case PM_FPA_FILE_PSF:
-        pmFPAviewWritePSFmodel (view, file);
-        psTrace ("pmFPAfile", 5, "wrote PSF %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-
-    case PM_FPA_FILE_JPEG:
-        pmFPAviewWriteJPEG (view, file);
-        psTrace ("pmFPAfile", 5, "wrote PSF %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-
-    default:
-        fprintf (stderr, "warning: type mismatch\n");
-        return false;
-    }
-    return true;
-}
-
-// create the data elements (headers, images) appropriate for this view
-bool pmFPAfileCreate (pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    // these are not error conditions; these are state tests
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("pmFPAfile", 6, "skip create for inactive file %s", file->name);
-        return true;
-    }
-    if (file->mode != PM_FPA_MODE_WRITE) {
-        psTrace("pmFPAfile", 6, "skip create for non-write file %s", file->name);
-        return true;
-    }
-
-    // get the current depth
-    pmFPAdepth depth = pmFPAviewDepth (view);
-
-    // don't create the file if the src FPA is not defined
-    if (file->src == NULL) {
-        psTrace("pmFPAfile", 6, "skip create for FPA without src FPA for %s", file->name);
-        return true;
-    }
-
-    // do we need to write this file?
-    if (depth != file->dataDepth) {
-        psTrace("pmFPAfile", 6, "skip creation of %s at this depth %s: dataDepth is %s",
-                file->name, depthEnumToName(depth), depthEnumToName(file->dataDepth));
-        return true;
-    }
-
-    switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-        /* create a PHU for thie file, if it does not exist */
-        pmFPAfileCopyStructureView (file->fpa, file->src, file->format, file->xBin, file->yBin, view);
-        psTrace ("pmFPAfile", 5, "created fpa data elements for %s (fpa: %p)\n", file->name, file->fpa);
-        break;
-
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "Unsupported type for %s: %d", file->name, file->type);
-        return false;
-    }
-    return true;
-}
-
-bool pmFPAfileClose (pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("pmFPAfile", 6, "skip close for %s, files is inactive", file->name);
-        return true;
-    }
-    if (file->state == PM_FPA_STATE_CLOSED) {
-        return true;
-    }
-
-    // is current depth == open depth?
-    pmFPAdepth depth = pmFPAviewDepth (view);
-    if (file->fileDepth != depth) {
-        psTrace("pmFPAfile", 6, "skip closing of %s at this depth %s: dataDepth is %s",
-                file->name, depthEnumToName(depth), depthEnumToName(file->dataDepth));
-        return true;
-    }
-
-    // check if we are actually open
-    switch (file->type) {
-        // check the FITS types
-    case PM_FPA_FILE_IMAGE:
-    case PM_FPA_FILE_CMF:
-        psFitsClose (file->fits);
-        psTrace ("pmFPAfile", 5, "closing %s (type: %d)\n", file->filename, file->type);
-        file->fits = NULL;
-        file->phu = NULL;
-        file->header = NULL;
-        file->state = PM_FPA_STATE_CLOSED;
-        break;
-
-        // ignore the TEXT types
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "type mismatch: %d", file->type);
-        return false;
-    }
-    return true;
-}
-
-// set the state of the specified pmFPAfile to active (state == true) or inactive
-// if name is NULL, set the state for all pmFPAfiles
-bool pmFPAfileActivate (psMetadata *files, bool state, char *name)
-{
-    PS_ASSERT_PTR_NON_NULL(files, false);
-
-    if (!name) {
-        psMetadataItem *item = NULL;
-        psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
-        while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-            pmFPAfile *file = item->data.V;
-            if (state) {
-                file->state &= NOT_U8(PM_FPA_STATE_INACTIVE);
-            } else {
-                file->state |= PM_FPA_STATE_INACTIVE;
-            }
-        }
-        psFree (iter);
-        return true;
-    }
-
-    bool status = false;
-    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
-    if (!status) {
-        psTrace("pmFPAfile", 6, "%s is not a defined IO file", name);
-        return false;
-    }
-    if (!file) {
-        psError(PS_ERR_IO, true, "file %s is NULL", name);
-        return false;
-    }
-    if (state) {
-        file->state &= NOT_U8(PM_FPA_STATE_INACTIVE);
-    } else {
-        file->state |= PM_FPA_STATE_INACTIVE;
-    }
-    return true;
-}
-
-// attempt create, read, write, close, or free pmFPAfiles available in files
-// files are automatically opened before they are read
-bool pmFPAfileIOChecks (psMetadata *files, const pmFPAview *view, pmFPAfilePlace place)
-{
-    PS_ASSERT_PTR_NON_NULL(files, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    bool status = true;
-
-    // attempt to perform all create, read, write
-    psMetadataItem *item = NULL;
-    psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
-    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-        pmFPAfile *file = item->data.V;
-
-        switch (place) {
-        case PM_FPA_BEFORE:
-            if (!pmFPAfileRead (file, view)) {
-                psError(PS_ERR_IO, false, "failed READ in FPA_BEFORE block for %s", file->name);
-                status = false;
-            }
-            if (!pmFPAfileCreate(file, view)) {
-                psError(PS_ERR_IO, false, "failed CREATE in FPA_BEFORE block for %s", file->name);
-                status = false;
-            }
-            break;
-        case PM_FPA_AFTER:
-            if (!pmFPAfileWrite (file, view)) {
-                psError(PS_ERR_IO, false, "failed WRITE in FPA_AFTER block for %s", file->name);
-                status = false;
-            }
-            if (!pmFPAfileClose(file, view)) {
-                psError(PS_ERR_IO, false, "failed CLOSE in FPA_AFTER block for %s", file->name);
-                status = false;
-            }
-            break;
-        default:
-            psAbort(PS_FILE_LINE, "You can't get here");
-        }
-    }
-
-    // attempt to free data that is no longer needed
-    psMetadataIteratorSet (iter, PS_LIST_HEAD);
-    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-        pmFPAfile *file = item->data.V;
-
-        switch (place) {
-        case PM_FPA_BEFORE:
-            break;
-        case PM_FPA_AFTER:
-            if (!pmFPAfileFreeData(file, view)) {
-                psError(PS_ERR_IO, false, "failed FREE in FPA_AFTER block for %s", file->name);
-                status = false;
-            }
-            break;
-        default:
-            psAbort(PS_FILE_LINE, "You can't get here");
-        }
-    }
-    psFree (iter);
-    return status;
-}
-
-// create a file with the given name, assign it type "INTERNAL", and supply it with an image
-// of the requested dimensions. (image only, mask and weight are ignored)
-pmReadout *pmFPAfileCreateInternal (psMetadata *files, char *name, int Nx, int Ny, int type)
-{
-    PS_ASSERT_PTR_NON_NULL(files, false);
-    PS_ASSERT_PTR_NON_NULL(name, false);
-    PS_ASSERT_INT_POSITIVE(strlen(name), false);
-
-    pmReadout *readout = pmReadoutAlloc(NULL);
-    readout->image = psImageAlloc(Nx, Ny, type);
-
-    // I want an image from the
-    pmFPAfile *file = pmFPAfileAlloc();
-    file->mode = PM_FPA_MODE_INTERNAL;
-    file->name = psStringCopy (name);
-
-    file->readout = readout;
-    psMetadataAddPtr(files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file);
-    psFree(file);
-    // we free this copy of file, but 'files' still has a copy
-
-    return readout;
-}
-
-bool pmFPAfileDropInternal(psMetadata *files, char *name)
-{
-    PS_ASSERT_PTR_NON_NULL(files, false);
-    PS_ASSERT_PTR_NON_NULL(name, false);
-    PS_ASSERT_INT_POSITIVE(strlen(name), false);
-
-    bool status = false;
-
-    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
-    if (!status) {
-        psTrace("pmFPAfile", 6, "Internal File %s not in file list", name);
-        return true;
-    }
-    if (file == NULL) {
-        psError(PS_ERR_IO, true, "file %s is NULL", name);
-        return false;
-    }
-    if (file->mode != PM_FPA_MODE_INTERNAL) {
-        psTrace("pmFPAfile", 6, "FPA File %s not Internal, not dropping", name);
-        return true;
-    }
-
-    psMetadataRemoveKey (files, name);
-    return true;
-}
-
 // select the readout from the named pmFPAfile; if the named file does not exist,
 pmReadout *pmFPAfileThisReadout (psMetadata *files, const pmFPAview *view, const char *name)
@@ -844,529 +108,5 @@
 }
 
-// given an already-opened fits file, read the components corresponding
-// to the specified view
-bool pmFPAviewReadFitsImage (const pmFPAview *view, pmFPAfile *file)
-{
-    PS_ASSERT_PTR_NON_NULL(view, false);
-    PS_ASSERT_PTR_NON_NULL(file, false);
-
-    bool status;
-    pmFPA *fpa = file->fpa;
-    psFits *fits = file->fits;
-
-    if (view->chip == -1) {
-        status = pmFPARead (fpa, fits, NULL);
-        return status;
-    }
-
-    if (view->chip >= fpa->chips->n) {
-        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
-        return false;
-    }
-    pmChip *chip = fpa->chips->data[view->chip];
-
-    if (view->cell == -1) {
-        status = pmChipRead (chip, fits, NULL);
-        return status;
-    }
-
-    if (view->cell >= chip->cells->n) {
-        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
-        return false;
-    }
-    pmCell *cell = chip->cells->data[view->cell];
-
-    if (view->readout == -1) {
-        status = pmCellRead (cell, fits, NULL);
-        return status;
-    }
-    psError(PS_ERR_UNKNOWN, true, "Returning false");
-    return false;
-
-    // XXX pmReadoutRead, pmReadoutReadSegement disabled for now
-    #if 0
-
-    if (view->readout >= cell->readouts->n) {
-        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
-                view->readout, cell->readouts->n);
-        return false;
-    }
-    pmReadout *readout = cell->readouts->data[view->readout];
-
-    if (view->nRows == 0) {
-        pmReadoutRead (readout, fits, NULL);
-    } else {
-        pmReadoutReadSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
-    }
-    return true;
-    #endif
-}
-
-// given an already-opened fits file, read the components corresponding
-// to the specified view
-bool pmFPAviewFreeFitsImage (const pmFPAview *view, pmFPAfile *file)
-{
-    PS_ASSERT_PTR_NON_NULL(view, false);
-    PS_ASSERT_PTR_NON_NULL(file, false);
-
-    pmFPA *fpa = file->fpa;
-
-    if (view->chip == -1) {
-        psTrace ("pmFPAfile", 5, "freeing fpa for %s\n", file->filename);
-        psFree (fpa);
-        file->fpa = NULL;
-        return true;
-    }
-
-    if (view->chip >= fpa->chips->n) {
-        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
-        return false;
-    }
-    pmChip *chip = fpa->chips->data[view->chip];
-
-    if (view->cell == -1) {
-        psTrace ("pmFPAfile", 5, "freeing chip %d for %s\n", view->chip, file->filename);
-        psFree (chip);
-        fpa->chips->data[view->chip] = NULL;
-        return true;
-    }
-
-    if (view->cell >= chip->cells->n) {
-        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
-        return false;
-    }
-    pmCell *cell = chip->cells->data[view->cell];
-
-    if (view->readout == -1) {
-        psTrace ("pmFPAfile", 5, "freeing cell %d for %s\n", view->cell, file->filename);
-        psFree (cell);
-        chip->cells->data[view->cell] = NULL;
-        return true;
-    }
-    psError(PS_ERR_UNKNOWN, true, "Returning false");
-    return false;
-
-    // XXX pmReadoutRead, pmReadoutReadSegement disabled for now
-    #if 0
-
-    if (view->readout >= cell->readouts->n) {
-        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
-                view->readout, cell->readouts->n);
-        return false;
-    }
-    pmReadout *readout = cell->readouts->data[view->readout];
-
-    if (view->nRows == 0) {
-        pmReadoutRead (readout, fits, NULL);
-    } else {
-        pmReadoutReadSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
-    }
-    return true;
-    #endif
-}
-
-// given an already-opened fits file, write the components corresponding
-// to the specified view
-bool pmFPAviewWriteFitsImage (const pmFPAview *view, pmFPAfile *file)
-{
-    PS_ASSERT_PTR_NON_NULL(view, false);
-    PS_ASSERT_PTR_NON_NULL(file, false);
-
-    pmFPA *fpa = file->fpa;
-    psFits *fits = file->fits;
-
-    // pmFPAWrite takes care of all PHUs as needed
-    if (view->chip == -1) {
-        pmFPAWrite(fpa, fits, NULL, true, true);
-        return true;
-    }
-
-    if (view->chip >= fpa->chips->n) {
-        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
-        return false;
-    }
-    pmChip *chip = fpa->chips->data[view->chip];
-
-    // do we need to write out a PHU for this entry?
-    if (file->phu == NULL) {
-        pmHDU *hdu = pmFPAviewThisHDU (view, file->fpa);
-        pmHDU *phu = pmFPAviewThisPHU (view, file->fpa);
-        // if this hdu is the phu, the write function below will create the phu
-        if (hdu != phu) {
-            // we assume that the PHU is just a header
-            psMetadata *outhead = psMetadataCopy (NULL, phu->header);
-            psMetadataAdd (outhead, PS_LIST_TAIL, "EXTEND", PS_DATA_BOOL | PS_META_REPLACE, "this file has extensions", true);
-            psFitsWriteBlank (file->fits, outhead);
-            file->phu = phu->header;
-            psTrace ("pmFPAfile", 5, "wrote phu %s (type: %d)\n", file->filename, file->type);
-            psFree (outhead);
-        }
-    }
-
-    if (view->cell == -1) {
-        pmChipWrite (chip, fits, NULL, true, true);
-        return true;
-    }
-
-    if (view->cell >= chip->cells->n) {
-        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
-        return false;
-    }
-    pmCell *cell = chip->cells->data[view->cell];
-
-    if (view->readout == -1) {
-        return pmCellWrite (cell, fits, NULL, true);
-    }
-    psError(PS_ERR_UNKNOWN, true, "Returning false");
-    return false;
-
-    // XXX disable readout write for now
-    #if 0
-
-    if (view->readout >= cell->readouts->n) {
-        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
-                view->readout, cell->readouts->n);
-        return false;
-    }
-    pmReadout *readout = cell->readouts->data[view->readout];
-
-    if (view->nRows == 0) {
-        pmReadoutWrite (readout, fits, NULL, NULL);
-    } else {
-        pmReadoutWriteSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
-    }
-    return true;
-    #endif
-}
-
-// look for the given name on the argument list.
-// returns the file (a view to the one saved on config->files)
-pmFPAfile *pmFPAfileFromArgs (bool *found, pmConfig *config, char *filename, char *argname)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_PTR_NON_NULL(filename, false);
-    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
-    PS_ASSERT_PTR_NON_NULL(argname, false);
-    PS_ASSERT_INT_POSITIVE(strlen(argname), false);
-
-    bool status;
-    pmFPA *fpa = NULL;
-    psFits *fits = NULL;
-    pmFPAfile *file = NULL;
-    psMetadata *phu = NULL;
-    psMetadata *format = NULL;
-
-    if (*found) {
-        return NULL;
-    }
-
-    // we search the argument data for the named fileset (argname)
-    psArray *infiles = psMetadataLookupPtr(&status, config->arguments, argname);
-    if (!status) {
-        psTrace("pmFPAfile", 5, "Failed to find %s in argument list", argname);
-        return NULL;
-    }
-    if (infiles->n < 1) {
-        psError(PS_ERR_IO, false, "Found n == %d files in %s in arguments\n", infiles->n, argname);
-        return NULL;
-    }
-
-    // determine the current format from the header
-    // if no camera has been specified, use the first image as a template for the rest.
-    fits = psFitsOpen (infiles->data[0], "r");
-    phu = psFitsReadHeader (NULL, fits);
-    format = pmConfigCameraFormatFromHeader (config, phu);
-    psFitsClose (fits);                        // don't close phu; we'll use it below
-    if (!format) {
-        psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", infiles->data[0]);
-        psFree(phu);
-        return NULL;
-    }
-
-    // build the template fpa, set up the basic view
-    fpa = pmFPAConstruct (config->camera);
-    if (!fpa) {
-        psError(PS_ERR_IO, false, "Failed to construct FPA from %s", infiles->data[0]);
-        return NULL;
-    }
-
-    // load the given filerule (from config->camera) and associate it with the fpa
-    // the output file is just a view to the file on config->files
-    file = pmFPAfileDefine (config->files, config->camera, fpa, filename);
-    if (!file) {
-        psError(PS_ERR_IO, false, "file %s not defined", filename);
-        psFree(phu);
-        psFree (fpa);
-        psFree (format);
-        return NULL;
-    }
-
-    // this file is (by virtue of being supplied in the argument list) coming from the fileset
-    psFree (file->filerule);
-    psFree (file->filextra);
-
-    // adjust the rules to identify these files in the file->names data
-    file->filerule = psStringCopy ("@FILES");
-    // XXX this rule does not work in general
-    file->filextra = psStringCopy ("{CHIP.NAME}.{CELL.NAME}");
-
-    // examine the list of input files and validate their cameras
-    for (int i = 0; i < infiles->n; i++) {
-        if (i > 0) {
-            fits = psFitsOpen (infiles->data[i], "r");
-            phu = psFitsReadHeader (NULL, fits);
-            pmConfigValidateCameraFormat (format, phu);
-            psFitsClose (fits);
-        }
-
-        // set the view to the corresponding entry for this phu
-        pmFPAview *view = pmFPAAddSourceFromHeader (fpa, phu, format);
-        if (!view) {
-            psError(PS_ERR_IO, false, "Failed to set view from file %s", infiles->data[i]);
-            psFree(phu);
-            psFree (fpa);
-            psFree (format);
-            return NULL;
-        }
-
-        // XXX is this the correct psMD to save the filename?
-        char *name = pmFPAfileNameFromRule (file->filextra, file, view);
-        psMetadataAddStr (file->names, PS_LIST_TAIL, name, 0, "", infiles->data[i]);
-
-        psFree (view);
-        psFree (name);
-        psFree (phu);
-    }
-    psFree (fpa);
-    psFree (format);
-    *found = true;
-
-    return file;
-}
-
-// XXX this this function through, then finish
-#if 0
-// look for the given name on the argument list.
-// returns the file (a view to the one saved on config->files)
-// in this case, each file should correspond to the same view
-// (except at the readout level), of multiple FPAs
-// XXX think this through a bit more:
-//  - do we create multiple input fpas, or assign the same files to the single fpa?
-//  - do we save the multiple pmFPAfiles in the config->files psMD?
-//  - do we save the multiple filenames in the file->names psMD?
-//  - if we have a single FPA and multiple names, we need a method to
-//    turn on a specific name for the I/O actions.  probably true if we
-//    have multiple FPAs as well.
-pmFPAfile *pmFPAfileSetFromArgs (bool *found, pmConfig *config, char *filename, char *argname)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_PTR_NON_NULL(filename, false);
-    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
-    PS_ASSERT_PTR_NON_NULL(argname, false);
-    PS_ASSERT_INT_POSITIVE(strlen(argname), false);
-
-    bool status;
-    pmFPA *fpa = NULL;
-    psFits *fits = NULL;
-    pmFPAfile *file = NULL;
-    psMetadata *phu = NULL;
-    psMetadata *format = NULL;
-
-    if (*found)
-        return NULL;
-
-    // we search the argument data for the named fileset (argname)
-    psArray *infiles = psMetadataLookupPtr(&status, config->arguments, argname);
-    if (!status) {
-        return NULL;
-    }
-    if (infiles->n < 1) {
-        return NULL;
-    }
-
-    // determine the current format from the header
-    // if no camera has been specified, use the first image as a template for the rest.
-    fits = psFitsOpen (infiles->data[0], "r");
-    phu = psFitsReadHeader (NULL, fits);
-    format = pmConfigCameraFormatFromHeader (config, phu);
-    psFitsClose (fits);
-
-    // build the template fpa, set up the basic view
-    fpa = pmFPAConstruct (config->camera);
-
-    // load the given filerule (from config->camera) and associate it with the fpa
-    // the output file is just a view to the file on config->files
-    // XXX the filenames placed on config->files should include the seq number
-    file = pmFPAfileDefine (config->files, config->camera, fpa, filename);
-    if (!file) {
-        psError(PS_ERR_IO, false, "file %s not defined", filename);
-        psFree (fpa);
-        psFree (format);
-        return NULL;
-    }
-
-    // this file is (by virtue of being supplied in the argument list) coming from the fileset
-    psFree (file->filerule);
-    psFree (file->filextra);
-
-    // adjust the rules to identify these files in the file->names data
-    file->filerule = psStringCopy ("@FILES");
-    // XXX this rule does not work in general
-    file->filextra = psStringCopy ("{CHIP.NAME}.{CELL.NAME}");
-
-    // examine the list of input files and validate their cameras
-    for (int i = 0; i < infiles->n; i++) {
-        if (i > 0) {
-            fits = psFitsOpen (infiles->data[i], "r");
-            phu = psFitsReadHeader (NULL, fits);
-            pmConfigValidateCameraFormat (format, phu);
-            psFitsClose (fits);
-        }
-
-        // set the view to the corresponding entry for this phu
-        pmFPAview *view = pmFPAAddSourceFromHeader (fpa, phu, format);
-
-        // XXX is this the correct psMD to save the filename?
-        char *name = pmFPAfileNameFromRule (file->filextra, file, view);
-        psMetadataAddStr (file->names, PS_LIST_TAIL, name, 0, "", infiles->data[i]);
-
-        psFree (view);
-        psFree (name);
-        psFree (phu);
-    }
-    psFree (fpa);
-    psFree (format);
-    *found = true;
-
-    return file;
-}
-#endif
-
-// create a new output pmFPAfile based on an existing FPA
-pmFPAfile *pmFPAfileFromFPA (pmConfig *config, pmFPA *src, int xBin, int yBin, char *filename)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_PTR_NON_NULL(src, false);
-    PS_ASSERT_PTR_NON_NULL(filename, false);
-    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
-
-    // XXX pmFPAConstruct has many leaks (6919)
-    pmFPA *fpa = pmFPAConstruct (config->camera);
-    pmFPAfile *file = pmFPAfileDefine (config->files, config->camera, fpa, filename);
-    if (!file) {
-        psErrorStackPrint(stderr, "file %s not defined\n", filename);
-        return NULL;
-    }
-    file->src = src; // inherit output elements from this source pmFPA
-    file->xBin = xBin;
-    file->yBin = yBin;
-
-    psFree (fpa);
-    return file;
-}
-
-// look for the given name on the argument list.
-pmFPAfile *pmFPAfileFromConf (bool *found, pmConfig *config, char *filename, pmFPA *input)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_PTR_NON_NULL(filename, false);
-    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
-    PS_ASSERT_PTR_NON_NULL(input, false);
-
-    psFits *fits = NULL;
-    pmFPAfile *file = NULL;
-    psMetadata *phu = NULL;
-    psMetadata *format = NULL;
-    psArray *infiles = NULL;
-
-    if (*found) {
-        return NULL;
-    }
-
-    // a camera config is needed (as source of file rule)
-    if (config->camera == NULL) {
-        psErrorStackPrint (stderr, "camera is not defined\n");
-        return NULL;
-    }
-
-    // expect @DETDB in the config filerule
-    file = pmFPAfileDefine (config->files, config->camera, NULL, filename);
-    if (!file) {
-        psError(PS_ERR_IO, false, "file %s not defined\n", filename);
-        return NULL;
-    }
-
-    // image names come from the file->name list?
-    if (!strcasecmp (file->filerule, "@FILES")) {
-        psAbort ("pmFPAfileFromConfig", "programming error");
-    }
-
-    // image needs to come from the detrend database
-    if (!strcasecmp (file->filerule, "@DETDB")) {
-        // char *extra = pmFPAfileNameFromRule (file->filextra, file, view);
-        // psArray *infiles = pmDetrendSelect (extra, input);
-        psAbort ("pmFPAfileFromConfig", "programming error: @DETDB not yet defined");
-    } else {
-        infiles = psArrayAlloc(1);
-        infiles->n = 1;
-        infiles->data[0] = psStringCopy (file->filerule);
-    }
-    if (infiles == NULL) {
-        return NULL;
-    }
-    if (infiles->n < 1) {
-        psFree (infiles);
-        return NULL;
-    }
-
-    // determine the current format from the header
-    // if no camera has been specified, use the first image as a template for the rest.
-    fits = psFitsOpen (infiles->data[0], "r");
-    phu = psFitsReadHeader (NULL, fits);
-    format = pmConfigCameraFormatFromHeader (config, phu);
-    psFitsClose (fits);
-
-    // build the template fpa, set up the basic view
-    file->fpa = pmFPAConstruct (config->camera);
-
-    // this file is (by virtue of being supplied in the argument list) coming from the fileset
-    psFree (file->filerule);
-    psFree (file->filextra);
-
-    // adjust the rules to identify these files in the file->names data
-    file->filerule = psStringCopy ("@FILES");
-    // XXX this rule does not work in general
-    file->filextra = psStringCopy ("{CHIP.NAME}.{CELL.NAME}");
-
-    // examine the list of input files and validate their cameras
-    for (int i = 0; i < infiles->n; i++) {
-        if (i > 0) {
-            fits = psFitsOpen (infiles->data[i], "r");
-            phu = psFitsReadHeader (NULL, fits);
-            pmConfigValidateCameraFormat (format, phu);
-            psFitsClose (fits);
-        }
-
-        // set the view to the corresponding entry for this phu
-        pmFPAview *view = pmFPAAddSourceFromHeader (file->fpa, phu, format);
-        if (!view) {
-            psError(PS_ERR_IO, false, "Unable to determine source for %s", file->name);
-            return NULL;
-        }
-
-        // XXX is this the correct psMD to save the filename?
-        char *name = pmFPAfileNameFromRule (file->filextra, file, view);
-        psMetadataAddStr (file->names, PS_LIST_TAIL, name, 0, "", infiles->data[i]);
-
-        psFree (view);
-        psFree (name);
-        psFree (phu);
-    }
-    psFree (format);
-    psFree (infiles);
-    *found = true;
-    return file;
-}
-
+// XXX reconsider this function name / concept
 bool pmFPAfileAddFileNames (psMetadata *files, char *name, char *value, int mode)
 {
Index: trunk/psModules/src/camera/pmFPAfile.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.h	(revision 7555)
+++ trunk/psModules/src/camera/pmFPAfile.h	(revision 7589)
@@ -7,6 +7,6 @@
 *  @author EAM, IfA
 *
-*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-06-10 03:01:29 $
+*  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-06-17 01:50:43 $
 *
 *  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
@@ -58,6 +58,6 @@
     pmFPAfileState state;  // have we opened the file, etc?
 
-    pmFPAdepth fileDepth;  // what depth in the FPA hierarchy represents a unique file?
-    pmFPAdepth dataDepth;  // at what depth do we read/write the data segment?
+    pmFPALevel fileLevel;  // what level in the FPA hierarchy represents a unique file?
+    pmFPALevel dataLevel;  // at what level do we read/write the data segment?
 
     pmFPA *fpa;    // for I/O files, we carry a pointer to the complete fpa
@@ -80,4 +80,6 @@
     char *extname;   // the current name of an active file extension
 
+    bool save;
+
     // the following elements are used for WRITE-mode IMAGE-type pmFPAfiles to inform
     // the creation of a new image based on an existing image
@@ -85,4 +87,6 @@
     int xBin;    // desired binning in x direction
     int yBin;    // desired binning in y direction
+
+    psMetadata *camera;
     psMetadata *format;
 }
@@ -92,66 +96,6 @@
 pmFPAfile *pmFPAfileAlloc ();
 
-// load the pmFPAfile information from the camera configuration data
-pmFPAfile *pmFPAfileDefine (psMetadata *files, psMetadata *camera, pmFPA *fpa, char *name);
-
-// load the pmFPAfile information from the camera configuration data, constructing the needed fpa structure
-// XXX deprecate this function?
-// pmFPAfile *pmFPAfileConstruct (psMetadata *files, psMetadata *format, psMetadata *camera, char *name);
-
-// open the real file corresponding to the given pmFPAfile appropriate to the current view
-bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view);
-
-// read from the real file corresponding to the given pmFPAfile for the current view
-bool pmFPAfileRead (pmFPAfile *file, const pmFPAview *view);
-
-bool pmFPAfileCreate (pmFPAfile *file, const pmFPAview *view);
-
-// write to the real file corresponding to the given pmFPAfile for the current view
-bool pmFPAfileWrite (pmFPAfile *file, const pmFPAview *view);
-
-// close the real file corresponding to the given pmFPAfile appropriate to the current view
-bool pmFPAfileClose (pmFPAfile *file, const pmFPAview *view);
-
-// free the data at this level
-bool pmFPAfileFreeData(pmFPAfile *file, const pmFPAview *view);
-
-// set the state of the specified pmFPAfile to active (state == true) or inactive
-// if name is NULL, set the state for all pmFPAfiles
-bool pmFPAfileActivate (psMetadata *files, bool state, char *name);
-
-// examine all pmFPAfiles listed in the files and perform the needed I/O operations (open,read,write,close)
-bool pmFPAfileIOChecks (psMetadata *files, const pmFPAview *view, pmFPAfilePlace place);
-
-// return an image corresponding to the current readout, from the specified file.  if the pmFPAfile does not
-// exist, construct the image using the given size and type (save it in a pmFPAfile??)
-// psImage *pmFPAfileReadoutImage (psMetadata *files, const pmFPAview *view, char *name, int Nx, int Ny, int type);
-
 // select the readout from the named pmFPAfile; if the named file does not exist,
 pmReadout *pmFPAfileThisReadout (psMetadata *files, const pmFPAview *view, const char *name);
-
-// create a file with the given name, assign it type "INTERNAL", and supply it with an image
-// of the requested dimensions. (image only, mask and weight are ignored)
-pmReadout *pmFPAfileCreateInternal (psMetadata *files, char *name, int Nx, int Ny, int type);
-
-// delete the INTERNAL file of the given name (if it exists)
-bool pmFPAfileDropInternal (psMetadata *files, char *name);
-
-// read an image into the current view
-bool pmFPAviewReadFitsImage (const pmFPAview *view, pmFPAfile *file);
-
-// write the components for the specified view
-bool pmFPAviewWriteFitsImage (const pmFPAview *view, pmFPAfile *file);
-
-// free the appropriate image containers
-bool pmFPAviewFreeFitsImage (const pmFPAview *view, pmFPAfile *file);
-
-// look for the given argname on the argument list.  find the give filename from the file rules
-pmFPAfile *pmFPAfileFromArgs (bool *found, pmConfig *config, char *filename, char *argname);
-
-// look for the given argname on the argument list.  find the give filename from the file rules
-pmFPAfile *pmFPAfileFromConf (bool *found, pmConfig *config, char *filename, pmFPA *input);
-
-// create a new output pmFPAfile based on an existing FPA
-pmFPAfile *pmFPAfileFromFPA (pmConfig *config, pmFPA *src, int xBin, int yBin, char *filename);
 
 // add the specified filename info (value) to the files of the given mode using the given reference name
Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 7589)
+++ trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 7589)
@@ -0,0 +1,702 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmConfig.h"
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "pmFPAConstruct.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+#include "pmFPAfile.h"
+#include "pmFPACopy.h"
+#include "pmFPARead.h"
+#include "pmFPAWrite.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModel.h"
+#include "pmSource.h"
+#include "pmSourceIO.h"
+#include "pmGrowthCurve.h"
+#include "pmPSF.h"
+#include "pmPSF_IO.h"
+#include "pmFPA_JPEG.h"
+#include "pmDetrendDB.h"
+
+// define an input-type pmFPAfile, bind to the optional fpa if supplied
+pmFPAfile *pmFPAfileDefineInput(pmConfig *config, pmFPA *fpa, char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->files, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->camera, NULL);
+    PS_ASSERT_PTR_NON_NULL(name, NULL);
+    PS_ASSERT_INT_POSITIVE(strlen(name), NULL);
+
+
+
+    bool status;
+    char *type;
+
+    // select the FILERULES from config->camera
+    psMetadata *filerules = psMetadataLookupPtr (&status, config->camera, "FILERULES");
+    if (filerules == NULL) {
+        psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
+        return NULL;
+    }
+
+    // select the name from the FILERULES
+    // check for alias name (type == STR, name is aliased name)
+    char *realname = psMetadataLookupStr (&status, filerules, name);
+    if (!realname || strlen(realname) == 0) {
+        realname = name;
+    }
+
+    psMetadata *data = psMetadataLookupPtr (&status, filerules, realname);
+    if (data == NULL) {
+        psError(PS_ERR_IO, true, "Can't find file concept %s!", name);
+        return NULL;
+    }
+
+    pmFPAfile *file = pmFPAfileAlloc ();
+
+    // save the name of this pmFPAfile
+    file->name = psStringCopy (name);
+
+    file->filerule = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "FILENAME.RULE"));
+    file->filextra = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "FILENAME.XTRA"));
+    file->extrule  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.RULE"));
+    file->extxtra  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.XTRA"));
+
+    file->type = PM_FPA_FILE_NONE;
+    type = psMetadataLookupStr (&status, data, "FILE.TYPE");
+    if (type != NULL) {
+        if (!strcasecmp (type, "SX"))     {
+            file->type = PM_FPA_FILE_SX;
+        }
+        if (!strcasecmp (type, "OBJ"))     {
+            file->type = PM_FPA_FILE_OBJ;
+        }
+        if (!strcasecmp (type, "CMP"))     {
+            file->type = PM_FPA_FILE_CMP;
+        }
+        if (!strcasecmp (type, "CMF"))     {
+            file->type = PM_FPA_FILE_CMF;
+        }
+        if (!strcasecmp (type, "RAW"))     {
+            file->type = PM_FPA_FILE_RAW;
+        }
+        if (!strcasecmp (type, "IMAGE"))     {
+            file->type = PM_FPA_FILE_IMAGE;
+        }
+        if (!strcasecmp (type, "PSF"))     {
+            file->type = PM_FPA_FILE_PSF;
+        }
+        if (!strcasecmp (type, "JPEG"))     {
+            file->type = PM_FPA_FILE_JPEG;
+        }
+    }
+    if (file->type == PM_FPA_FILE_NONE) {
+        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
+        return NULL;
+    }
+
+    file->mode = PM_FPA_MODE_READ;
+    file->fileLevel = PM_FPA_LEVEL_NONE; // the fileLevel depends on the input data
+
+    file->dataLevel = pmFPALevelFromName(psMetadataLookupStr (&status, data, "DATA.LEVEL"));
+    if (file->dataLevel == PM_FPA_LEVEL_NONE) {
+        psError(PS_ERR_IO, true, "DATA.LEVEL is not set for %s\n", name);
+        return NULL;
+    }
+
+    if (fpa != NULL) {
+        file->fpa = psMemIncrRefCounter(fpa);
+    }
+
+    psMetadataAddPtr (config->files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file);
+    psFree (file); // we free this copy of file, but 'files' still has a copy
+
+    return (file); // the returned value is a view into the version on 'files'
+}
+
+// define a pmFPAfile, bind to the optional fpa if supplied
+pmFPAfile *pmFPAfileDefineOutput(pmConfig *config, pmFPA *fpa, char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->files, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->camera, NULL);
+    PS_ASSERT_PTR_NON_NULL(name, NULL);
+    PS_ASSERT_INT_POSITIVE(strlen(name), NULL);
+
+    bool status;
+    char *type;
+
+    // select the FILERULES from the camera config
+    psMetadata *filerules = psMetadataLookupPtr (&status, config->camera, "FILERULES");
+    if (filerules == NULL) {
+        psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
+        return NULL;
+    }
+
+    // select the name from the FILERULES
+    // check for alias name (type == STR, name is aliased name)
+    char *realname = psMetadataLookupStr (&status, filerules, name);
+    if (!realname || strlen(realname) == 0) {
+        realname = name;
+    }
+
+    psMetadata *data = psMetadataLookupPtr (&status, filerules, realname);
+    if (data == NULL) {
+        psError(PS_ERR_IO, true, "Can't find file concept %s!", name);
+        return NULL;
+    }
+
+    pmFPAfile *file = pmFPAfileAlloc ();
+
+    // save the name of this pmFPAfile
+    file->name = psStringCopy (name);
+
+    file->filerule = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "FILENAME.RULE"));
+    file->filextra = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "FILENAME.XTRA"));
+    file->extrule  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.RULE"));
+    file->extxtra  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.XTRA"));
+
+    file->type = PM_FPA_FILE_NONE;
+    type = psMetadataLookupStr (&status, data, "FILE.TYPE");
+    if (type != NULL) {
+        if (!strcasecmp (type, "SX"))     {
+            file->type = PM_FPA_FILE_SX;
+        }
+        if (!strcasecmp (type, "OBJ"))     {
+            file->type = PM_FPA_FILE_OBJ;
+        }
+        if (!strcasecmp (type, "CMP"))     {
+            file->type = PM_FPA_FILE_CMP;
+        }
+        if (!strcasecmp (type, "CMF"))     {
+            file->type = PM_FPA_FILE_CMF;
+        }
+        if (!strcasecmp (type, "RAW"))     {
+            file->type = PM_FPA_FILE_RAW;
+        }
+        if (!strcasecmp (type, "IMAGE"))     {
+            file->type = PM_FPA_FILE_IMAGE;
+        }
+        if (!strcasecmp (type, "PSF"))     {
+            file->type = PM_FPA_FILE_PSF;
+        }
+        if (!strcasecmp (type, "JPEG"))     {
+            file->type = PM_FPA_FILE_JPEG;
+        }
+    }
+    if (file->type == PM_FPA_FILE_NONE) {
+        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
+        return NULL;
+    }
+
+    file->mode = PM_FPA_MODE_WRITE;
+    file->save = false;
+    char *save = psMetadataLookupStr (&status, data, "FILE.SAVE");
+    if (save != NULL) {
+        if (!strcasecmp (type, "TRUE"))     {
+            file->save = true;
+        }
+        if (!strcasecmp (type, "FALSE"))     {
+            file->save = false;
+        }
+    }
+
+    file->fileLevel = pmFPALevelFromName(psMetadataLookupStr(&status, data, "FILE.LEVEL"));
+    if (file->fileLevel == PM_FPA_LEVEL_NONE) {
+        psError(PS_ERR_IO, true, "FILE.LEVEL is not set for %s\n", name);
+        return NULL;
+    }
+
+    file->dataLevel = pmFPALevelFromName(psMetadataLookupStr (&status, data, "DATA.LEVEL"));
+    if (file->dataLevel == PM_FPA_LEVEL_NONE) {
+        psError(PS_ERR_IO, true, "DATA.LEVEL is not set for %s\n", name);
+        return NULL;
+    }
+
+    if (fpa != NULL) {
+        file->fpa = psMemIncrRefCounter(fpa);
+    }
+
+    // for WRITE type of data, the output format needs to be determined
+    // this is only needed if the output file is not identical in structure to the input?
+    // for
+    char *formatLine = psMetadataLookupStr (&status, data, "FILE.FORMAT");
+    if (formatLine && strcasecmp (formatLine, "NONE")) {
+
+        char *formatName = NULL;
+
+        psArray *words = psStringSplitArray (formatLine, ":", false);
+        if (!words || !words->n) {
+            psAbort("pmFPAfileDefine", "programming error: cannot be NULL or empty!");
+        }
+        if (words->n == 1) {
+            // format selected in this camera
+            formatName = formatLine;
+            file->camera = psMemIncrRefCounter (config->camera);
+        }
+        if (words->n == 2) {
+            // select the requested camera
+            formatName = words->data[1];
+            file->camera = pmConfigCameraByName(config, words->data[0]);
+            if (!file->camera) {
+                psError(PS_ERR_IO, false, "camera %s not found\n", words->data[0]);
+                psFree(words);
+                return NULL;
+            }
+        }
+
+        // select the format list from the selected camera
+        psMetadata *formats = psMetadataLookupMD(&status, file->camera, "FORMATS"); // List of formats
+
+        // select the desired format
+        char *formatFile = psMetadataLookupStr (&status, formats, formatName);
+        if (!formatFile) {
+            psError(PS_ERR_IO, false, "format %s for %s not defined", formatName, name);
+            psFree (file);
+            psFree (words);
+            return NULL;
+        }
+        readConfig (&file->format, formatFile, formatName);
+        psFree (words);
+    }
+
+    psMetadataAddPtr (config->files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file);
+    psFree (file); // we free this copy of file, but 'files' still has a copy
+    return (file); // the returned value is a view into the version on 'files'
+}
+
+// search for argname on the config->argument list
+// construct an FPA based on the files in this list (must represent a single FPA)
+// built the association between the FPA elements (CHIP/CELL) and the files
+// define the pmFPAfile filename and bind it to this FPA
+// save the pmFPAfile on config->files
+// return the pmFPAfile (a view to the one saved on config->files)
+pmFPAfile *pmFPAfileDefineFromArgs (bool *found, pmConfig *config, char *filename, char *argname)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_PTR_NON_NULL(filename, NULL);
+    PS_ASSERT_INT_POSITIVE(strlen(filename), NULL);
+    PS_ASSERT_PTR_NON_NULL(argname, NULL);
+    PS_ASSERT_INT_POSITIVE(strlen(argname), NULL);
+
+    bool status;
+    pmFPA *fpa = NULL;
+    psFits *fits = NULL;
+    pmFPAfile *file = NULL;
+    psMetadata *phu = NULL;
+    psMetadata *format = NULL;
+
+    if (*found)
+        return NULL;
+
+    // we search the argument data for the named fileset (argname)
+    psArray *infiles = psMetadataLookupPtr(&status, config->arguments, argname);
+    if (!status) {
+        psTrace("pmFPAfile", 5, "Failed to find %s in argument list", argname);
+        return NULL;
+    }
+    if (infiles->n < 1) {
+        psError(PS_ERR_IO, false, "Found n == %d files in %s in arguments\n", infiles->n, argname);
+        return NULL;
+    }
+
+    // load the header of the first image
+    fits = psFitsOpen (infiles->data[0], "r");
+    phu = psFitsReadHeader (NULL, fits);
+    psFitsClose (fits);
+
+    // determine the current format from the header
+    // determine camera if not specified already
+    format = pmConfigCameraFormatFromHeader (config, phu);
+    if (!format) {
+        psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", infiles->data[0]);
+        psFree(phu);
+        return NULL;
+    }
+
+    // build the template fpa, set up the basic view
+    fpa = pmFPAConstruct (config->camera);
+    if (!fpa) {
+        psError(PS_ERR_IO, false, "Failed to construct FPA from %s", infiles->data[0]);
+        return NULL;
+    }
+
+    // load the given filerule (from config->camera) and bind it to the fpa
+    // the returned file is just a view to the entry on config->files
+    file = pmFPAfileDefineInput (config, fpa, filename);
+    if (!file) {
+        psError(PS_ERR_IO, false, "file %s not defined\n", filename);
+        psFree(phu);
+        psFree (fpa);
+        psFree (format);
+        return NULL;
+    }
+
+    // adjust the rules to identify these files in the file->names data
+    psFree (file->filerule);
+    psFree (file->filextra);
+    file->filerule = psStringCopy ("@FILES");
+    file->filextra = psStringCopy ("{CHIP.NAME}.{CELL.NAME}");
+
+    // find the matching fileLevel
+    psMetadata *filemenu = psMetadataLookupPtr (&status, format, "FILE");
+    if (!filemenu) {
+        psError (PS_ERR_IO, true, "missing FILE in FORMAT");
+        return NULL;
+    }
+    char *levelName = psMetadataLookupStr (&status, filemenu, "PHU");
+    if (!levelName) {
+        psError (PS_ERR_IO, true, "missing PHU in FILE in FORMAT");
+        return NULL;
+    }
+    file->fileLevel = pmFPALevelFromName (levelName);
+    if (file->fileLevel == PM_FPA_LEVEL_NONE) {
+        psError (PS_ERR_IO, true, "unknown level");
+        return NULL;
+    }
+
+    // examine the list of input files and validate their cameras
+    // associated each filename with an element of the FPA
+    // save the association on file->names
+    for (int i = 0; i < infiles->n; i++) {
+        if (i > 0) {
+            fits = psFitsOpen (infiles->data[i], "r");
+            phu = psFitsReadHeader (NULL, fits);
+            pmConfigValidateCameraFormat (format, phu);
+            psFitsClose (fits);
+        }
+
+        // set the view to the corresponding entry for this phu
+        pmFPAview *view = pmFPAAddSourceFromHeader (fpa, phu, format);
+        if (!view) {
+            psError(PS_ERR_IO, false, "Unable to determine source for %s", file->name);
+            psFree(phu);
+            psFree (fpa);
+            psFree (format);
+            return NULL;
+        }
+
+        // associate the filename with the FPA element
+        char *name = pmFPAfileNameFromRule (file->filextra, file, view);
+
+        // save the name association in the pmFPAfile structure
+        psMetadataAddStr (file->names, PS_LIST_TAIL, name, 0, "", infiles->data[i]);
+
+        psFree (view);
+        psFree (name);
+        psFree (phu);
+    }
+    psFree (fpa);
+
+    file->format = format;
+    *found = true;
+    return file;
+}
+
+// define the named pmFPAfile from the camera->config
+// only valid for pmFPAfile->mode = READ
+pmFPAfile *pmFPAfileDefineFromConf (bool *found, pmConfig *config, char *filename)
+{
+    bool status;
+
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(filename, false);
+    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
+
+    if (*found)
+        return NULL;
+
+    // a camera config is needed (as source of file rule)
+    if (config->camera == NULL) {
+        psError(PS_ERR_IO, true, "camera is not defined");
+        return NULL;
+    }
+
+    // build the template fpa, set up the basic view
+    pmFPA *fpa = pmFPAConstruct (config->camera);
+    if (!fpa) {
+        psError(PS_ERR_IO, false, "Failed to construct FPA for %s", filename);
+        return NULL;
+    }
+
+    // load the given filerule (from config->camera) and bind it to the fpa
+    // the returned file is just a view to the entry on config->files
+    pmFPAfile *file = pmFPAfileDefineInput (config, fpa, filename);
+    if (!file) {
+        psError(PS_ERR_IO, false, "file %s not defined\n", filename);
+        psFree(fpa);
+        psFree(file);
+        return NULL;
+    }
+
+    // image names may not come from file->names
+    if (!strcasecmp (file->filerule, "@FILES")) {
+        psError(PS_ERR_IO, true, "supplied filerule uses illegal value @FILES");
+        // XXX remove the file from config->files
+        psFree(fpa);
+        psFree(file);
+        return NULL;
+    }
+
+    // image names may come from the detrend database
+    if (!strcasecmp (file->filerule, "@DETDB")) {
+        psTrace ("pmFPAfile", 5, "requiring use of detrend database source\n");
+        // don't free the file here: it is left on config->files
+        // to be used optionally by pmFPAfileDefineFromDetDB (or others)
+        psFree(fpa);
+        return NULL;
+    }
+
+    // use the supplied filename
+    char *infile = psStringCopy (file->filerule);
+
+    // load the header of the first image
+    psFits *fits = psFitsOpen (infile, "r");
+    psMetadata *phu = psFitsReadHeader (NULL, fits);
+    psFitsClose (fits);
+
+    // determine the current format from the header
+    // determine camera if not specified already
+    file->format = pmConfigCameraFormatFromHeader (config, phu);
+    if (!file->format) {
+        psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", infile);
+        psFree(phu);
+        psFree(fpa);
+        psFree(file);
+        psFree(infile);
+        return NULL;
+    }
+
+    // set the view to the corresponding entry for this phu
+    pmFPAview *view = pmFPAAddSourceFromHeader (fpa, phu, file->format);
+    if (!view) {
+        psError(PS_ERR_IO, false, "Unable to determine source for %s (%s)", file->name, infile);
+        psFree(phu);
+        psFree(fpa);
+        psFree(file);
+        psFree(infile);
+        return NULL;
+    }
+
+    // adjust the rules to identify these files in the file->names data
+    psFree (file->filerule);
+    psFree (file->filextra);
+    file->filerule = psStringCopy ("@FILES");
+    file->filextra = psStringCopy ("{CHIP.NAME}.{CELL.NAME}");
+
+    // find the matching fileLevel
+    psMetadata *filemenu = psMetadataLookupPtr (&status, file->format, "FILE");
+    if (!filemenu) {
+        psError (PS_ERR_IO, true, "missing FILE in FORMAT");
+        psFree(phu);
+        psFree(fpa);
+        psFree(file);
+        psFree(view);
+        psFree(infile);
+        return NULL;
+    }
+    char *levelName = psMetadataLookupStr (&status, filemenu, "PHU");
+    if (!levelName) {
+        psError (PS_ERR_IO, true, "missing PHU in FILE in FORMAT");
+        return NULL;
+    }
+    file->fileLevel = pmFPALevelFromName (levelName);
+    if (file->fileLevel == PM_FPA_LEVEL_NONE) {
+        psError (PS_ERR_IO, true, "unknown level");
+        return NULL;
+    }
+
+    // associate the filename with the FPA element
+    char *name = pmFPAfileNameFromRule (file->filextra, file, view);
+
+    // save the name association in the pmFPAfile structure
+    psMetadataAddStr (file->names, PS_LIST_TAIL, name, 0, "", infile);
+
+    psFree (phu);
+    psFree (fpa);
+    psFree (view);
+    psFree (name);
+    psFree (infile);
+
+    *found = true;
+    return file;
+}
+
+// construct an FPA based on the supplied config->camera
+// built the association between the FPA elements (CHIP/CELL) and the files
+// define the pmFPAfile filename and bind it to this FPA
+// save the pmFPAfile on config->files
+// return the pmFPAfile (a view to the one saved on config->files)
+pmFPAfile *pmFPAfileDefineFromDetDB (bool *found, pmConfig *config, char *filename, pmFPA *input, pmDetrendType type)
+{
+    PS_ASSERT_PTR_NON_NULL(input, NULL);
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->camera, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->files, NULL);
+    PS_ASSERT_PTR_NON_NULL(filename, NULL);
+
+    pmFPA *fpa = NULL;
+    pmFPAfile *file = NULL;
+
+    if (*found)
+        return NULL;
+
+    // a camera config is needed (as source of file rule)
+    if (config->camera == NULL) {
+        psError(PS_ERR_IO, true, "camera is not defined");
+        return NULL;
+    }
+
+    // find or define a pmFPAfile with this name
+    file = psMetadataLookupPtr (NULL, config->files, filename);
+    if (!file) {
+        // build the template fpa, set up the basic view
+        fpa = pmFPAConstruct (config->camera);
+        if (!fpa) {
+            psError(PS_ERR_IO, false, "Failed to construct FPA for %s", filename);
+            return NULL;
+        }
+        // load the given filerule (from config->camera) and bind it to the fpa
+        // the returned file is just a view to the entry on config->files
+        file = pmFPAfileDefineInput (config, fpa, filename);
+        if (!file) {
+            psError(PS_ERR_IO, false, "file %s not defined\n", filename);
+            psFree (fpa);
+            return NULL;
+        }
+    }
+
+    // detselect -camera (camera) -time (time) -type (type) [others]
+    // camera and time are functions of (pmFPA *input)
+
+    // XXX does this do something NASTY to the stack??
+    psTime *time = psTimeGetNow (PS_TIME_TAI);
+
+    psString camera = psStringCopy ("megacam");
+    pmDetrendSelectOptions *options = pmDetrendSelectOptionsAlloc(camera, *time, type);
+    psFree (camera);
+    psFree (time);
+
+    // add other options here f(pmFPA *input, type)
+
+    // search for existing detrend data (detID)
+    pmDetrendSelectResults *results = pmDetrendSelect (options);
+    if (!results) {
+        psLogMsg ("pmFPAfile", 2, "no matching detrend data");
+        psError (PS_ERR_IO, true, "no matching detrend data");
+        return NULL;
+    }
+
+    // replace the existing value of filextra with the selected detID
+    psFree (file->filextra);
+    file->filextra  = psStringCopy (results->detID);
+
+    // set the fileLevel based on the detDB results
+    file->fileLevel = results->level;
+
+    psFree (results);
+    psFree (options);
+
+    *found = true;
+    return file;
+}
+
+// create a new output pmFPAfile based on an existing FPA
+// only valid for pmFPAfile->mode == WRITE (or internal?)
+pmFPAfile *pmFPAfileDefineFromFPA (pmConfig *config, pmFPA *src, int xBin, int yBin, char *filename)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(src, false);
+    PS_ASSERT_PTR_NON_NULL(filename, false);
+    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
+
+    pmFPA *fpa = pmFPAConstruct (config->camera);
+    pmFPAfile *file = pmFPAfileDefineOutput (config, fpa, filename);
+    if (!file) {
+        psErrorStackPrint(stderr, "file %s not defined\n", filename);
+        return NULL;
+    }
+    file->src = src; // inherit output elements from this source pmFPA
+    file->xBin = xBin;
+    file->yBin = yBin;
+
+    psFree (fpa);
+    return file;
+}
+
+// create a new output pmFPAfile based on an existing FPA
+// only valid for pmFPAfile->mode == WRITE (or internal?)
+pmFPAfile *pmFPAfileDefineNewCamera (pmConfig *config, char *filename)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(filename, false);
+    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
+
+    pmFPAfile *file = pmFPAfileDefineOutput (config, NULL, filename);
+    if (!file) {
+        psErrorStackPrint(stderr, "file %s not defined\n", filename);
+        return NULL;
+    }
+    if (!file->camera) {
+        psErrorStackPrint(stderr, "file %s does not define a new camera\n", filename);
+        return NULL;
+    }
+    file->fpa = pmFPAConstruct(file->camera);
+    return file;
+}
+
+// create a file with the given name, assign it type "INTERNAL", and supply it with an image
+// of the requested dimensions. (image only, mask and weight are ignored)
+pmReadout *pmFPAfileDefineInternal (psMetadata *files, char *name, int Nx, int Ny, int type)
+{
+    PS_ASSERT_PTR_NON_NULL(files, false);
+    PS_ASSERT_PTR_NON_NULL(name, false);
+    PS_ASSERT_INT_POSITIVE(strlen(name), false);
+
+    pmReadout *readout = pmReadoutAlloc(NULL);
+    readout->image = psImageAlloc(Nx, Ny, type);
+
+    // I want an image from the
+    pmFPAfile *file = pmFPAfileAlloc();
+    file->mode = PM_FPA_MODE_INTERNAL;
+    file->name = psStringCopy (name);
+
+    file->readout = readout;
+    psMetadataAddPtr(files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file);
+    psFree(file);
+    // we free this copy of file, but 'files' still has a copy
+
+    return readout;
+}
+
+bool pmFPAfileDropInternal(psMetadata *files, char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(files, false);
+    PS_ASSERT_PTR_NON_NULL(name, false);
+    PS_ASSERT_INT_POSITIVE(strlen(name), false);
+
+    bool status = false;
+
+    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
+    if (!status) {
+        psTrace("pmFPAfile", 6, "Internal File %s not in file list", name);
+        return true;
+    }
+    if (file == NULL) {
+        psError(PS_ERR_IO, true, "file %s is NULL", name);
+        return false;
+    }
+    if (file->mode != PM_FPA_MODE_INTERNAL) {
+        psTrace("pmFPAfile", 6, "FPA File %s not Internal, not dropping", name);
+        return true;
+    }
+
+    psMetadataRemoveKey (files, name);
+    return true;
+}
+
Index: trunk/psModules/src/camera/pmFPAfileDefine.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.h	(revision 7589)
+++ trunk/psModules/src/camera/pmFPAfileDefine.h	(revision 7589)
@@ -0,0 +1,48 @@
+/** @file  pmFPAview.h
+*
+*  @brief Tools to manipulate the FPA structure elements.
+*
+*  @ingroup AstroImage
+*
+*  @author EAM, IfA
+*
+*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-06-17 01:50:43 $
+*
+*  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
+*/
+
+#include <pmDetrendDB.h>
+
+#ifndef PM_FPA_FILE_DEFINE_H
+#define PM_FPA_FILE_DEFINE_H
+
+// load the pmFPAfile information from the camera configuration data
+pmFPAfile *pmFPAfileDefineInput (pmConfig *config, pmFPA *fpa, char *name);
+
+// load the pmFPAfile information from the camera configuration data
+pmFPAfile *pmFPAfileDefineOutput (pmConfig *config, pmFPA *fpa, char *name);
+
+// look for the given argname on the argument list.  find the give filename from the file rules
+pmFPAfile *pmFPAfileDefineFromArgs (bool *found, pmConfig *config, char *filename, char *argname);
+
+// look for the given argname on the argument list.  find the give filename from the file rules
+pmFPAfile *pmFPAfileDefineFromConf (bool *found, pmConfig *config, char *filename);
+
+// look for the given argname on the argument list.  find the give filename from the file rules
+pmFPAfile *pmFPAfileDefineFromDetDB (bool *found, pmConfig *config, char *filename, pmFPA *input, pmDetrendType type);
+
+// create a new output pmFPAfile based on an existing FPA
+pmFPAfile *pmFPAfileDefineFromFPA (pmConfig *config, pmFPA *src, int xBin, int yBin, char *filename);
+
+// create a new output pmFPAfile based on a different camera
+pmFPAfile *pmFPAfileDefineNewCamera (pmConfig *config, char *filename);
+
+// create a file with the given name, assign it type "INTERNAL", and supply it with an image
+// of the requested dimensions. (image only, mask and weight are ignored)
+pmReadout *pmFPAfileDefineInternal (psMetadata *files, char *name, int Nx, int Ny, int type);
+
+// delete the INTERNAL file of the given name (if it exists)
+bool pmFPAfileDropInternal (psMetadata *files, char *name);
+
+# endif
Index: trunk/psModules/src/camera/pmFPAfileFitsIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 7589)
+++ trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 7589)
@@ -0,0 +1,210 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmConfig.h"
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPARead.h"
+#include "pmFPAWrite.h"
+#include "pmFPAMaskWeight.h"
+#include "pmFPAConstruct.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+#include "pmFPAfileFitsIO.h"
+
+// given an already-opened fits file, read the components corresponding
+// to the specified view
+bool pmFPAviewReadFitsImage (const pmFPAview *view, pmFPAfile *file)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    bool status;
+    pmFPA *fpa = file->fpa;
+    psFits *fits = file->fits;
+
+    if (view->chip == -1) {
+        status = pmFPARead (fpa, fits, NULL);
+        return status;
+    }
+
+    if (view->chip >= fpa->chips->n) {
+        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
+        return false;
+    }
+    pmChip *chip = fpa->chips->data[view->chip];
+
+    if (view->cell == -1) {
+        status = pmChipRead (chip, fits, NULL);
+        return status;
+    }
+
+    if (view->cell >= chip->cells->n) {
+        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
+        return false;
+    }
+    pmCell *cell = chip->cells->data[view->cell];
+
+    if (view->readout == -1) {
+        status = pmCellRead (cell, fits, NULL);
+        return status;
+    }
+    psError(PS_ERR_UNKNOWN, true, "Returning false");
+    return false;
+
+    // XXX pmReadoutRead, pmReadoutReadSegement disabled for now
+    #if 0
+
+    if (view->readout >= cell->readouts->n) {
+        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
+                view->readout, cell->readouts->n);
+        return false;
+    }
+    pmReadout *readout = cell->readouts->data[view->readout];
+
+    if (view->nRows == 0) {
+        pmReadoutRead (readout, fits, NULL);
+    } else {
+        pmReadoutReadSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
+    }
+    return true;
+    #endif
+}
+
+// given an already-opened fits file, write the components corresponding
+// to the specified view
+bool pmFPAviewWriteFitsImage (const pmFPAview *view, pmFPAfile *file)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    pmFPA *fpa = file->fpa;
+    psFits *fits = file->fits;
+
+    // pmFPAWrite takes care of all PHUs as needed
+    if (view->chip == -1) {
+        pmFPAWrite(fpa, fits, NULL, true, true);
+        return true;
+    }
+
+    if (view->chip >= fpa->chips->n) {
+        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
+        return false;
+    }
+    pmChip *chip = fpa->chips->data[view->chip];
+
+    // do we need to write out a PHU for this entry?
+    if (file->phu == NULL) {
+        pmHDU *hdu = pmFPAviewThisHDU (view, file->fpa);
+        pmHDU *phu = pmFPAviewThisPHU (view, file->fpa);
+        // if this hdu is the phu, the write function below will create the phu
+        if (hdu != phu) {
+            // we assume that the PHU is just a header
+            psMetadata *outhead = psMetadataCopy (NULL, phu->header);
+            psMetadataAdd (outhead, PS_LIST_TAIL, "EXTEND", PS_DATA_BOOL | PS_META_REPLACE, "this file has extensions", true);
+            psFitsWriteBlank (file->fits, outhead);
+            file->phu = phu->header;
+            psTrace ("pmFPAfile", 5, "wrote phu %s (type: %d)\n", file->filename, file->type);
+            psFree (outhead);
+        }
+    }
+
+    if (view->cell == -1) {
+        pmChipWrite (chip, fits, NULL, true, true);
+        return true;
+    }
+
+    if (view->cell >= chip->cells->n) {
+        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
+        return false;
+    }
+    pmCell *cell = chip->cells->data[view->cell];
+
+    if (view->readout == -1) {
+        return pmCellWrite (cell, fits, NULL, true);
+    }
+    psError(PS_ERR_UNKNOWN, true, "Returning false");
+    return false;
+
+    // XXX disable readout write for now
+    #if 0
+
+    if (view->readout >= cell->readouts->n) {
+        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
+                view->readout, cell->readouts->n);
+        return false;
+    }
+    pmReadout *readout = cell->readouts->data[view->readout];
+
+    if (view->nRows == 0) {
+        pmReadoutWrite (readout, fits, NULL, NULL);
+    } else {
+        pmReadoutWriteSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
+    }
+    return true;
+    #endif
+}
+
+// given an already-opened fits file, read the components corresponding
+// to the specified view
+bool pmFPAviewFreeFitsImage (const pmFPAview *view, pmFPAfile *file)
+{
+    PS_ASSERT_PTR_NON_NULL(view, false);
+    PS_ASSERT_PTR_NON_NULL(file, false);
+
+    pmFPA *fpa = file->fpa;
+
+    if (view->chip == -1) {
+        psTrace ("pmFPAfile", 5, "freeing fpa for %s\n", file->filename);
+        pmFPAFreeData (fpa);
+        // XXX drop me: file->fpa = NULL;
+        return true;
+    }
+
+    if (view->chip >= fpa->chips->n) {
+        psError(PS_ERR_IO, true, "Requested chip == %d >= fpa->chips->n == %d", view->chip, fpa->chips->n);
+        return false;
+    }
+    pmChip *chip = fpa->chips->data[view->chip];
+
+    if (view->cell == -1) {
+        psTrace ("pmFPAfile", 5, "freeing chip %d for %s\n", view->chip, file->filename);
+        pmChipFreeData (chip);
+        // XXX drop me: fpa->chips->data[view->chip] = NULL;
+        return true;
+    }
+
+    if (view->cell >= chip->cells->n) {
+        psError(PS_ERR_IO, true, "Requested cell == %d >= chip->cells->n == %d", view->cell, chip->cells->n);
+        return false;
+    }
+    pmCell *cell = chip->cells->data[view->cell];
+
+    if (view->readout == -1) {
+        psTrace ("pmFPAfile", 5, "freeing cell %d for %s\n", view->cell, file->filename);
+        pmCellFreeData (cell);
+        // XXX drop me: chip->cells->data[view->cell] = NULL;
+        return true;
+    }
+    psError(PS_ERR_UNKNOWN, true, "Returning false");
+    return false;
+
+    // XXX pmReadoutRead, pmReadoutReadSegement disabled for now
+    #if 0
+
+    if (view->readout >= cell->readouts->n) {
+        psError(PS_ERR_IO, true, "Requested readout == %d >= cell->readouts->n == %d",
+                view->readout, cell->readouts->n);
+        return false;
+    }
+    pmReadout *readout = cell->readouts->data[view->readout];
+
+    if (view->nRows == 0) {
+        pmReadoutRead (readout, fits, NULL);
+    } else {
+        pmReadoutReadSegment (readout, fits, view->nRows, view->iRows, NULL, NULL);
+    }
+    return true;
+    #endif
+}
+
Index: trunk/psModules/src/camera/pmFPAfileFitsIO.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfileFitsIO.h	(revision 7589)
+++ trunk/psModules/src/camera/pmFPAfileFitsIO.h	(revision 7589)
@@ -0,0 +1,27 @@
+/** @file  pmFPAview.h
+*
+*  @brief Tools to manipulate the FPA structure elements.
+*
+*  @ingroup AstroImage
+*
+*  @author EAM, IfA
+*
+*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-06-17 01:50:43 $
+*
+*  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
+*/
+
+#ifndef PM_FPA_FILE_FITS_IO_H
+#define PM_FPA_FILE_FITS_IO_H
+
+// read an image into the current view
+bool pmFPAviewReadFitsImage (const pmFPAview *view, pmFPAfile *file);
+
+// write the components for the specified view
+bool pmFPAviewWriteFitsImage (const pmFPAview *view, pmFPAfile *file);
+
+// free the appropriate image containers
+bool pmFPAviewFreeFitsImage (const pmFPAview *view, pmFPAfile *file);
+
+# endif
Index: trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.c	(revision 7589)
+++ trunk/psModules/src/camera/pmFPAfileIO.c	(revision 7589)
@@ -0,0 +1,578 @@
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmConfig.h"
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "pmFPAConstruct.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+#include "pmFPACopy.h"
+#include "pmFPARead.h"
+#include "pmFPAWrite.h"
+#include "pmFPAfileFitsIO.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModel.h"
+#include "pmSource.h"
+#include "pmSourceIO.h"
+#include "pmGrowthCurve.h"
+#include "pmPSF.h"
+#include "pmPSF_IO.h"
+#include "pmFPA_JPEG.h"
+# include "pmDetrendDB.h"
+
+// open file (if not already opened)
+bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    bool status;
+    char *extra;
+    char *mode = NULL;
+    char *readMode = "r";
+    char *writeMode = "w";
+
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("pmFPAfile", 6, "skip open for %s, files is inactive", file->name);
+        return true;
+    }
+
+    if (file->state == PM_FPA_STATE_OPEN) {
+        return true;
+    }
+
+    if (file->mode == PM_FPA_MODE_NONE) {
+        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_NONE");
+        return false;
+    }
+    if (file->mode == PM_FPA_MODE_INTERNAL) {
+        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
+        return false;
+    }
+    if (file->mode == PM_FPA_MODE_READ) {
+        mode = readMode;
+    }
+    if (file->mode == PM_FPA_MODE_WRITE) {
+        mode = writeMode;
+    }
+
+    // determine the file name
+    // free a name allocated earlier
+    psFree (file->filename);
+    file->filename = pmFPAfileNameFromRule (file->filerule, file, view);
+    if (file->filename == NULL) {
+        psError(PS_ERR_IO, true, "Filename is NULL");
+        return false;
+    }
+
+    // indirect filenames
+    if (!strcasecmp (file->filename, "@FILES")) {
+        psFree (file->filename);
+        extra = pmFPAfileNameFromRule (file->filextra, file, view);
+        file->filename = psMetadataLookupStr (&status, file->names, extra);
+        psFree (extra);
+        if (file->filename == NULL) {
+            psError(PS_ERR_IO, true, "filename lookup error (@FILES) for %s : %s\n", file->filextra, extra);
+            return false;
+        }
+        // psMetadataLookupStr just returns a view, file->filename must be protected
+        psMemIncrRefCounter (file->filename);
+    }
+    if (!strcasecmp (file->filename, "@DETDB")) {
+        psFree (file->filename);
+        extra = pmFPAfileNameFromRule (file->extrule, file, view);
+        psTrace ("pmFPAfile", 6, "looking for detrend (%s, %s)\n", file->filextra, extra);
+        file->filename = pmDetrendFile (file->filextra, extra);
+        psTrace ("pmFPAfile", 6, "got detrend file %s\n", file->filename);
+        psFree (extra);
+        if (file->filename == NULL) {
+            psError(PS_ERR_IO, true, "filename lookup error (@DETBD) for %s : %s\n", file->filextra, extra);
+            return false;
+        }
+    }
+
+    switch (file->type) {
+        // open the FITS types:
+    case PM_FPA_FILE_IMAGE:
+    case PM_FPA_FILE_CMF:
+        psTrace ("pmFPAfile", 5, "opening %s (type: %d)\n", file->filename, file->type);
+        file->fits = psFitsOpen (file->filename, mode);
+        if (file->fits == NULL) {
+            psError(PS_ERR_IO, false, "error opening file %s\n", file->filename);
+            return false;
+        }
+        file->state = PM_FPA_STATE_OPEN;
+
+        // In some cases, I need to call pmFPAAddSourceFromHeader after I've opened the file
+        // specifically if I have not called this function on startup.  This happens for the
+        // images supplied by the detrend database, which are only identified here (above).
+        // this is never true for the output images, which are constructed later
+
+        if (file->mode != PM_FPA_MODE_READ) {
+            break;
+        }
+
+        pmChip *chip;
+        pmCell *cell;
+        bool addSource = false;
+        switch (file->fileLevel) {
+        case PM_FPA_LEVEL_FPA:
+            addSource = !file->fpa->hdu;
+            break;
+        case PM_FPA_LEVEL_CHIP:
+            chip = pmFPAviewThisChip(view, file->fpa);
+            if (!chip) {
+                psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CHIP, view is FPA");
+                return false;
+            }
+            addSource = !chip->hdu;
+            break;
+        case PM_FPA_LEVEL_CELL:
+            cell = pmFPAviewThisCell(view, file->fpa);
+            if (!cell) {
+                psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CELL, view is FPA");
+                return false;
+            }
+            addSource = !cell->hdu;
+            break;
+        default:
+            psAbort ("pmFPAfileIO", "fileLevel not correctly set");
+            break;
+        }
+
+        if (addSource) {
+            psMetadata *phu = psFitsReadHeader (NULL, file->fits);
+            if (!file->format) {
+                file->format = pmConfigCameraFormatFromHeader (config, phu);
+                if (!file->format) {
+                    psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
+                    psFree(phu);
+                    return NULL;
+                }
+            } else {
+                pmConfigValidateCameraFormat (file->format, phu);
+            }
+            pmFPAview *thisView = pmFPAAddSourceFromHeader (file->fpa, phu, file->format);
+            psFree (thisView);
+            psFree (phu);
+            // XXX we can check the output view to be sure it corresponds to our current view
+        }
+        break;
+
+        // defer opening TEXT types:
+    case PM_FPA_FILE_SX:
+    case PM_FPA_FILE_OBJ:
+    case PM_FPA_FILE_CMP:
+    case PM_FPA_FILE_RAW:
+    case PM_FPA_FILE_PSF:
+    case PM_FPA_FILE_JPEG:
+        psTrace ("pmFPAfile", 5, "defer opening %s\n", file->filename);
+        break;
+
+    default:
+        psError(PS_ERR_IO, true, "type mismatch for %s : %d\n", file->filename, file->type);
+        return false;
+    }
+    return true;
+}
+
+bool pmFPAfileRead(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("pmFPAfile", 6, "skip read for %s, files is inactive", file->name);
+        return true;
+    }
+
+    if (file->mode != PM_FPA_MODE_READ) {
+        psTrace("pmFPAfile", 6, "skip read for %s, mode is not READ", file->name);
+        return true;
+    }
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // do we need to open this file?
+    if (level == file->fileLevel) {
+        if (!pmFPAfileOpen (file, view, config)) {
+            psError(PS_ERR_IO, false, "failed to open file %s", file->name);
+            return false;
+        }
+    }
+
+    // do we need to read this file?
+    if (level != file->dataLevel) {
+        psTrace("pmFPAfile", 6, "skip reading of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
+        return true;
+    }
+
+    switch (file->type) {
+    case PM_FPA_FILE_IMAGE:
+        if (pmFPAviewReadFitsImage (view, file)) {
+            psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
+        } else {
+            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
+            return false;
+        }
+        break;
+
+    case PM_FPA_FILE_SX:
+    case PM_FPA_FILE_RAW:
+    case PM_FPA_FILE_OBJ:
+    case PM_FPA_FILE_CMP:
+    case PM_FPA_FILE_CMF:
+        pmFPAviewReadObjects (view, file);
+        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
+        break;
+
+    case PM_FPA_FILE_PSF:
+        pmFPAviewReadPSFmodel (view, file);
+        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
+        break;
+
+    case PM_FPA_FILE_JPEG:
+        break;
+
+    default:
+        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d", file->type);
+        return false;
+    }
+    return true;
+}
+
+bool pmFPAfileFreeData(pmFPAfile *file, const pmFPAview *view)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("pmFPAfile", 6, "skip free for %s, files is inactive", file->name);
+        return true;
+    }
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // do we need to read this file?
+    if (level != file->dataLevel) {
+        psTrace("pmFPAfile", 6, "skip free of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
+        return true;
+    }
+
+    switch (file->type) {
+    case PM_FPA_FILE_IMAGE:
+        if (pmFPAviewFreeFitsImage (view, file)) {
+            psTrace ("pmFPAfile", 5, "freed %s (type: %d)\n", file->filename, file->type);
+        } else {
+            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
+            return false;
+        }
+        break;
+
+    case PM_FPA_FILE_SX:
+    case PM_FPA_FILE_RAW:
+    case PM_FPA_FILE_OBJ:
+    case PM_FPA_FILE_CMP:
+    case PM_FPA_FILE_CMF:
+        // pmFPAviewFreeObjects (view, file);
+        psTrace ("pmFPAfile", 5, "NOT freeing %s (type: %d)\n", file->filename, file->type);
+        break;
+
+        // XXX not certain what I need to free here
+    case PM_FPA_FILE_PSF:
+    case PM_FPA_FILE_JPEG:
+        break;
+
+    default:
+        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d", file->type);
+        return false;
+    }
+    return true;
+}
+
+bool pmFPAfileWrite(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("pmFPAfile", 6, "skip write for %s, files is inactive", file->name);
+        return true;
+    }
+
+    if (file->mode != PM_FPA_MODE_WRITE) {
+        psTrace("pmFPAfile", 6, "skip write for %s, mode is not WRITE", file->name);
+        return true;
+    }
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // do we need to write this file?
+    if (level != file->dataLevel) {
+        psTrace("pmFPAfile", 6, "skip writing of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
+        return true;
+    }
+
+    // do we need to open this file?
+    if (level >= file->fileLevel) {
+        if (!pmFPAfileOpen (file, view, config)) {
+            psError(PS_ERR_IO, false, "failed to open %s", file->filename);
+            return false;
+        }
+    }
+
+    switch (file->type) {
+    case PM_FPA_FILE_IMAGE:
+        pmFPAviewWriteFitsImage (view, file);
+        psTrace ("pmFPAfile", 5, "wrote image %s (fpa: %p)\n", file->filename, file->fpa);
+        break;
+
+    case PM_FPA_FILE_SX:
+    case PM_FPA_FILE_RAW:
+    case PM_FPA_FILE_OBJ:
+    case PM_FPA_FILE_CMP:
+    case PM_FPA_FILE_CMF:
+        psTrace ("pmFPAfile", 5, "writing object %s (fpa: %p)\n", file->filename, file->fpa);
+        if (!pmFPAviewWriteObjects (view, file)) {
+            psError(PS_ERR_IO, false, "Failed to write object %s", file->filename);
+            return false;
+        }
+
+        break;
+
+    case PM_FPA_FILE_PSF:
+        pmFPAviewWritePSFmodel (view, file);
+        psTrace ("pmFPAfile", 5, "wrote PSF %s (fpa: %p)\n", file->filename, file->fpa);
+        break;
+
+    case PM_FPA_FILE_JPEG:
+        pmFPAviewWriteJPEG (view, file);
+        psTrace ("pmFPAfile", 5, "wrote PSF %s (fpa: %p)\n", file->filename, file->fpa);
+        break;
+
+    default:
+        fprintf (stderr, "warning: type mismatch\n");
+        return false;
+    }
+    return true;
+}
+
+// create the data elements (headers, images) appropriate for this view
+bool pmFPAfileCreate (pmFPAfile *file, const pmFPAview *view)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    // these are not error conditions; these are state tests
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("pmFPAfile", 6, "skip create for inactive file %s", file->name);
+        return true;
+    }
+    if (file->mode != PM_FPA_MODE_WRITE) {
+        psTrace("pmFPAfile", 6, "skip create for non-write file %s", file->name);
+        return true;
+    }
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // don't create the file if the src (FPA) is not defined
+    if (file->src == NULL) {
+        psTrace("pmFPAfile", 6, "skip create for FPA without src FPA for %s", file->name);
+        return true;
+    }
+
+    // do we need to write this file?
+    if (level != file->dataLevel) {
+        psTrace("pmFPAfile", 6, "skip creation of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
+        return true;
+    }
+
+    switch (file->type) {
+    case PM_FPA_FILE_IMAGE:
+
+        /* create a PHU for thie file, if it does not exist */
+        pmFPAfileCopyStructureView (file->fpa, file->src, file->format, file->xBin, file->yBin, view);
+        psTrace ("pmFPAfile", 5, "created fpa data elements for %s (fpa: %p)\n", file->name, file->fpa);
+        break;
+
+    case PM_FPA_FILE_SX:
+    case PM_FPA_FILE_RAW:
+    case PM_FPA_FILE_OBJ:
+    case PM_FPA_FILE_CMP:
+    case PM_FPA_FILE_CMF:
+    case PM_FPA_FILE_PSF:
+    case PM_FPA_FILE_JPEG:
+        break;
+
+    default:
+        psError(PS_ERR_IO, true, "Unsupported type for %s: %d", file->name, file->type);
+        return false;
+    }
+    return true;
+}
+
+bool pmFPAfileClose (pmFPAfile *file, const pmFPAview *view)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("pmFPAfile", 6, "skip close for %s, files is inactive", file->name);
+        return true;
+    }
+    if (file->state == PM_FPA_STATE_CLOSED) {
+        return true;
+    }
+
+    // is current level == open level?
+    pmFPALevel level = pmFPAviewLevel (view);
+    if (file->fileLevel != level) {
+        psTrace("pmFPAfile", 6, "skip closing of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
+        return true;
+    }
+
+    // check if we are actually open
+    switch (file->type) {
+        // check the FITS types
+    case PM_FPA_FILE_IMAGE:
+    case PM_FPA_FILE_CMF:
+        psFitsClose (file->fits);
+        psTrace ("pmFPAfile", 5, "closing %s (type: %d)\n", file->filename, file->type);
+        file->fits = NULL;
+        file->phu = NULL;
+        file->header = NULL;
+        file->state = PM_FPA_STATE_CLOSED;
+        break;
+
+        // ignore the TEXT types
+    case PM_FPA_FILE_SX:
+    case PM_FPA_FILE_RAW:
+    case PM_FPA_FILE_OBJ:
+    case PM_FPA_FILE_CMP:
+    case PM_FPA_FILE_PSF:
+    case PM_FPA_FILE_JPEG:
+        break;
+
+    default:
+        psError(PS_ERR_IO, true, "type mismatch: %d", file->type);
+        return false;
+    }
+    return true;
+}
+
+// set the state of the specified pmFPAfile to active (state == true) or inactive
+// if name is NULL, set the state for all pmFPAfiles
+bool pmFPAfileActivate (psMetadata *files, bool state, char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(files, false);
+
+    if (!name) {
+        psMetadataItem *item = NULL;
+        psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
+        while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+            pmFPAfile *file = item->data.V;
+            if (state) {
+                file->state &= NOT_U8(PM_FPA_STATE_INACTIVE);
+            } else {
+                file->state |= PM_FPA_STATE_INACTIVE;
+            }
+        }
+        psFree (iter);
+        return true;
+    }
+
+    bool status = false;
+    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
+    if (!status) {
+        psTrace("pmFPAfile", 6, "%s is not a defined IO file", name);
+        return false;
+    }
+    if (!file) {
+        psError(PS_ERR_IO, true, "file %s is NULL", name);
+        return false;
+    }
+    if (state) {
+        file->state &= NOT_U8(PM_FPA_STATE_INACTIVE);
+    } else {
+        file->state |= PM_FPA_STATE_INACTIVE;
+    }
+    return true;
+}
+
+// attempt create, read, write, close, or free pmFPAfiles available in files
+// files are automatically opened before they are read
+bool pmFPAfileIOChecks (pmConfig *config, const pmFPAview *view, pmFPAfilePlace place)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(config->files, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    bool status = true;
+    psMetadata *files = config->files;
+
+    // attempt to perform all create, read, write
+    psMetadataItem *item = NULL;
+    psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
+    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+        pmFPAfile *file = item->data.V;
+
+        switch (place) {
+        case PM_FPA_BEFORE:
+            if (!pmFPAfileRead (file, view, config)) {
+                psError(PS_ERR_IO, false, "failed READ in FPA_BEFORE block for %s", file->name);
+                status = false;
+            }
+            if (!pmFPAfileCreate(file, view)) {
+                psError(PS_ERR_IO, false, "failed CREATE in FPA_BEFORE block for %s", file->name);
+                status = false;
+            }
+            break;
+        case PM_FPA_AFTER:
+            if (!pmFPAfileWrite (file, view, config)) {
+                psError(PS_ERR_IO, false, "failed WRITE in FPA_AFTER block for %s", file->name);
+                status = false;
+            }
+            if (!pmFPAfileClose(file, view)) {
+                psError(PS_ERR_IO, false, "failed CLOSE in FPA_AFTER block for %s", file->name);
+                status = false;
+            }
+            break;
+        default:
+            psAbort(PS_FILE_LINE, "You can't get here");
+        }
+    }
+
+    // attempt to free data that is no longer needed
+    psMetadataIteratorSet (iter, PS_LIST_HEAD);
+    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+        pmFPAfile *file = item->data.V;
+
+        switch (place) {
+        case PM_FPA_BEFORE:
+            break;
+        case PM_FPA_AFTER:
+            if (!pmFPAfileFreeData(file, view)) {
+                psError(PS_ERR_IO, false, "failed FREE in FPA_AFTER block for %s", file->name);
+                status = false;
+            }
+            break;
+        default:
+            psAbort(PS_FILE_LINE, "You can't get here");
+        }
+    }
+    psFree (iter);
+    return status;
+}
+
Index: trunk/psModules/src/camera/pmFPAfileIO.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.h	(revision 7589)
+++ trunk/psModules/src/camera/pmFPAfileIO.h	(revision 7589)
@@ -0,0 +1,42 @@
+/** @file  pmFPAview.h
+*
+*  @brief Tools to manipulate the FPA structure elements.
+*
+*  @ingroup AstroImage
+*
+*  @author EAM, IfA
+*
+*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-06-17 01:50:43 $
+*
+*  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
+*/
+
+#ifndef PM_FPA_FILE_IO_H
+#define PM_FPA_FILE_IO_H
+
+// open the real file corresponding to the given pmFPAfile appropriate to the current view
+bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view, pmConfig *config);
+
+// read from the real file corresponding to the given pmFPAfile for the current view
+bool pmFPAfileRead (pmFPAfile *file, const pmFPAview *view, pmConfig *config);
+
+bool pmFPAfileCreate (pmFPAfile *file, const pmFPAview *view);
+
+// write to the real file corresponding to the given pmFPAfile for the current view
+bool pmFPAfileWrite (pmFPAfile *file, const pmFPAview *view, pmConfig *config);
+
+// close the real file corresponding to the given pmFPAfile appropriate to the current view
+bool pmFPAfileClose (pmFPAfile *file, const pmFPAview *view);
+
+// free the data at this level
+bool pmFPAfileFreeData(pmFPAfile *file, const pmFPAview *view);
+
+// set the state of the specified pmFPAfile to active (state == true) or inactive
+// if name is NULL, set the state for all pmFPAfiles
+bool pmFPAfileActivate (psMetadata *files, bool state, char *name);
+
+// examine all pmFPAfiles listed in the files and perform the needed I/O operations (open,read,write,close)
+bool pmFPAfileIOChecks (pmConfig *config, const pmFPAview *view, pmFPAfilePlace place);
+
+# endif
Index: trunk/psModules/src/camera/pmFPAview.c
===================================================================
--- trunk/psModules/src/camera/pmFPAview.c	(revision 7555)
+++ trunk/psModules/src/camera/pmFPAview.c	(revision 7589)
@@ -3,6 +3,6 @@
  *  @author EAM, IfA
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-06-02 00:55:22 $
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-17 01:50:43 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -38,18 +38,18 @@
 }
 
-pmFPAdepth pmFPAviewDepth(const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(view, PM_FPA_DEPTH_NONE);
-
-    if (view->chip < 0) {
-        return PM_FPA_DEPTH_FPA;
-    }
-    if (view->cell < 0) {
-        return PM_FPA_DEPTH_CHIP;
-    }
-    if (view->readout < 0) {
-        return PM_FPA_DEPTH_CELL;
-    }
-    return PM_FPA_DEPTH_READOUT;
+pmFPALevel pmFPAviewLevel(const pmFPAview *view)
+{
+    PS_ASSERT_PTR_NON_NULL(view, PM_FPA_LEVEL_NONE);
+
+    if (view->chip < 0) {
+        return PM_FPA_LEVEL_FPA;
+    }
+    if (view->cell < 0) {
+        return PM_FPA_LEVEL_CHIP;
+    }
+    if (view->readout < 0) {
+        return PM_FPA_LEVEL_CELL;
+    }
+    return PM_FPA_LEVEL_READOUT;
 }
 
Index: trunk/psModules/src/camera/pmFPAview.h
===================================================================
--- trunk/psModules/src/camera/pmFPAview.h	(revision 7555)
+++ trunk/psModules/src/camera/pmFPAview.h	(revision 7589)
@@ -7,6 +7,6 @@
 *  @author EAM, IfA
 *
-*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-05-01 01:55:43 $
+*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-06-17 01:50:43 $
 *
 *  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
@@ -20,13 +20,4 @@
 /// @addtogroup AstroImage
 /// @{
-
-// depth of interest
-typedef enum {
-    PM_FPA_DEPTH_NONE,
-    PM_FPA_DEPTH_FPA,
-    PM_FPA_DEPTH_CHIP,
-    PM_FPA_DEPTH_CELL,
-    PM_FPA_DEPTH_READOUT,
-} pmFPAdepth;
 
 typedef struct
@@ -43,6 +34,6 @@
 pmFPAview *pmFPAviewAlloc (int nRows);
 
-// determine the current view depth
-pmFPAdepth pmFPAviewDepth (const pmFPAview *view);
+// determine the current view level
+pmFPALevel pmFPAviewLevel (const pmFPAview *view);
 
 // return the currently selected chip for this view
