Index: /trunk/archive/scripts/Makefile
===================================================================
--- /trunk/archive/scripts/Makefile	(revision 4900)
+++ /trunk/archive/scripts/Makefile	(revision 4901)
@@ -15,5 +15,5 @@
 LIBS	= 	-lpsmodule $(LPSLIB)
 CFLAGS	=	$(INCS) -std=c99
-LFLAGS	=	$(LIBS) -static
+LFLAGS	=	$(LIBS)
 
 PSPHOT = \
Index: /trunk/psphot/Makefile
===================================================================
--- /trunk/psphot/Makefile	(revision 4900)
+++ /trunk/psphot/Makefile	(revision 4901)
@@ -3,5 +3,5 @@
 	@echo "USAGE: make psphot"
 
-CC      =       gcc -g -Wall
+CC      =       gcc -g -Wall -O2
 SRC     =       src
 BIN     =       bin
@@ -36,5 +36,7 @@
 $(SRC)/fit_galaxies.$(ARCH).o \
 $(SRC)/LocalSky.$(ARCH).o \
-$(SRC)/basic_classes.$(ARCH).o
+$(SRC)/basic_classes.$(ARCH).o \
+$(SRC)/psLine.$(ARCH).o \
+$(SRC)/output.$(ARCH).o
 
 FITSOURCE = \
Index: /trunk/psphot/src/LocalSky.c
===================================================================
--- /trunk/psphot/src/LocalSky.c	(revision 4900)
+++ /trunk/psphot/src/LocalSky.c	(revision 4901)
@@ -18,13 +18,9 @@
     //  psImage *subImageNoise = psImageSubset(imdata->noise, srcRegion);
 
-    psImage *subImage = psImageSubset(imdata->image, srcRegion->x0, srcRegion->y0, srcRegion->x1, srcRegion->y1);
-    psImage *subImageMask = psImageSubset(imdata->mask, srcRegion->x0, srcRegion->y0, srcRegion->x1, srcRegion->y1);
-    psImage *subImageNoise = psImageSubset(imdata->noise, srcRegion->x0, srcRegion->y0, srcRegion->x1, srcRegion->y1);
-
-    mySource->pixels = subImage;
-    mySource->mask = subImageMask;
-    mySource->noise = subImageNoise;
+    mySource->pixels = psImageSubset(imdata->image, srcRegion->x0, srcRegion->y0, srcRegion->x1, srcRegion->y1);
+    mySource->noise  = psImageSubset(imdata->noise, srcRegion->x0, srcRegion->y0, srcRegion->x1, srcRegion->y1);
+    mySource->mask   = psImageSubset(imdata->mask,  srcRegion->x0, srcRegion->y0, srcRegion->x1, srcRegion->y1);
+
     psFree (srcRegion);
-
     return(mySource);
 }
@@ -48,10 +44,12 @@
     myStats = psImageStats(myStats, image, mask, 0xff);
     psImageMaskRegion (mask, srcRegion, AND, 0x7f);
-    psFree (srcRegion);
 
     psF64 tmpF64;
     p_psGetStatValue(myStats, &tmpF64);
+
+    psFree (myStats);
+    psFree (srcRegion);
+
     if (isnan(tmpF64)) return (false);
-
     source->moments = pmMomentsAlloc();
     source->moments->Sky = (psF32) tmpF64;
Index: /trunk/psphot/src/apply_psf_model.c
===================================================================
--- /trunk/psphot/src/apply_psf_model.c	(revision 4900)
+++ /trunk/psphot/src/apply_psf_model.c	(revision 4901)
@@ -14,4 +14,5 @@
     int   Niter = 0;
 
+    psMemoryId id = psMemGetId ();
     psTimerStart ("psphot");
 
@@ -33,4 +34,5 @@
 
     for (int i = 0; i < sources->n; i++) {
+
 	psSource *source = sources->data[i];
 
@@ -39,16 +41,12 @@
 	if (source->type == PS_SOURCE_SATURATED) continue;
 
-	// do I even need to test?
-	if (source->modelPSF != NULL) {
-	  psFree (source->modelPSF);
-	}
-
 	// use the source moments, etc to guess basic model parameters
-	psModel *model  = pmSourceModelGuess (source, psf->type); 
+	psModel *modelFLT  = pmSourceModelGuess (source, psf->type); 
 
 	// set PSF parameters for this model
-	model  = psModelFromPSF (model, psf);
+	psModel *model  = psModelFromPSF (modelFLT, psf);
 	x = model->params->data.F32[2];
 	y = model->params->data.F32[3];
+	psFree (modelFLT);
 
 	// set the fit radius based on the object flux limit and the model
@@ -72,4 +70,5 @@
 	  psLogMsg ("psphot", 3, "PSF fit failed for %f, %f (%d iterations)\n", x, y, model->nIter);
 	  source->type = PS_SOURCE_FAIL_FIT_PSF;  // better choice?
+	  psFree (model);
 	  continue;
 	}
Index: /trunk/psphot/src/basic_classes.c
===================================================================
--- /trunk/psphot/src/basic_classes.c	(revision 4900)
+++ /trunk/psphot/src/basic_classes.c	(revision 4901)
@@ -6,6 +6,8 @@
 
     // group into STAR, COSMIC, GALAXY, SATURATED
