Index: /trunk/psModules/src/config/pmConfig.c
===================================================================
--- /trunk/psModules/src/config/pmConfig.c	(revision 7675)
+++ /trunk/psModules/src/config/pmConfig.c	(revision 7676)
@@ -3,6 +3,6 @@
  *  @author PAP, IfA
  *
- *  @version $Revision: 1.26 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-06-21 03:05:53 $
+ *  @version $Revision: 1.27 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-24 03:25:14 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -35,5 +35,5 @@
 }
 
-pmConfig *pmConfigAlloc(void)
+pmConfig *pmConfigAlloc(int argc, char **argv)
 {
     pmConfig *config = psAlloc(sizeof(pmConfig));
@@ -46,4 +46,6 @@
     config->arguments = NULL;
     config->database = NULL;
+    config->argc = argc;
+    config->argv = argv;
 
     // the file structure is used to carry pmFPAfiles
@@ -166,11 +168,11 @@
  *****************************************************************************/
 pmConfig *pmConfigRead(
-    int *argc,
+    int argc,
     char **argv)
 {
-    PS_ASSERT_INT_POSITIVE(*argc, false);
+    PS_ASSERT_INT_POSITIVE(argc, false);
     PS_ASSERT_PTR_NON_NULL(argv, false);
 
-    pmConfig *config = pmConfigAlloc(); // The configuration, containing site, camera and recipes
+    pmConfig *config = pmConfigAlloc(argc, argv); // The configuration, containing site, camera and recipes
 
     //
@@ -183,5 +185,5 @@
     // First, try command line
     //
-    psS32 argNum = psArgumentGet(*argc, argv, "-site");
+    psS32 argNum = psArgumentGet(config->argc, config->argv, "-site");
     if (argNum != 0) {
         //
@@ -190,11 +192,11 @@
         // remove it as well.
         //
-        psArgumentRemove(argNum, argc, argv);
-        if (argNum >= *argc) {
+        psArgumentRemove(argNum, &config->argc, config->argv);
+        if (argNum >= config->argc) {
             psLogMsg(__func__, PS_LOG_WARN,
                      "-site command-line switch provided without the required filename --- ignored.\n");
         } else {
-            siteName = psStringCopy(argv[argNum]);
-            psArgumentRemove(argNum, argc, argv);
+            siteName = psStringCopy(config->argv[argNum]);
+            psArgumentRemove(argNum, &config->argc, config->argv);
         }
     }
@@ -250,13 +252,13 @@
     // file is read and parsed into psMetadata struct "camera".
     //
-    argNum = psArgumentGet(*argc, argv, "-camera");
+    argNum = psArgumentGet(config->argc, config->argv, "-camera");
     if (argNum > 0) {
-        psArgumentRemove(argNum, argc, argv);
-        if (argNum >= *argc) {
+        psArgumentRemove(argNum, &config->argc, config->argv);
+        if (argNum >= config->argc) {
             psLogMsg(__func__, PS_LOG_WARN,
                      "-camera command-line switch provided without the required camera or filename --- "
                      "ignored.\n");
         } else {
-            char *cameraFile = argv[argNum]; // The camera configuration file to read
+            char *cameraFile = config->argv[argNum]; // The camera configuration file to read
 
             // look for a symbolic camera name in the CAMERAS metadata
@@ -277,5 +279,5 @@
 
             readConfig(&config->camera, cameraFile, "camera");
-            psArgumentRemove(argNum, argc, argv);
+            psArgumentRemove(argNum, &config->argc, config->argv);
         }
     }
@@ -328,15 +330,16 @@
 
 
-    argNum = psArgumentGet(*argc, argv, "-log");
+    argNum = psArgumentGet(config->argc, config->argv, "-log");
     if (argNum > 0) {
-        psArgumentRemove(argNum, argc, argv);
-        if (argNum >= *argc) {
+        psArgumentRemove(argNum, &config->argc, config->argv);
+        if (argNum >= config->argc) {
             psLogMsg(__func__, PS_LOG_WARN,
                      "-log command-line switch provided without the required log destination --- ignored.\n");
         } else {
-            if (!psLogSetDestination(psMessageDestination(argv[argNum]))) {
-                psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n", argv[argNum]);
-            }
-            psArgumentRemove(argNum, argc, argv);
+            if (!psLogSetDestination(psMessageDestination(config->argv[argNum]))) {
+                psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n",
+                         config->argv[argNum]);
+            }
+            psArgumentRemove(argNum, &config->argc, config->argv);
         }
     } else {
@@ -351,5 +354,6 @@
             // expanded in the future to do files, and perhaps even sockets.
             if (!psLogSetDestination(psMessageDestination(logDest))) {
-                psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n", argv[argNum]);
+                psLogMsg(__func__, PS_LOG_WARN, "Unable to set log destination to %s\n",
+                         config->argv[argNum]);
             }
         }
@@ -384,5 +388,5 @@
     //
     psS32 saveLogLevel = psLogGetLevel();
-    psArgumentVerbosity(argc, argv);
+    psArgumentVerbosity(&config->argc, config->argv);
     // XXX: substitute the string for the default log level for "2".
     if (2 == psLogGetLevel()) {
@@ -498,5 +502,5 @@
 psMetadata *pmConfigCameraFormatFromHeader(
     pmConfig *config,                   // The configuration
-    const psMetadata *header           // The FITS header
+    const psMetadata *header            // The FITS header
 )
 {
@@ -599,10 +603,50 @@
 }
 
-bool pmConfigReadRecipes(
-    pmConfig *config
-)
+
+// Read the recipe filenames
+static bool recipeFileNames(psMetadata *target, // The target metadata into which to read the recipes
+                            psMetadata *source, // The source configuration, from which to read the filenames
+                            const char *sourceName // The name of the source, for error messages
+                           )
+{
+    assert(target);
+
+    if (!source) {
+        psLogMsg(__func__, PS_LOG_WARN, "The %s has not been read --- cannot read recipes from this "
+                 "location.\n", sourceName);
+        return false;
+    }
+
+    bool mdok = true;                   // Status of MD lookup
+    psMetadata *recipes = psMetadataLookupMD(&mdok, source, "RECIPES"); // The list of recipes
+    if (!mdok || !recipes) {
+        psLogMsg(__func__, PS_LOG_WARN, "RECIPES in the %s is not of type METADATA --- ignored\n",
+                 sourceName);
+        return false;
+    }
+
+    // Copy the filenames to the target from the "RECIPES" in the source.
+    // We could use psMetadataCopy for this, but it's better to check that everything's of the correct type.
+    // If it's not of the correct type, we can tell the user which file it's in, so they can find it easier.
+    psMetadataIterator *recipesIter = psMetadataIteratorAlloc(recipes, PS_LIST_HEAD, NULL); // Iterator
+    psMetadataItem *fileItem = NULL;    // MD item containing the filename, from recipe iteration
+    while ((fileItem = psMetadataGetAndIncrement(recipesIter))) {
+        if (fileItem->type != PS_DATA_STRING) {
+            psLogMsg(__func__, PS_LOG_WARN, "Recipe %s from %s is not of type STR --- ignored.\n",
+                     fileItem->name, sourceName);
+            continue;
+        }
+        psMetadataAddItem(target, fileItem, PS_LIST_TAIL, PS_META_REPLACE);
+    }
+    psFree(recipesIter);
+
+    return true;
+}
+
+
+bool pmConfigReadRecipes(pmConfig *config
+                        )
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_PTR_NON_NULL(config->camera, false);
 
     if (!config->recipes) {
@@ -611,11 +655,43 @@
 
     bool mdok = true;                   // Status of MD lookup
-    psMetadata *recipes = psMetadataLookupMD(&mdok, config->camera, "RECIPES"); // The list of recipes
-    if (! mdok || ! recipes) {
-        psLogMsg(__func__, PS_LOG_WARN, "RECIPES in the camera configuration file is not of type METADATA\n");
-        return false;
-    }
-    // Go through the recipes and load each one
-    psMetadataIterator *recipesIter = psMetadataIteratorAlloc(recipes, PS_LIST_HEAD, NULL); // Iterator
+
+    // Read the recipe file names from the site configuration and camera configuration
+    recipeFileNames(config->recipes, config->site, "site configuration");
+    recipeFileNames(config->recipes, config->camera, "camera configuration");
+
+    // Go through the command-line arguments
+    int argNum; // Argument number for "-recipe"
+    while ((argNum = psArgumentGet(config->argc, config->argv, "-recipe")) > 0) {
+        psArgumentRemove(argNum, &config->argc, config->argv);
+        if (argNum + 1 >= config->argc) {
+            psLogMsg(__func__, PS_LOG_WARN, "-recipe command-line switch provided without the "
+                     "required recipe and source --- ignored.\n");
+            if (argNum == config->argc) {
+                // Remove the single last argument (we required two, they gave us one)
+                psArgumentRemove(argNum, &config->argc, config->argv);
+            }
+            continue;
+        }
+
+        const char *recipeName = psStringCopy(config->argv[argNum]); // Name of the recipe
+        psArgumentRemove(argNum, &config->argc, config->argv);
+        const char *recipeSource = psStringCopy(config->argv[argNum]); // Source of the recipe
+        psArgumentRemove(argNum, &config->argc, config->argv);
+
+        // Is the source a symbolic reference?
+        const char *recipeFile = psMetadataLookupStr(&mdok, config->recipes, recipeSource);
+        if (mdok && recipeFile && strlen(recipeFile) > 0) {
+            psString comment = psStringCopy("Recipe added from command line as symbolic link to ");
+            psStringAppend(&comment, "%s", recipeSource);
+            psMetadataAddStr(config->recipes, PS_LIST_TAIL, recipeName, PS_META_REPLACE, comment, recipeFile);
+        } else {
+            // Otherwise, treat the source as a filename
+            psMetadataAddStr(config->recipes, PS_LIST_TAIL, recipeName, PS_META_REPLACE,
+                             "Recipe added from command line", recipeSource);
+        }
+    }
+
+    // Read the recipes
+    psMetadataIterator *recipesIter = psMetadataIteratorAlloc(config->recipes, PS_LIST_HEAD, NULL);// Iterator
     psMetadataItem *recipesItem = NULL; // Item from iteration
     while ((recipesItem = psMetadataGetAndIncrement(recipesIter))) {
@@ -625,5 +701,4 @@
             continue;
         }
-
         psMetadata *recipe = NULL;      // Recipe from file
         if (readConfig(&recipe, recipesItem->data.V, "recipe")) {
@@ -705,9 +780,9 @@
 // given the 'file' and 'list' words, find the arguments associated with these words
 // and interpret them as lists of files.  return an array of the resulting filenames.
-psArray *pmConfigFileSets (int *argc, char **argv, char *file, char *list)
-{
-    PS_ASSERT_PTR_NON_NULL(argc, NULL);
-    PS_ASSERT_INT_NONNEGATIVE(*argc, NULL);
-    PS_ASSERT_PTR_NON_NULL(argv, NULL);
+psArray *pmConfigFileSets(pmConfig *config, char *file, char *list)
+{
+    PS_ASSERT_INT_NONNEGATIVE(config->argc, NULL);
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->argv, NULL);
     PS_ASSERT_PTR_NON_NULL(file, NULL);
     PS_ASSERT_INT_POSITIVE(strlen(file), NULL);
@@ -722,12 +797,12 @@
 
     // load the list of filenames the supplied file (may be a glob: "file*.fits")
-    if ((Narg = psArgumentGet (*argc, argv, file))) {
+    if ((Narg = psArgumentGet (config->argc, config->argv, file))) {
         glob_t globList;
-        psArgumentRemove (Narg, argc, argv);
+        psArgumentRemove (Narg, &config->argc, config->argv);
         globList.gl_offs = 0;
-        glob (argv[Narg], 0, NULL, &globList);
+        glob (config->argv[Narg], 0, NULL, &globList);
 
         if (globList.gl_pathc == 0) {
-            psError(PS_ERR_IO, true, "No match for %s", argv[Narg]);
+            psError(PS_ERR_IO, true, "No match for %s", config->argv[Narg]);
             return input;
         }
@@ -738,9 +813,9 @@
             psFree (filename);
         }
-        psArgumentRemove (Narg, argc, argv);
+        psArgumentRemove (Narg, &config->argc, config->argv);
     }
 
     // load the list from the supplied text file
-    if ((Narg = psArgumentGet (*argc, argv, list))) {
+    if ((Narg = psArgumentGet (config->argc, config->argv, list))) {
         int nItems;
         char line[1024]; // XXX limits the list lines to 1024 chars
@@ -748,6 +823,6 @@
         char *filename;
 
-        psArgumentRemove (Narg, argc, argv);
-        FILE *f = fopen (argv[Narg], "r");
+        psArgumentRemove (Narg, &config->argc, config->argv);
+        FILE *f = fopen (config->argv[Narg], "r");
         if (f == NULL) {
             psAbort ("psphot", "unable to open specified list file");
@@ -769,5 +844,5 @@
             }
         }
-        psArgumentRemove (Narg, argc, argv);
+        psArgumentRemove (Narg, &config->argc, config->argv);
     }
 
@@ -775,10 +850,10 @@
 }
 
-bool pmConfigFileSetsMD (psMetadata *metadata, int *argc, char **argv, char *name, char *file, char *list)
+bool pmConfigFileSetsMD (psMetadata *metadata, pmConfig *config, char *name, char *file, char *list)
 {
     PS_ASSERT_PTR_NON_NULL(metadata, false);
-    PS_ASSERT_PTR_NON_NULL(argc, false);
-    PS_ASSERT_INT_NONNEGATIVE(*argc, NULL);
-    PS_ASSERT_PTR_NON_NULL(argv, false);
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_INT_NONNEGATIVE(config->argc, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->argv, false);
     PS_ASSERT_PTR_NON_NULL(name, false);
     PS_ASSERT_INT_POSITIVE(strlen(name), NULL);
@@ -790,5 +865,5 @@
     psErrorClear();   // pmConfigFileSets may or may not call psError, so
     // if files->n == 0 we'll want to call psError(..., false, ...)
-    psArray *files = pmConfigFileSets (argc, argv, file, list);
+    psArray *files = pmConfigFileSets(config, file, list);
     if (files->n == 0) {
         // psError(PS_ERR_IO, false, "pmConfigFileSets failed to find %s in the argument list", name);
Index: /trunk/psModules/src/config/pmConfig.h
===================================================================
--- /trunk/psModules/src/config/pmConfig.h	(revision 7675)
+++ /trunk/psModules/src/config/pmConfig.h	(revision 7676)
@@ -3,6 +3,6 @@
  *  @author PAP, IfA
  *
- *  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-06-17 01:50:43 $
+ *  @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-24 03:25:14 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -20,12 +20,15 @@
     psMetadata *camera;                 // Camera specification
     psMetadata *recipes;                // Recipes for processing
-    psMetadata *arguments;              // Command-line arguments
+    psMetadata *arguments;              // Processed command-line arguments
     psMetadata *files;                  // pmFPAfiles used for analysis
-    //    psMetadata *format;   // camera format for primary image
     psDB *database;                     // Database handle
+    int argc;                           // Number of command-line arguments
+    char **argv;                        // Command-line arguments (raw version)
 }
 pmConfig;
 
-pmConfig *pmConfigAlloc(void);
+pmConfig *pmConfigAlloc(int argc,       // Number of command-line arguments
+                        char **argv     // Command-line arguments
+                       );
 
 void pmConfigSet(const char *path); // set the configPath
@@ -51,5 +54,5 @@
  */
 pmConfig *pmConfigRead(
-    int *argc,
+    int argc,
     char **argv);
 
@@ -90,5 +93,5 @@
 psMetadata *pmConfigCameraByName(
     pmConfig *config,                   // The configuration
-    const char *cameraName   // The camera name header
+    const char *cameraName                      // The camera name header
 );
 
@@ -99,7 +102,6 @@
  *
  */
-bool pmConfigReadRecipes(
-    pmConfig *config
-);
+bool pmConfigReadRecipes(pmConfig *config // Configuration
+                        );
 
 /** pmConfigDB
@@ -123,6 +125,6 @@
 
 
-psArray *pmConfigFileSets (int *argc, char **argv, char *file, char *list);
-bool pmConfigFileSetsMD (psMetadata *metadata, int *argc, char **argv, char *name, char *file, char *list);
+psArray *pmConfigFileSets(pmConfig *config, char *file, char *list);
+bool pmConfigFileSetsMD (psMetadata *metadata, pmConfig *config, char *name, char *file, char *list);
 
 
