Index: /trunk/psphot/src/psphot.c
===================================================================
--- /trunk/psphot/src/psphot.c	(revision 24143)
+++ /trunk/psphot/src/psphot.c	(revision 24144)
@@ -1,8 +1,3 @@
 # include "psphotStandAlone.h"
-
-static void usage (void) {
-    fprintf (stderr, "USAGE: psphot [-file image(s)] [-list imagelist] (output)\n");
-    exit (PS_EXIT_CONFIG_ERROR);
-}
 
 int main (int argc, char **argv) {
@@ -14,8 +9,5 @@
     // load command-line arguments, options, and system config data
     pmConfig *config = psphotArguments (argc, argv);
-    if (!config) {
-        psErrorStackPrint(stderr, "Error reading arguments\n");
-        usage ();
-    }
+    assert(config);
 
     psphotVersionPrint();
Index: /trunk/psphot/src/psphotArguments.c
===================================================================
--- /trunk/psphot/src/psphotArguments.c	(revision 24143)
+++ /trunk/psphot/src/psphotArguments.c	(revision 24144)
@@ -1,3 +1,99 @@
 # include "psphotStandAlone.h"
+
+static void writeHelpInfo(const char* program, pmConfig* config, FILE* ofile)
+{
+  fprintf(ofile,
+	  "Usage: one of the following\n"
+	  "%s -file fname1[,fname2,...] -mask maskfile1[,maskfile2,...]\n"
+	  "     -variance varfile1[,varfile2,...] OutFileBaseName\n"
+	  "\n"
+	  "%s -list FileNameList [-masklist MaskFileNameList] \n"
+	  "     -variancelist VarFileNameList OutFileBaseName\n"
+	  "\n"
+	  "%s -help\n"
+	  "\n"
+	  "%s -version\n"
+	  "\n"
+	  "where:\n"
+	  "  FileNameList is a text file containing filenames, one per line\n"
+	  "  MaskFileNameList is a text file of mask filenames, one per line\n"
+	  "  VarFileNameList is a text file of variance filenames, one per line\n"
+	  "  OutFileBaseName is the 'root name' for output files\n"
+	  "\n"
+	  "additional options:\n"
+	  "  -modeltest xObj yObj [-model DEFAULT|ModelName] \n"
+	  "        [-fitmode DEFAULT|PSF|CONV] [-fitset FitFileName]\n"
+	  "     Test fit for object at the given coordinates.  ModelName\n"
+	  "     is one of PS_MODEL_GAUSS, PS_MODEL_PGAUSS, PS_MODEL_QGAUSS,\n"
+	  "     PS_MODEL_RGAUSS, PS_MODEL_PS1_V1, or PS_MODEL_SERSIC.\n"
+	  "     FitFileName is a file of x,y,Io triples.\n"
+	  "  -psf PsfFile1[,PsfFile2,...] or -psflist PsfFileNameList\n"
+	  "     specify PSF rather than letting %s estimate it\n"
+	  "  -src SrcFile1[,SrcFile2,...] or -srclist SrcFileNameList\n"
+	  "     specify additional sources for PSF generation\n"
+	  "  -chip nn[,nn,...]\n"
+	  "     select detector chips to process; default is all.\n"
+	  "     Indices correspond to zero-based offset in the FPA metadata table.\n"
+	  "  -photcode PhotoCodeName\n"
+	  "     specify photocode\n"
+	  "  -region RegionString\n"
+	  "     specify analysis region.  String is of form '[x0:x1,y0:y1]'\n"
+	  "     To use this option you must define a default in psphot.config\n"
+	  "  -visual\n"
+	  "     turns on interactive display mode\n"
+	  "  -dumpconfig CfgFileName\n"
+          "     causes config info to be dumped to the named file.\n"
+	  "  -break NOTHING|BACKMDL|PEAKS|MOMENTS|PSFMODEL|ENSEMBLE|PASS1\n"
+	  "     choose a point at which to exit processing early\n"
+	  "  -nthreads n\n"
+	  "     set number of parallel threads of execution\n"
+	  "  -F OldFileRule ReplacementFileRule\n"
+	  "     change file naming rule; e.g. '-F PSPHOT.OUTPUT PSPHOT.OUT.CMF.MEF'\n"
+	  "  -D name stringval\n"
+	  "     set a string-valued config parameter\n"
+	  "  -Di name intval\n"
+	  "     set an integer-valued config parameter\n"
+	  "  -Df name fval\n"
+	  "     set a float-valued config parameter\n"
+	  "  -Db name boolval\n"
+	  "     set a boolean-valued config parameter\n"
+	  "  -v, -vv, -vvv\n"
+	  "     set increasing levels of verbosity\n"
+	  "  -logfmt FormatString\n"
+	  "     set format string used for log messages\n"
+	  "  -trace Fac Lvl\n"
+	  "     set tracing for facility Fac to integer Lvl, e.g. '-trace err 10'\n"
+	  "  -trace-levels\n"
+	  "     print current trace levels\n",
+	  program,program,program,program,program);
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+    exit(PS_EXIT_SUCCESS);
+}
+
+static void usage(const char *program,  // Name of the program
+                  psMetadata *arguments, // Command-line arguments
+                  pmConfig *config,      // Configuration
+		  int exitCode
+		  ) 
+{
+  fprintf(stderr,
+	  "Usage: one of the following\n"
+	  "%s -file fname1[,fname2,...] -mask maskfile1[,maskfile2,...]\n"
+	  "     -variance varfile1[,varfile2,...] OutFileBaseName\n"
+	  "\n"
+	  "%s -list FileNameList [-masklist MaskFileNameList] \n"
+	  "     -variancelist VarFileNameList OutFileBaseName\n"
+	  "\n"
+	  "Try '%s -help' for more options and explanation\n",
+	  program,program,program);
+    if (exitCode != PS_EXIT_SUCCESS)
+      psErrorStackPrint(stderr, "Error reading arguments\n");
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+    exit(exitCode);
+}
 
 pmConfig *psphotArguments(int argc, char **argv) {
@@ -5,17 +101,4 @@
     int N;
     bool status;
-
-    if (argc == 1) {
-        psError(PSPHOT_ERR_ARGUMENTS, true, "Too few arguments: %d", argc);
-        return NULL;
-    }
-
-    if ((N = psArgumentGet (argc, argv, "-version"))) {
-        psString version;
-        version = psphotVersionLong();    fprintf (stdout, "%s\n", version); psFree (version);
-        version = psModulesVersionLong(); fprintf (stdout, "%s\n", version); psFree (version);
-        version = psLibVersionLong();     fprintf (stdout, "%s\n", version); psFree (version);
-        exit (0);
-    }
 
     // load config data from default locations
@@ -23,6 +106,8 @@
     if (config == NULL) {
         psError(PSPHOT_ERR_CONFIG, false, "Can't read site configuration");
-        return NULL;
-    }
+	exit(PS_EXIT_CONFIG_ERROR);
+    }
+
+    PSARGUMENTS_INSTANTIATE_GENERICS( psphot, config, argc, argv );
 
     // save the following additional recipe values based on command-line options
@@ -30,18 +115,15 @@
     psMetadata *options = pmConfigRecipeOptions (config, PSPHOT_RECIPE);
 
-    // Number of threads
-    if ((N = psArgumentGet(argc, argv, "-threads"))) {
-        psArgumentRemove(N, &argc, argv);
-        int nThreads = atoi(argv[N]);
-        psMetadataAddS32(config->arguments, PS_LIST_TAIL, "NTHREADS", 0, "number of psphot threads", nThreads);
-        psArgumentRemove(N, &argc, argv);
-
-        // create the thread pool with number of desired threads, supplying our thread launcher function
-        psThreadPoolInit (nThreads);
-    }
-    psphotSetThreads();
+    // Number of threads is handled
+    PSARGUMENTS_INSTANTIATE_THREADSARG( psphot, config, argc, argv )
 
     // run the test model (requires X,Y coordinate)
     if ((N = psArgumentGet (argc, argv, "-modeltest"))) {
+        if (argc<=N+2) {
+          psError(PSPHOT_ERR_ARGUMENTS, true, 
+		  "Expected to see 2 more arguments; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
+
         psMetadataAddBool (options, PS_LIST_TAIL, "TEST_FIT",   0, "", true);
         psMetadataAddF32  (options, PS_LIST_TAIL, "TEST_FIT_X", 0, "", atof(argv[N+1]));
@@ -54,4 +136,9 @@
         // specify the modeltest model
         if ((N = psArgumentGet (argc, argv, "-model"))) {
+	    if (argc<=N+1) {
+	      psError(PSPHOT_ERR_ARGUMENTS, true, 
+		      "Expected to see 1 more argument; saw %d", argc - 1);
+	      exit(PS_EXIT_CONFIG_ERROR);
+	    }
             psArgumentRemove (N, &argc, argv);
             psMetadataAddStr (options, PS_LIST_TAIL, "TEST_FIT_MODEL", 0, "", argv[N]);
@@ -61,4 +148,9 @@
         // specify the test fit mode
         if ((N = psArgumentGet (argc, argv, "-fitmode"))) {
+	    if (argc<=N+1) {
+	      psError(PSPHOT_ERR_ARGUMENTS, true, 
+		      "Expected to see 1 more argument; saw %d", argc - 1);
+	      exit(PS_EXIT_CONFIG_ERROR);
+	    }
             psArgumentRemove (N, &argc, argv);
             psMetadataAddStr (options, PS_LIST_TAIL, "TEST_FIT_MODE", 0, "", argv[N]);
@@ -66,4 +158,9 @@
         }
         if ((N = psArgumentGet (argc, argv, "-fitset"))) {
+	    if (argc<=N+1) {
+	      psError(PSPHOT_ERR_ARGUMENTS, true, 
+		      "Expected to see 1 more argument; saw %d", argc - 1);
+	      exit(PS_EXIT_CONFIG_ERROR);
+	    }
             psArgumentRemove (N, &argc, argv);
             psMetadataAddStr (options, PS_LIST_TAIL, "TEST_FIT_SET", 0, "", argv[N]);
@@ -74,4 +171,9 @@
     // photcode : used in output to supplement header data (argument or recipe?)
     if ((N = psArgumentGet (argc, argv, "-photcode"))) {
+        if (argc<=N+1) {
+	  psError(PSPHOT_ERR_ARGUMENTS, true, 
+		  "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
         psArgumentRemove (N, &argc, argv);
         psMetadataAddStr (options, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "", argv[N]);
@@ -87,13 +189,11 @@
     // break : used from recipe throughout psphotReadout
     if ((N = psArgumentGet (argc, argv, "-break"))) {
+	if (argc<=N+1) {
+	  psError(PSPHOT_ERR_ARGUMENTS, true, 
+		  "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
         psArgumentRemove (N, &argc, argv);
         psMetadataAddStr (options, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", argv[N]);
-        psArgumentRemove (N, &argc, argv);
-    }
-
-    // fitmode : used from recipe throughout psphotReadout
-    if ((N = psArgumentGet (argc, argv, "-fitmode"))) {
-        psArgumentRemove (N, &argc, argv);
-        psMetadataAddStr (options, PS_LIST_TAIL, "FITMODE", PS_META_REPLACE, "", argv[N]);
         psArgumentRemove (N, &argc, argv);
     }
@@ -101,4 +201,9 @@
     // analysis region : overrides recipe value, used in psphotReadout/psphotEnsemblePSF
     if ((N = psArgumentGet (argc, argv, "-region"))) {
+	if (argc<=N+1) {
+	  psError(PSPHOT_ERR_ARGUMENTS, true, 
+		  "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
         psArgumentRemove (N, &argc, argv);
         psMetadataAddStr (options, PS_LIST_TAIL, "ANALYSIS_REGION", 0, "", argv[N]);
@@ -108,4 +213,9 @@
     // chip selection is used to limit chips to be processed
     if ((N = psArgumentGet (argc, argv, "-chip"))) {
+	if (argc<=N+1) {
+	  psError(PSPHOT_ERR_ARGUMENTS, true, 
+		  "Expected to see 1 more argument; saw %d", argc - 1);
+	  exit(PS_EXIT_CONFIG_ERROR);
+	}
         psArgumentRemove (N, &argc, argv);
         psMetadataAddStr (config->arguments, PS_LIST_TAIL, "CHIP_SELECTIONS", PS_DATA_STRING, "", argv[N]);
@@ -121,14 +231,23 @@
     pmConfigFileSetsMD (config->arguments, &argc, argv, "SRC",    "-src",    "-srclist");
 
+    if (argc == 1) {
+        psError(PSPHOT_ERR_ARGUMENTS, true, "Too few arguments: %d", argc);
+	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
+    }
+
+    if (psArgumentGet(argc, argv, "-help")
+	|| psArgumentGet(argc, argv, "-h"))
+      writeHelpInfo(argv[0], config, stdout);
+      
     // the input file is a required argument; if not found, we will exit
     status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
     if (!status) {
         psError(PSPHOT_ERR_ARGUMENTS, false, "pmConfigFileSetsMD failed to parse arguments");
-        return NULL;
+	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
     }
 
     if (argc != 2) {
         psError(PSPHOT_ERR_ARGUMENTS, true, "Expected to see one more argument; saw %d", argc - 1);
-        return NULL;
+	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
     }
 
Index: /trunk/psphot/src/psphotCleanup.c
===================================================================
--- /trunk/psphot/src/psphotCleanup.c	(revision 24143)
+++ /trunk/psphot/src/psphotCleanup.c	(revision 24144)
@@ -2,4 +2,13 @@
 
 void psphotCleanup (pmConfig *config) {
+
+    // Dump configuration if requested
+    bool status;
+    psString dump_file = psMetadataLookupStr(&status, config->arguments, "DUMP_CONFIG");
+    if (dump_file) {
+        (void)pmConfigCamerasCull(config,NULL);
+	(void)pmConfigRecipesCull(config,NULL);
+        pmConfigDump(config, dump_file);
+    }
 
     psFree (config);