+    // XXX - this has 1 leak
     psfClump = pmSourcePSFClump (sources, config);
     pmSourceRoughClass (sources, config, psfClump);
+
     return (true);
 }
Index: /trunk/psphot/src/choose_psf_model.c
===================================================================
--- /trunk/psphot/src/choose_psf_model.c	(revision 4900)
+++ /trunk/psphot/src/choose_psf_model.c	(revision 4901)
@@ -7,5 +7,5 @@
     bool        status;
     char       *modelName;
-    char        key[64], filename[64];
+    char        key[64];
     pmPSF_Test *test  = NULL;
     psArray    *stars = NULL;
@@ -31,6 +31,7 @@
     psArray *tests = psArrayAlloc (Ntest);
     for (int i = 0; i < tests->n; i++) { 
-	sprintf (key, "PSF_MODEL_%d", i);
+	snprintf (key, 64, "PSF_MODEL_%d", i);
 	modelName = psMetadataLookupPtr (&status, config, key);
+
 	tests->data[i] = pmPSF_TestModel (stars, modelName, RADIUS);
 	psFree (modelName);
@@ -55,9 +56,11 @@
 	}
     }
+    // keep only the selected test:
     test = tests->data[bestN];
     modelName = psModelGetType (test->modelType);
     psLogMsg ("psphot.pspsf", 3, "selected psf model %s, ApResid: %f +/- %f\n", modelName, test->ApResid, test->dApResid);
-    psFree (modelName);
 
+    // XXX I am having trouble tracking down the double frees vs leaks
+    # if (0)
     // we are keeping the modelPSF fits from the PSF test, 
     // but we replace these later on (apply_psf_model)
@@ -70,13 +73,12 @@
 	  source->modelPSF = NULL;
 	} else {
+	  // source->modelPSF = psMemCopy(test->modelPSF->data[i]);
 	  source->modelPSF = test->modelPSF->data[i];
 	}
     }
-    pmPSF *psf = test->psf;
+    # endif
 
-    // free unused test models:
-    psFree (test);
-    psFree (stars);
-
+    pmPSF *psf = psMemCopy(test->psf);
+    psFree (tests);
     return (psf);
 }
Index: /trunk/psphot/src/find_peaks.c
===================================================================
--- /trunk/psphot/src/find_peaks.c	(revision 4900)
+++ /trunk/psphot/src/find_peaks.c	(revision 4901)
@@ -21,9 +21,10 @@
     psTimerStart ("psphot");
 
-    // find the peaks in the smoothed image 
+    // set peak threshold
     NSIGMA    = psMetadataLookupF32 (&status, config, "PEAK_NSIGMA");
     threshold = NSIGMA*sky->sampleStdev + sky->sampleMean;
     psLogMsg ("psphot", 3, "threshold: %f DN\n", threshold);
 
+    // find the peaks in the smoothed image 
     psArray *peaks = pmFindImagePeaks (smooth, threshold);
     if (peaks == NULL) psAbort ("find peaks", "no peaks found");
@@ -31,5 +32,5 @@
 
     // make this optional
-    DumpPeaks (peaks, "peaks.dat");
+    // DumpPeaks (peaks, "peaks.dat");
 
     psLogMsg ("psphot", 3, "%d peaks: %f sec\n", peaks->n, psTimerMark ("psphot"));
Index: /trunk/psphot/src/fit_galaxies.c
===================================================================
--- /trunk/psphot/src/fit_galaxies.c	(revision 4900)
+++ /trunk/psphot/src/fit_galaxies.c	(revision 4901)
@@ -24,4 +24,10 @@
 
     psTimerStart ("psphot");
+
+    float dt = 0;
+    float dT = 0;
+    float dT2 = 0;
+    int dTn = 0;
+
     for (int i = 0; i < sources->n; i++) {
 	psSource *source = sources->data[i];
@@ -72,5 +78,10 @@
 	// fit as FLT, not PSF (skip poor fits)
 	psImageKeepCircle (source->mask, x, y, model->radius, OR, 0x80);
+	psTimerStart ("galfit");
 	status = pmSourceFitModel_EAM (source, model, false);
+	dt = psTimerMark ("galfit");
+	dT += dt;
+	dT2 += dt*dt;
+	dTn ++;
 	psImageKeepCircle (source->mask, x, y, model->radius, AND, 0x7f);
 	if (!status) {
@@ -105,4 +116,6 @@
 
     }
+    dt = dT / dTn;
+    fprintf (stderr, "dt: %f +/- %f\n", dt, sqrt(dT2/dTn - PS_SQR(dt)));
     psLogMsg ("psphot", 3, "fit galaxies: %f sec for %d galaxies (%d failures, %d total iterations)\n", psTimerMark ("psphot"), Nfit, Nfail, Niter);
     return (true);
Index: /trunk/psphot/src/image_stats.c
===================================================================
--- /trunk/psphot/src/image_stats.c	(revision 4900)
+++ /trunk/psphot/src/image_stats.c	(revision 4901)
@@ -36,5 +36,5 @@
 	stats = psVectorStats (stats, subset, NULL, NULL, 0); // use a mask?
 	psFree (subset);
-	psFree (rnd)
+	psFree (rnd);
     }
 
