Index: trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.c	(revision 23574)
+++ trunk/psModules/src/camera/pmFPAfileIO.c	(revision 23576)
@@ -635,4 +635,74 @@
 }
 
+psString pmFPAfileName(const pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, NULL);
+    PS_ASSERT_PTR_NON_NULL(view, NULL);
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psString filename = pmFPAfileNameFromRule(file->filerule, file, view); // Filename, based on rule
+    if (!filename) {
+        psError(PS_ERR_IO, true, "Cannot determine file name from rule");
+        return false;
+    }
+
+    // indirect filenames: these come from a list on the command line or elsewhere
+    if (!strcasecmp(filename, "@FILES")) {
+        psString filesrc = pmFPAfileNameFromRule(file->filesrc, file, view); // Source of file name
+        if (!filesrc) {
+            psError(PS_ERR_IO, false, "error converting filesrc to name %s", file->filesrc);
+            return false;
+        }
+        psFree(filename);
+        filename = psMemIncrRefCounter(psMetadataLookupStr(NULL, file->names, filesrc));
+        if (!filename) {
+            psError(PS_ERR_IO, false, "filename lookup error (@FILES) for %s : %s", file->filesrc, filesrc);
+            psFree(filesrc);
+            return false;
+        }
+        psFree(filesrc);
+    }
+
+    // get name from detrend database
+    // file->detrend->detID contains the desired -det_id detID -iteration iter string
+    if (!strcasecmp(filename, "@DETDB")) {
+        if (!file->detrend) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find information about selected detrend.");
+            return false;
+        }
+        psMetadata *menu = psMetadataLookupMetadata(NULL, file->camera, "CLASSID"); // Menu of class IDs
+        if (!menu) {
+            psError(PS_ERR_IO, false, "Unable to find CLASSID metadata in camera configuration");
+            return false;
+        }
+        const char *rule = psMetadataLookupStr(NULL, menu, file->detrend->level); // Rule for class_id
+        if (!rule || strlen(rule) == 0) {
+            psError(PS_ERR_IO, false, "Unable to find %s in CLASSID in camera configuration",
+                    file->detrend->level);
+            return false;
+        }
+        psString classId = pmFPAfileNameFromRule(rule, file, view); // The class identifier, for pmDetrendFile
+        if (!classId) {
+            psError(PS_ERR_IO, false, "error converting CLASSID rule to name: %s\n", rule);
+            return false;
+        }
+
+        psTrace("psModules.camera", 6, "looking for detrend (%s, %s)\n", file->detrend->detID, classId);
+        psFree(filename);
+        filename = pmDetrendFile(file->detrend->detID, classId, config);
+        if (!filename) {
+            psError(PS_ERR_IO, false, "failed to find a valid detrend image for detID %s : classID %s",
+                    file->detrend->detID, classId);
+            psFree(classId);
+            return false;
+        }
+
+        psTrace("psModules.camera", 6, "got detrend file %s", filename);
+        psFree(classId);
+    }
+
+    return filename;
+}
+
 // open file (if not already opened).
 // this function is only called only within pmFPAfileRead or pmFPAfileWrite.
@@ -672,68 +742,9 @@
 
     // 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: these come from a list on the command line or elsewhere
-    if (!strcasecmp (file->filename, "@FILES")) {
-        char *filesrc = pmFPAfileNameFromRule (file->filesrc, file, view);
-        if (filesrc == NULL) {
-            psError(PS_ERR_IO, false, "error converting filesrc to name %s\n", file->filesrc);
-            return false;
-        }
-
-        psFree (file->filename);
-        file->filename = psMetadataLookupStr (&status, file->names, filesrc);
-
-        if (file->filename == NULL) {
-            psError(PS_ERR_IO, true, "filename lookup error (@FILES) for %s : %s\n", file->filesrc, filesrc);
-            psFree (filesrc);
-            return false;
-        }
-        // psMetadataLookupStr just returns a view, file->filename must be protected
-        psMemIncrRefCounter (file->filename);
-        psFree (filesrc);
-    }
-
-    // get name from detrend database
-    // file->detrend->detID contains the desired -det_id detID -iteration iter string
-    if (!strcasecmp (file->filename, "@DETDB")) {
-        if (!file->detrend) {
-            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find information about selected detrend.");
-            return false;
-        }
-
-        psString classId = NULL;        // The class identifier, to pass to pmDetrendFile
-        psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "CLASSID"); // Menu of class IDs
-        if (!status || !menu) {
-            psError(PS_ERR_IO, false, "Unable to find CLASSID metadata in camera configuration");
-            return false;
-        }
-        const char *rule = psMetadataLookupStr(&status, menu, file->detrend->level); // Rule for class_id
-        if (!status || !rule || strlen(rule) == 0) {
-            psError(PS_ERR_IO, false, "Unable to find %s in CLASSID in camera configuration", file->detrend->level);
-            return false;
-        }
-        classId = pmFPAfileNameFromRule(rule, file, view);
-        if (!classId) {
-            psError(PS_ERR_IO, false, "error converting CLASSID rule to name: %s\n", rule);
-            return false;
-        }
-        psTrace ("psModules.camera", 6, "looking for detrend (%s, %s)\n", file->detrend->detID, classId);
-        psFree (file->filename);
-
-        file->filename = pmDetrendFile(file->detrend->detID, classId, config);
-        if (file->filename == NULL) {
-            psError(PS_ERR_IO, false, "failed to find a valid detrend image for detID %s : classID %s\n", file->detrend->detID, classId);
-            psFree (classId);
-            return false;
-        }
-
-        psTrace ("psModules.camera", 6, "got detrend file %s\n", file->filename);
-        psFree (classId);
+    psFree(file->filename);
+    file->filename = pmFPAfileName(file, view, config);
+    if (!file->filename) {
+        psError(PS_ERR_IO, true, "Unable to determine filename");
+        return false;
     }
 
Index: trunk/psModules/src/camera/pmFPAfileIO.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.h	(revision 23574)
+++ trunk/psModules/src/camera/pmFPAfileIO.h	(revision 23576)
@@ -15,4 +15,7 @@
 /// @addtogroup Camera Camera Layout
 /// @{
+
+// Determine appropriate file name
+psString pmFPAfileName(const pmFPAfile *file, const pmFPAview *view, pmConfig *config);
 
 // open the real file corresponding to the given pmFPAfile appropriate to the current view