@@ -52,4 +52,5 @@
     psLogMsg ("psphot", 3, "background: %f +/- %f\n", sky->sampleMean, sky->sampleStdev);
 
+    psFree (stats);
     return (sky);
 }
Index: /trunk/psphot/src/load_args.c
===================================================================
--- /trunk/psphot/src/load_args.c	(revision 4900)
+++ /trunk/psphot/src/load_args.c	(revision 4901)
@@ -36,4 +36,5 @@
 
   // load config information
+  // XXX - 3 leaks from this 
   psMetadata *config = psMetadataParseConfig (NULL, &Nfail, argv[3], FALSE);
 
Index: /trunk/psphot/src/output.c
===================================================================
--- /trunk/psphot/src/output.c	(revision 4900)
+++ /trunk/psphot/src/output.c	(revision 4901)
@@ -3,49 +3,89 @@
 // output functions: we have several fixed modes (sx, obj, cmp)
 
+static int GetDophotType (psSource *source) {
+
+    switch (source->type) {
+
+      case PS_SOURCE_DEFECT:
+      case PS_SOURCE_SATURATED:
+	return (8);
+
+      case PS_SOURCE_SATSTAR:
+	return (10);
+
+      case PS_SOURCE_PSFSTAR:
+      case PS_SOURCE_GOODSTAR:
+	return (1);
+
+      case PS_SOURCE_POOR_FIT_PSF:
+	return (7);
+
+      case PS_SOURCE_FAIL_FIT_PSF:
+      case PS_SOURCE_FAINTSTAR:
+	return (4);
+
+      case PS_SOURCE_GALAXY:
+      case PS_SOURCE_FAINT_GALAXY:
+      case PS_SOURCE_DROP_GALAXY:
+      case PS_SOURCE_FAIL_FIT_GAL:
+      case PS_SOURCE_POOR_FIT_GAL:
+	return (2);
+
+      case PS_SOURCE_OTHER:
+      default:
+	return (0);
+    }
+    return (0);
+}
+
 void output (psImageData *imdata, psMetadata *config, psArray *sources) {
 
-  char *outputMode = psMetadataLookupPtr (&status, config, "OUTPUT_MODE");
-
-  if (outputMode == NULL) {
-    WriteSourcesText (imdata, config, sources);
+    bool status;
+
+    char *outputMode = psMetadataLookupPtr (&status, config, "OUTPUT_MODE");
+
+    if (outputMode == NULL) {
+	WriteSourcesText (imdata, config, sources);
+	exit (0);
+    }
+
+    if (!strcasecmp (outputMode, "OBJ")) {
+	WriteSourcesOBJ (imdata, config, sources);
+	exit (0);
+    }
+  
+    if (!strcasecmp (outputMode, "SX")) {
+	WriteSourcesSX (imdata, config, sources);
+	exit (0);
+    }
+  
+    if (!strcasecmp (outputMode, "CMP")) {
+	WriteSourcesCMP (imdata, config, sources);
+	exit (0);
+    }
+  
+    if (!strcasecmp (outputMode, "CMF")) {
+	WriteSourcesCMF (imdata, config, sources);
+	exit (0);
+    }
+  
+    psAbort ("psphot", "unknown output mode %s", outputMode);
+}
+
+bool WriteSourcesText (psImageData *imdata, psMetadata *config, psArray *sources) {
+
+    bool status;
+
+    char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
+
+    DumpImage (imdata->image, filename);
+
+    // get these names from config?
+    DumpModelPSF (sources, "psfsources.dat");
+    DumpModelFLT (sources, "fltsources.dat");
+    DumpModelNULL (sources, "nullsources.dat");
+    DumpMoments (sources, "moments.dat");
+
     exit (0);
-  }
-
-  if (!strcasecmp (outputMode, "OBJ")) {
-    WriteSourcesOBJ (imdata, config, sources);
-    exit (0);
-  }
-  
-  if (!strcasecmp (outputMode, "SX")) {
-    WriteSourcesSX (imdata, config, sources);
-    exit (0);
-  }
-  
-  if (!strcasecmp (outputMode, "CMP")) {
-    WriteSourcesCMP (imdata, config, sources);
-    exit (0);
-  }
-  
-  if (!strcasecmp (outputMode, "CMF")) {
-    WriteSourcesCMF (imdata, config, sources);
-    exit (0);
-  }
-  
-  psAbort ("psphot", "unknown output mode %s", outputMode);
-}
-
-bool WriteSourceText (psImageData *imdata, psMetadata *config, psArray *sources) {
-
-  char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
-
-  DumpImage (imdata->image, filename);
-
-  // get these names from config?
-  DumpModelPSF (sources, "psfsources.dat");
-  DumpModelFLT (sources, "fltsources.dat");
-  DumpModelNULL (sources, "nullsources.dat");
-  DumpMoments (sources, "moments.dat");
-
-  exit (0);
 }
 
@@ -53,9 +93,62 @@
 bool WriteSourcesOBJ (psImageData *imdata, psMetadata *config, psArray *sources) {
 
-# define NCHAR 104
-
-    char line[NCHAR];
-
-    char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
+    int i, type;
+    bool status;
+    psModel *model;
+    psF32 *PAR, *dPAR;
+    float dmag, apMag, fitMag;
+
+    char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
+    psLine *line = psLineAlloc (104);  // 104 is dophot-defined line length
+
+    FILE *f = fopen (filename, "w");
+    if (f == NULL) {
+	psLogMsg ("WriteSourceOBJ", 3, "can't open output file for output %s\n", filename);
+	return false;
+    }
+
+    // write sources with models first 
+    for (i = 0; i < sources->n; i++) {
+	psSource *source = (psSource *) sources->data[i];
+	model = source->modelPSF;
+	if (model == NULL) continue;
+	PAR = model->params->data.F32;
+	dPAR = model->dparams->data.F32;
+
+	pmSourcePhotometry (&fitMag, &apMag, model, source->pixels, source->mask);
+	dmag = dPAR[1] / PAR[1];
+
+	type = GetDophotType (source);
+	psLineInit (line);
+	psLineAdd (line, "%3d", type);
+	psLineAdd (line, "%8.2f", PAR[2]);
+	psLineAdd (line, "%8.2f", PAR[3]);
+	psLineAdd (line, "%8.3f", fitMag);
+	psLineAdd (line, "%6.3f", dmag);
+	psLineAdd (line, "%9.2f", PAR[0]);
+	psLineAdd (line, "%9.3f", PAR[4]);
+	psLineAdd (line, "%9.3f", PAR[5]);
+	psLineAdd (line, "%7.2f", PAR[6]);
+	psLineAdd (line, "%8.3f", 32.0);
+	psLineAdd (line, "%8.3f", apMag);
+	psLineAdd (line, "%8.2f", apMag - fitMag);
+	fwrite (line->line, 1, line->Nline, f);
+    }
+    fclose (f);
+    return true;
+
+}
+
+// elixir/sextractor-style output list with fixed line width
+bool WriteSourcesSX (psImageData *imdata, psMetadata *config, psArray *sources) {
+
+    int i, type;
+    bool status;
+    psModel *model;
+    psF32 *PAR, *dPAR;
+    float dmag, apMag, fitMag;
+
+    char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
+    psLine *line = psLineAlloc (104);  // 104 is dophot-defined line length
 
     FILE *f = fopen (filename, "w");
@@ -70,38 +163,42 @@
 	model = (psModel  *) source->modelPSF;
 	if (model == NULL) continue;
-	params = model->params;
-	dparams = model->dparams;
+	PAR = model->params->data.F32;
+	dPAR = model->dparams->data.F32;
 
 	pmSourcePhotometry (&fitMag, &apMag, model, source->pixels, source->mask);
-	dmag = dparams[0].data.F32[1] / params[0].data.F32[1];
-
+	dmag = dPAR[1] / PAR[1];
+
+	// XXX EAM : fix this to match sextractor output
 	type = GetDophotType (source);
-	init_line (line, &Nline);
-	add_to_line (line, &Nline, "%3d", type);
-	add_to_line (line, &Nline, "%8.2f", params[0].data.F32[2]);
-	add_to_line (line, &Nline, "%8.2f", params[0].data.F32[3]);
-	add_to_line (line, &Nline, "%8.3f", fitMag);
-	add_to_line (line, &Nline, "%6.3f", dmag);
-	add_to_line (line, &Nline, "%9.2f", params[0].data.F32[0]);
-	add_to_line (line, &Nline, "%9.3f", params[0].data.F32[4]);
-	add_to_line (line, &Nline, "%9.3f", params[0].data.F32[5]);
-	add_to_line (line, &Nline, "%7.2f", params[0].data.F32[6]);
-	add_to_line (line, &Nline, "%8.3f", 32.0);
-	add_to_line (line, &Nline, "%8.3f", apMag);
-	add_to_line (line, &Nline, "%8.2f", apMag - fitMag);
+	psLineInit (line);
+	psLineAdd (line, "%3d", type);
+	psLineAdd (line, "%8.2f", PAR[2]);
+	psLineAdd (line, "%8.2f", PAR[3]);
+	psLineAdd (line, "%8.3f", fitMag);
+	psLineAdd (line, "%6.3f", dmag);
+	psLineAdd (line, "%9.2f", PAR[0]);
+	psLineAdd (line, "%9.3f", PAR[4]);
+	psLineAdd (line, "%9.3f", PAR[5]);
+	psLineAdd (line, "%7.2f", PAR[6]);
+	psLineAdd (line, "%8.3f", 32.0);
+	psLineAdd (line, "%8.3f", apMag);
+	psLineAdd (line, "%8.2f", apMag - fitMag);
+	fwrite (line->line, 1, line->Nline, f);
     }
     fclose (f);
     return true;
-
-}
-
-// elixir/sextractor-style output list with fixed line width
-bool WriteSourcesSX (psImageData *imdata, psMetadata *config, psArray *sources) {
-
-# define NCHAR 104
-
-    char line[NCHAR];
-
-    char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
+}
+
+// elixir-style pseudo FITS table (header + ascii list)
+bool WriteSourcesCMP (psImageData *imdata, psMetadata *config, psArray *sources) {
+
+    int i, type;
+    bool status;
+    psModel *model;
+    psF32 *PAR, *dPAR;
+    float dmag, apMag, fitMag;
+
+    char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
+    psLine *line = psLineAlloc (104);  // 104 is dophot-defined line length
 
     FILE *f = fopen (filename, "w");
@@ -110,4 +207,6 @@
 	return false;
     }
+
+    // write imdata->header to file
 
     // write sources with models first 
@@ -116,75 +215,26 @@
 	model = (psModel  *) source->modelPSF;
 	if (model == NULL) continue;
-	params = model->params;
-	dparams = model->dparams;
+	PAR = model->params->data.F32;
+	dPAR = model->dparams->data.F32;
 
 	pmSourcePhotometry (&fitMag, &apMag, model, source->pixels, source->mask);
-	dmag = dparams[0].data.F32[1] / params[0].data.F32[1];
+	dmag = dPAR[1] / PAR[1];
 
 	// XXX EAM : fix this to match sextractor output
 	type = GetDophotType (source);
-	init_line (line, &Nline);
-	add_to_line (line, &Nline, "%3d", type);
-	add_to_line (line, &Nline, "%8.2f", params[0].data.F32[2]);
-	add_to_line (line, &Nline, "%8.2f", params[0].data.F32[3]);
-	add_to_line (line, &Nline, "%8.3f", fitMag);
-	add_to_line (line, &Nline, "%6.3f", dmag);
-	add_to_line (line, &Nline, "%9.2f", params[0].data.F32[0]);
-	add_to_line (line, &Nline, "%9.3f", params[0].data.F32[4]);
-	add_to_line (line, &Nline, "%9.3f", params[0].data.F32[5]);
-	add_to_line (line, &Nline, "%7.2f", params[0].data.F32[6]);
-	add_to_line (line, &Nline, "%8.3f", 32.0);
-	add_to_line (line, &Nline, "%8.3f", apMag);
-	add_to_line (line, &Nline, "%8.2f", apMag - fitMag);
-    }
-    fclose (f);
-    return true;
-
-}
-
-// elixir-style pseudo FITS table (header + ascii list)
-bool WriteSourcesCMP (psImageData *imdata, psMetadata *config, psArray *sources) {
-
-
-# define NCHAR 104
-
-    char line[NCHAR];
-
-    char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
-
-    FILE *f = fopen (filename, "w");
-    if (f == NULL) {
-	psLogMsg ("WriteSourceOBJ", 3, "can't open output file for output %s\n", filename);
-	return false;
-    }
-
-    // write imdata->header to file
-
-    // write sources with models first 
-    for (i = 0; i < sources->n; i++) {
-	psSource *source = (psSource *) sources->data[i];
-	model = (psModel  *) source->modelPSF;
-	if (model == NULL) continue;
-	params = model->params;
-	dparams = model->dparams;
-
-	pmSourcePhotometry (&fitMag, &apMag, model, source->pixels, source->mask);
-	dmag = dparams[0].data.F32[1] / params[0].data.F32[1];
-
-	// XXX EAM : fix this to match sextractor output
-	type = GetDophotType (source);
-	init_line (line, &Nline);
-	add_to_line (line, &Nline, "%3d", type);
-	add_to_line (line, &Nline, "%8.2f", params[0].data.F32[2]);
-	add_to_line (line, &Nline, "%8.2f", params[0].data.F32[3]);
-	add_to_line (line, &Nline, "%8.3f", fitMag);
-	add_to_line (line, &Nline, "%6.3f", dmag);
-	add_to_line (line, &Nline, "%9.2f", params[0].data.F32[0]);
-	add_to_line (line, &Nline, "%9.3f", params[0].data.F32[4]);
-	add_to_line (line, &Nline, "%9.3f", params[0].data.F32[5]);
-	add_to_line (line, &Nline, "%7.2f", params[0].data.F32[6]);
-	add_to_line (line, &Nline, "%8.3f", 32.0);
-	add_to_line (line, &Nline, "%8.3f", apMag);
-	add_to_line (line, &Nline, "%8.2f", apMag - fitMag);
+	psLineInit (line);
+	psLineAdd (line, "%3d", type);
+	psLineAdd (line, "%8.2f", PAR[2]);
+	psLineAdd (line, "%8.2f", PAR[3]);
+	psLineAdd (line, "%8.3f", fitMag);
+	psLineAdd (line, "%6.3f", dmag);
+	psLineAdd (line, "%9.2f", PAR[0]);
+	psLineAdd (line, "%9.3f", PAR[4]);
+	psLineAdd (line, "%9.3f", PAR[5]);
+	psLineAdd (line, "%7.2f", PAR[6]);
+	psLineAdd (line, "%8.3f", 32.0);
+	psLineAdd (line, "%8.3f", apMag);
+	psLineAdd (line, "%8.2f", apMag - fitMag);
+	fwrite (line->line, 1, line->Nline, f);
     }
     fclose (f);
@@ -195,4 +245,6 @@
 bool WriteSourcesCMF (psImageData *imdata, psMetadata *config, psArray *sources) {
 
+    bool status;
+
     char *filename = psMetadataLookupPtr (&status, config, "OUTPUT");
 
@@ -200,18 +252,5 @@
 
     // write FITS table to file (use autocode tools)
-}
-
-// we require a fixed number of chars already allocated
-init_line (char *line, int *Nline) {
-  *Nline = 0;
-}
-
-add_to_line (char *line, int *Nline, char *format, ...) {
-
-    va_list ap;
-
-    va_start (ap, format);
-    Nchar = vsprintf (&line[*Nline], format, ap);
-    *Nline += Nchar;
-}
-
+
+    return true;
+}
Index: /trunk/psphot/src/psPolynomials.c
===================================================================
--- /trunk/psphot/src/psPolynomials.c	(revision 4900)
+++ /trunk/psphot/src/psPolynomials.c	(revision 4901)
@@ -42,4 +42,13 @@
 }
 
+static void psPolynomial1DFree (psPolynomial1D *poly) {
+
+  if (poly == NULL) return;
+  psFree (poly->coeff);
+  psFree (poly->coeffErr);
+  psFree (poly->mask);
+  return;
+}
+
 // XXX EAM : use Nterm = Norder + 1 definition  
 // XXX EAM : should we provide both order and nterms in struct?
@@ -54,7 +63,4 @@
 
     newPoly = (psPolynomial1D* ) psAlloc(sizeof(psPolynomial1D));
-    // p_psMemSetDeallocator(newPoly, (psFreeFcn) polynomial1DFree);
-    // XXX EAM : me, being lazy
-
     newPoly->type = type;
     newPoly->n = nOrder;
@@ -67,4 +73,5 @@
         newPoly->mask[i] = 0;
     }
+    p_psMemSetDeallocator(newPoly, (psFreeFcn) psPolynomial1DFree);
     return(newPoly);
 }
@@ -185,4 +192,7 @@
 	    myPoly->coeff[k] = coeffs->data.F64[k];
 	}
+	psFree (ALUD);
+	psFree (outPerm);
+	psFree (coeffs);
     }
 
@@ -262,4 +272,18 @@
 }
 
+static void psPolynomial2DFree(psPolynomial2D *poly) {
+
+  if (poly == NULL) return;
+  for (int i = 0; i < poly->nX + 1; i++) {
+    psFree (poly->coeff[i]);
+    psFree (poly->coeffErr[i]);
+    psFree (poly->mask[i]);
+  }
+  psFree (poly->coeff);
+  psFree (poly->coeffErr);
+  psFree (poly->mask);
+  return;
+}
+
 // XXX EAM : use Nterm = Norder + 1 definition  
 // the user requests a polynomial of order Norder
@@ -277,7 +301,4 @@
 
     newPoly = (psPolynomial2D* ) psAlloc(sizeof(psPolynomial2D));
-    // p_psMemSetDeallocator(newPoly, (psFreeFcn) polynomial2DFree);
-    // XXX EAM : me, being lazy
-
     newPoly->type = type;
     newPoly->nX = nXorder;
@@ -299,4 +320,5 @@
         }
     }
+    p_psMemSetDeallocator(newPoly, (psFreeFcn) psPolynomial2DFree);
     return(newPoly);
 }
Index: /trunk/psphot/src/psUtils.c
===================================================================
--- /trunk/psphot/src/psUtils.c	(revision 4900)
+++ /trunk/psphot/src/psUtils.c	(revision 4901)
@@ -2,4 +2,21 @@
 
 static psHash *timers = NULL;
+
+bool psTimerClear (char *name) {
+
+  bool status;
+
+  if (name == NULL) return false;
+
+  status = psHashRemove (timers, name);
+  return (status);
+}
+
+void psTimerFree () {
+
+  psFree (timers);
+  p_psTimeFinalize();
+  return;
+}
 
 // start/restart a named timer
@@ -11,7 +28,6 @@
 
     start = psTimeGetTime (PS_TIME_UTC);
-
     psHashAdd (timers, name, start);
-
+    psFree (start); 
     return (TRUE);
 }
@@ -31,4 +47,7 @@
     mark = psTimeGetTime (PS_TIME_UTC);
     delta = psTimeDelta (mark, start);
+    psFree (mark);
+    // psFree (start); -- XXX is psHashLookup not psMemCopying?
+
     return (delta);
 }
@@ -191,4 +210,5 @@
 	    }
 	    *status = true;
+	    // psFree (item);
 	    return (value);
 	}	
@@ -198,4 +218,5 @@
     if (item->type == PS_META_F32) {
 	value = item->data.F32;
+	// psFree (item);
 	return (value);
     }
Index: /trunk/psphot/src/psphot-utils.c
===================================================================
--- /trunk/psphot/src/psphot-utils.c	(revision 4900)
+++ /trunk/psphot/src/psphot-utils.c	(revision 4901)
@@ -439,2 +439,26 @@
 
 # endif
+
+static void psImageDataFree (psImageData *imdata) {
+
+  if (imdata == NULL) return;
+
+  psFree (imdata->image);
+  psFree (imdata->header);
+  psFree (imdata->noise);
+  psFree (imdata->mask);
+  return;
+}
+
+psImageData *psImageDataAlloc (psImage *image, psImage *noise, psImage *mask, psMetadata *header) {
+  
+    psImageData *imdata = psAlloc(sizeof(psImageData));
+    imdata->image = image;
+    imdata->header = header;
+    imdata->noise = noise;
+    imdata->mask = mask;
+
+    p_psMemSetDeallocator(imdata, (psFreeFcn) psImageDataFree);
+    return (imdata);
+}
+  
Index: /trunk/psphot/src/psphot.c
===================================================================
--- /trunk/psphot/src/psphot.c	(revision 4900)
+++ /trunk/psphot/src/psphot.c	(revision 4901)
@@ -14,4 +14,5 @@
     // load input data (image and config)
     // create or load mask and noise images
+    // we have memory leaks here -- may be from psMetadata
     imdata = setup (config);
 
Index: /trunk/psphot/src/psphot.h
===================================================================
--- /trunk/psphot/src/psphot.h	(revision 4900)
+++ /trunk/psphot/src/psphot.h	(revision 4901)
@@ -31,8 +31,16 @@
 } pmPSF_Test;
 
+// structure to carry a dynamic string
+typedef struct {
+  int NLINE;
+  int Nline;
+  char *line;
+} psLine;
+
 // used by mask operations
 # define AND true
 # define OR false
 
+# define psMemCopy(A)(psMemIncrRefCounter((A)))
 
 // top-level psphot functions
@@ -71,4 +79,12 @@
 bool DumpImage (psImage *image, char *filename);
 bool DumpPSFTestData (pmPSF_Test *test, char *filename);
+void output (psImageData *imdata, psMetadata *config, psArray *sources);
+bool WriteSourcesText (psImageData *imdata, psMetadata *config, psArray *sources);
+bool WriteSourcesOBJ (psImageData *imdata, psMetadata *config, psArray *sources);
+bool WriteSourcesSX (psImageData *imdata, psMetadata *config, psArray *sources);
+bool WriteSourcesCMP (psImageData *imdata, psMetadata *config, psArray *sources);
+bool WriteSourcesCMF (psImageData *imdata, psMetadata *config, psArray *sources);
+bool init_line (char *line, int *Nline);
+bool add_to_line (char *line, int *Nline, char *format, ...);
 
 // psphot utilities
@@ -86,4 +102,5 @@
 psBool psMinimizeLMChi2_EAM(psMinimization *min, psImage *covar, psVector *params, const psVector *paramMask, const psArray *x, const psVector *y, const psVector *yErr, psMinimizeLMChi2Func func);
 psF64 p_psMinLM_dLinear (const psVector *Beta, const psVector *beta, psF64 lambda);
+psImageData *psImageDataAlloc (psImage *image, psImage *noise, psImage *mask, psMetadata *header);
 
 // fitsource utilities
@@ -110,4 +127,6 @@
 // utilities
 bool psTimerStart (char *name);
+void psTimerFree ();
+bool psTimerClear (char *name);
 psF64 psTimerMark (char *name);
 psS32 psLogArguments (int *argc, char **argv);
@@ -117,4 +136,9 @@
 psF32 pmConfigLookupF32 (bool *status, psMetadata *config, psMetadata *header, char *name);
 psVector *psVectorCreate (double lower, double upper, double delta, psElemType type);
+
+// psLine functions
+psLine *psLineAlloc (int Nline);
+bool psLineInit (psLine *line);
+bool psLineAdd (psLine *line, char *format, ...);
 
 // polynomial functions
Index: /trunk/psphot/src/pspsf.c
===================================================================
--- /trunk/psphot/src/pspsf.c	(revision 4900)
+++ /trunk/psphot/src/pspsf.c	(revision 4901)
@@ -1,3 +1,11 @@
 # include "psphot.h"
+
+static void pmPSFFree (pmPSF *psf) {
+
+  if (psf == NULL) return;
+
+  psFree (psf->params);
+  return;
+}
 
 // a PSF always has 4 parameters fewer than the equivalent model
@@ -16,4 +24,5 @@
 	return(NULL);
     }      
+
     psf->params = psArrayAlloc (Nparams - 4);
     for (int i = 0; i < psf->params->n; i++) {
@@ -21,6 +30,21 @@
 	psf->params->data[i] = Polynomial2DAlloc(1, 1, PS_POLYNOMIAL_ORD);
     }
-    // set the destructors
+
+    p_psMemSetDeallocator(psf, (psFreeFcn) pmPSFFree);
     return(psf);
+}
+
+static void pmPSF_TestFree (pmPSF_Test *test) {
+
+  if (test == NULL) return;
+
+  psFree (test->psf);
+  psFree (test->sources);
+  psFree (test->modelFLT);
+  psFree (test->modelPSF);
+  psFree (test->metric);
+  psFree (test->fitMag);
+  psFree (test->mask);
+  return;
 }
 
@@ -32,5 +56,5 @@
     test->modelType   = psModelSetType (modelName);
     test->psf         = pmPSFAlloc (test->modelType);
-    test->sources     = sources;
+    test->sources     = psMemCopy(sources);
     test->modelFLT    = psArrayAlloc (sources->n);
     test->modelPSF    = psArrayAlloc (sources->n);
@@ -49,6 +73,6 @@
 	test->fitMag->data.F64[i] = 0;
     }	
-    // set the destructors
-
+
+    p_psMemSetDeallocator(test, (psFreeFcn) pmPSF_TestFree);
     return (test);
 }
@@ -74,4 +98,5 @@
     psTimerStart ("fit");
     for (int i = 0; i < test->sources->n; i++) {
+
 	psSource *source = test->sources->data[i];
 	psModel  *model  = pmSourceModelGuess (source, test->modelType); 
@@ -88,4 +113,5 @@
 	if (!status) {
 	  test->mask->data.U8[i] = 2;
+	  psFree (model);
 	  continue;
 	}
@@ -122,4 +148,5 @@
 	if (!status) {
 	    test->mask->data.U8[i] = 3;
+	    psFree (modelPSF);
 	    goto next_source;
 	}
@@ -154,4 +181,5 @@
     psLogMsg ("psphot.pspsf", 3, "test model %s, ap-fit: %f +/- %f, sky bias: %f\n", 
 	      modelName, test->ApResid, test->dApResid, test->skyBias);
+
     return (test);
 }
@@ -223,5 +251,4 @@
   float dBin;
   int   nKeep, nSkip;
-  
 
   // the measured (aperture - fit) magnitudes (dA == test->metric)
@@ -280,4 +307,5 @@
     if (tmp->n < 2) {
       maskB->data.U8[i] = 1;
+      psFree (tmp);
       continue;
     } 
@@ -327,7 +355,8 @@
   test->skyBias = poly->coeff[1] / (M_PI * PS_SQR(RADIUS));
 
-  psFree (maskB);
+  psFree (rflux);
   psFree (rfBin);
   psFree (daBin);
+  psFree (maskB);
   psFree (daBinFit);
   psFree (daResid);
Index: /trunk/psphot/src/setup.c
===================================================================
--- /trunk/psphot/src/setup.c	(revision 4900)
+++ /trunk/psphot/src/setup.c	(revision 4901)
@@ -29,4 +29,6 @@
     image = psFitsReadImage (NULL, file, region, 0);
     psFree (file);
+    // psFree (input);
+    // XXX - does the current API expect to get a copy or a view?
 
     // grab these values from the approrpiate location (image header if necessary)
@@ -42,4 +44,5 @@
       noise = psFitsReadImage  (NULL, file, region, 0);
       psFree (file);
+      // psFree (noiseName); XXX - see psFree (input)
     } else {
 
@@ -73,4 +76,5 @@
       mask  = psFitsReadImage  (NULL, file, region, 0);
       psFree (file);
+      // psFree (maskName); XXX - see psFree (input)
       // XXX require / convert mask to psU8?
     } else {
@@ -96,13 +100,9 @@
 	}
     }
+
     psLogMsg ("psphot", 3, "load data: %f sec\n", psTimerMark ("psphot"));
 
     // save the image data & return it
-    psImageData *imdata = psAlloc(sizeof(psImageData));
-    imdata->image = image;
-    imdata->header = header;
-    imdata->noise = noise;
-    imdata->mask = mask;
-
+    psImageData *imdata = psImageDataAlloc(image, noise, mask, header);
     return (imdata);
 }
Index: /trunk/psphot/src/source_moments.c
===================================================================
--- /trunk/psphot/src/source_moments.c	(revision 4900)
+++ /trunk/psphot/src/source_moments.c	(revision 4901)
@@ -5,4 +5,6 @@
     bool     status  = false;
     psArray *sources = NULL;
+
+    psMemoryId id = psMemGetId ();
 
     psTimerStart ("psphot");
@@ -17,19 +19,28 @@
 
     for (int i = 0; i < peaks->n; i++) {
+
 	// create a new source, add peak
 	psSource *source = pmSourceAlloc();
-	source->peak = (psPeak *)peaks->data[i];
+	source->peak = (psPeak *)psMemCopy(peaks->data[i]);
 
 	// allocate image, noise, mask arrays for each peak (square of radius OUTER)
+	// XXX - this has 12 leaks (v.5)
 	pmSourceDefinePixels (source, imdata, source->peak->x, source->peak->y, OUTER);
 
 	// this should use ROBUST not SAMPLE median, but it is broken
 	status = pmSourceLocalSky_EAM (source, PS_STAT_SAMPLE_MEDIAN, INNER);
-	if (!status) continue;
+	if (!status) {
+	  psFree (source);
+	  continue;
+	}
 
 	status = pmSourceMoments (source, RADIUS);
-	if (!status) continue;
+	if (!status) {
+	  psFree (source);
+	  continue;
+	}
 	
 	psArrayAdd (sources, 100, source);
+	psFree (source);
     }
 
