Index: trunk/Ohana/src/addstar/Makefile
===================================================================
--- trunk/Ohana/src/addstar/Makefile	(revision 38543)
+++ trunk/Ohana/src/addstar/Makefile	(revision 38553)
@@ -24,4 +24,5 @@
 sedstar      : $(BIN)/sedstar.$(ARCH)
 load2mass    : $(BIN)/load2mass.$(ARCH)
+loadgalphot  : $(BIN)/loadgalphot.$(ARCH)
 loadstarpar  : $(BIN)/loadstarpar.$(ARCH)
 loadstarpar_client : $(BIN)/loadstarpar_client.$(ARCH)
@@ -36,11 +37,33 @@
 mkcmf        : $(BIN)/mkcmf.$(ARCH)
 
-all: addstar addstar_client sedstar load2mass loadstarpar loadstarpar_client loadICRF loadICRF_client skycells mkcmf loadwise loadtycho loadsupercos dumpskycells findskycell
-
-INSTALL = addstar addstar_client sedstar load2mass loadstarpar loadstarpar_client loadICRF loadICRF_client skycells mkcmf loadwise loadtycho loadsupercos dumpskycells findskycell
+# programs in 'OTHERS' have not been updated since moving from Stars to Catalog as an internal carrier
+# programs in 'SERVER' use the client-server concept and are out of date
+
+INSTALL = addstar sedstar loadstarpar loadstarpar_client loadICRF loadICRF_client skycells mkcmf dumpskycells findskycell
+OTHERS  = load2mass loadwise loadtycho loadsupercos
+SERVER  = addstar_client addstarc addstard addstart
+
+old: $(OTHERS)
+all: $(INSTALL)
 
 # I need to fix the client/server version of addstar now that I have dropped Stars
 # as an autocode type and have converted to carrying average and measure
-# all: addstar addstarc addstard addstart sedstar load2mass skycells
+# all: addstar sedstar load2mass skycells
+
+# $(SRC)/find_matches.$(ARCH).o \
+# $(SRC)/find_matches_closest.$(ARCH).o \
+# $(SRC)/find_matches_refstars.$(ARCH).o \
+# $(SRC)/find_matches_closest_refstars.$(ARCH).o \
+# $(SRC)/find_subset.$(ARCH).o \
+# $(SRC)/getgsc.$(ARCH).o \
+# $(SRC)/getusno.$(ARCH).o \
+# $(SRC)/getusnob.$(ARCH).o \
+# $(SRC)/greference.$(ARCH).o \
+# $(SRC)/grefstars.$(ARCH).o \
+# $(SRC)/dump.$(ARCH).o \
+# $(SRC)/ReadStarsTEXT.$(ARCH).o \
+# $(SRC)/StarOps.$(ARCH).o \
+# $(SRC)/replace_match.$(ARCH).o \
+# 
 
 ADDSTAR = \
@@ -56,18 +79,10 @@
 $(SRC)/build_links.$(ARCH).o \
 $(SRC)/calibrate.$(ARCH).o \
-$(SRC)/dump.$(ARCH).o \
 $(SRC)/edge_check.$(ARCH).o \
 $(SRC)/fakeimage.$(ARCH).o \
 $(SRC)/find_matches.$(ARCH).o \
 $(SRC)/find_matches_closest.$(ARCH).o \
-$(SRC)/find_matches_refstars.$(ARCH).o \
-$(SRC)/find_matches_closest_refstars.$(ARCH).o \
-$(SRC)/find_subset.$(ARCH).o \
-$(SRC)/getgsc.$(ARCH).o \
-$(SRC)/getusno.$(ARCH).o \
-$(SRC)/getusnob.$(ARCH).o \
-$(SRC)/greference.$(ARCH).o \
-$(SRC)/grefstars.$(ARCH).o \
 $(SRC)/GetZeroPointExposure.$(ARCH).o \
+$(SRC)/LoadFilenames.$(ARCH).o \
 $(SRC)/LoadStars.$(ARCH).o \
 $(SRC)/LoadHeaders.$(ARCH).o \
@@ -81,12 +96,9 @@
 $(SRC)/opening_angle.$(ARCH).o \
 $(SRC)/parse_time.$(ARCH).o \
-$(SRC)/replace_match.$(ARCH).o \
 $(SRC)/resort_catalogs.$(ARCH).o \
 $(SRC)/resort_threaded.$(ARCH).o \
 $(SRC)/resort_unthreaded.$(ARCH).o \
 $(SRC)/resort_catalog.$(ARCH).o \
-$(SRC)/StarOps.$(ARCH).o \
 $(SRC)/ReadStarsFITS.$(ARCH).o \
-$(SRC)/ReadStarsTEXT.$(ARCH).o \
 $(SRC)/ReadStarsSDSS.$(ARCH).o \
 $(SRC)/ReadStarsUKIRT.$(ARCH).o \
@@ -100,4 +112,6 @@
 $(SRC)/update_coords.$(ARCH).o \
 $(SRC)/psps_ids.$(ARCH).o
+
+##
 
 # this is the client for parallel operations
@@ -244,4 +258,26 @@
 $(SRC)/psps_ids.$(ARCH).o
 
+LOAD-GALPHOT = \
+$(SRC)/loadgalphot.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/args_loadgalphot.$(ARCH).o \
+$(SRC)/find_matches_galphot.$(ARCH).o \
+$(SRC)/loadgalphot_catalog.$(ARCH).o \
+$(SRC)/loadgalphot_make_subset.$(ARCH).o \
+$(SRC)/loadgalphot_readstars.$(ARCH).o \
+$(SRC)/loadgalphot_fit2d.$(ARCH).o \
+$(SRC)/loadgalphot_join.$(ARCH).o \
+$(SRC)/loadgalphot_table.$(ARCH).o \
+$(SRC)/strhash.$(ARCH).o \
+$(SRC)/sortIDs.$(ARCH).o \
+$(SRC)/psps_ids.$(ARCH).o
+
+# $(SRC)/SkyRegionUtils.$(ARCH).o 
+# $(SRC)/loadstarpar_io.$(ARCH).o 
+# $(SRC)/loadgalphot_remote_hosts.$(ARCH).o 
+# $(SRC)/loadgalphot_save_remote.$(ARCH).o 
+
 LOAD-STARPAR = \
 $(SRC)/loadstarpar.$(ARCH).o \
@@ -338,5 +374,4 @@
 $(SRC)/find_matches_closest_refstars.$(ARCH).o \
 $(SRC)/build_links.$(ARCH).o \
-$(SRC)/replace_match.$(ARCH).o \
 $(SRC)/SetSignals.$(ARCH).o \
 $(SRC)/update_coords.$(ARCH).o \
@@ -404,4 +439,5 @@
 $(FINDSKYCELL)	       : $(INC)/addstar.h
 $(LOAD-2MASS)  	       : $(INC)/addstar.h $(INC)/2mass.h
+$(LOAD-GALPHOT)	       : $(INC)/addstar.h $(INC)/loadgalphot.h
 $(LOAD-STARPAR)	       : $(INC)/addstar.h $(INC)/loadstarpar.h
 $(LOAD-STARPAR-CLIENT) : $(INC)/addstar.h $(INC)/loadstarpar.h
@@ -421,4 +457,5 @@
 $(BIN)/loadwise.$(ARCH)       : $(LOAD-WISE)
 $(BIN)/loadtycho.$(ARCH)      : $(LOAD-TYCHO)
+$(BIN)/loadgalphot.$(ARCH)    : $(LOAD-GALPHOT)
 $(BIN)/loadstarpar.$(ARCH)    : $(LOAD-STARPAR)
 $(BIN)/loadstarpar_client.$(ARCH) : $(LOAD-STARPAR-CLIENT)
Index: trunk/Ohana/src/addstar/doc/ff.and.diff.txt
===================================================================
--- trunk/Ohana/src/addstar/doc/ff.and.diff.txt	(revision 38553)
+++ trunk/Ohana/src/addstar/doc/ff.and.diff.txt	(revision 38553)
@@ -0,0 +1,11 @@
+
+full-forced warp and diffs need to be loaded in a more efficient manner.
+
+I need to load a bunch of images at once, then merge them into the database.
+
+for the full-force skycells, the individual images need to be mutually merged
+
+things I need to add:
+
+1) associate neb names with real files names read from a list:
+   realname = nebname
Index: trunk/Ohana/src/addstar/include/addstar.h
===================================================================
--- trunk/Ohana/src/addstar/include/addstar.h	(revision 38543)
+++ trunk/Ohana/src/addstar/include/addstar.h	(revision 38553)
@@ -33,4 +33,10 @@
 
 # define myAbortF(FORMAT,...) { fprintf (stderr, FORMAT, __VA_ARGS__); abort(); }
+
+// things that are needed for a single file
+typedef struct {
+  char *filename;  // name of the file on disk (full path)
+  char *imagename; // name of the image for user reference (eg, base of neb path, full path, etc)
+} AddstarFile;
 
 typedef struct {
@@ -44,4 +50,5 @@
 } HeaderSet;
 
+# if (0)
 typedef struct {
   Average  average;
@@ -61,4 +68,5 @@
   char *refcat;
 } DVO_DATA;
+# endif
 
 # define IDTYPE int
@@ -190,4 +198,5 @@
 AddstarClientOptions args         	  PROTO((int argc, char **argv, AddstarClientOptions options));
 AddstarClientOptions args_parallel_client PROTO((int argc, char **argv, AddstarClientOptions options));
+void FreeConfig PROTO((void));
 
 void       AddToCalibration       PROTO((Average *average, SecFilt *secfilt, Measure *measure, Measure *new, off_t *next, off_t Nstar));
@@ -205,17 +214,21 @@
 SkyTable  *SkyTableFromTychoIndex PROTO((char *filename, int VERBOSE));
 void       check_permissions      PROTO((char *basefile));
-int        dump_rawstars          PROTO((Stars *stars, unsigned int Nstars));
 int        edge_check             PROTO((double *x1, double *y1, double *x2, double *y2));
 Image     *fakeimage              PROTO((char *rootname, off_t *Nimage, int photcode));
 
-int        find_matches           	 PROTO((SkyRegion *region, Stars *stars,  unsigned int Nstars, Catalog *catalog, AddstarClientOptions options));
-int        find_matches_closest   	 PROTO((SkyRegion *region, Stars *stars,  unsigned int Nstars, Catalog *catalog, AddstarClientOptions options));
+double     get_subpix             PROTO((double x, double y));
+
+int        find_matches_closest   PROTO((SkyRegion *region, Catalog *newcat, Catalog *catalog, AddstarClientOptions options));
+int        find_matches        	  PROTO((SkyRegion *region, Catalog *newcat, Catalog *catalog, AddstarClientOptions options));
+
+# if (0)
 int        find_matches_refstars  	 PROTO((SkyRegion *region, Stars **stars, unsigned int Nstars, Catalog *catalog, AddstarClientOptions options));
 int        find_matches_closest_refstars PROTO((SkyRegion *region, Stars **stars, unsigned int Nstars, Catalog *catalog, AddstarClientOptions options));
+
+int        dump_rawstars          PROTO((Stars *stars, unsigned int Nstars));
 
 Stars    **find_subset            PROTO((SkyRegion *region, Stars *stars, unsigned int Nstars, unsigned int *NSTARS));
 int        gcatalog               PROTO((Catalog *catalog));
 Stars     *get2mass               PROTO((SkyRegion *patch, int photcode, int mode, unsigned int *NSTARS));
-double     get_subpix             PROTO((double x, double y));
 
 Stars     *greference             PROTO((char *Refcat, SkyRegion *catstats, int photcode, unsigned int *nstars));
@@ -227,8 +240,14 @@
 Stars     *grefstars              PROTO((char *file, int photcode, unsigned int *Nstars));
 
-Stars     *LoadStars              PROTO((char *file, unsigned int *Nstars, Image **images, off_t *Nimages, AddstarClientOptions *options));
+Stars     *rd_gsc                 PROTO((char *filename, unsigned int *nstars));
+
+int        replace_match          PROTO((Average *average, Measure *measure, Stars *star));
+# endif
+
+Catalog   *LoadStars              PROTO((char *file, Image **images, off_t *Nimages, AddstarClientOptions *options));
 Header   **LoadHeaders            PROTO((FILE *f, int *mode, int *Nheader));
 HeaderSet *MatchHeaders           PROTO((off_t **extsize, off_t *nimage, int mode, Header **headers, int Nheaders));
-int        LoadData               PROTO((FILE *f, char *file, Image **images, off_t *nvalid, Stars **stars, unsigned int *Nstars, Header **headers, off_t *extsize, HeaderSet *headerSets, int NheaderSets, AddstarClientOptions *options));
+void       HeaderSetFree          PROTO((HeaderSet *headerSets, off_t NheaderSets));
+Catalog   *LoadData               PROTO((FILE *f, AddstarFile *file, Image **images, off_t *nvalid, Header **headers, off_t *extsize, HeaderSet *headerSets, int NheaderSets, AddstarClientOptions *options));
 int        GetZeroPointExposure   PROTO((Header **headers, HeaderSet *headerSets, off_t Nimages));
 
@@ -240,6 +259,4 @@
 double     opening_angle          PROTO((double x1, double y1, double x2, double y2, double x3, double y3));
 int        parse_time             PROTO((Header *header));
-Stars     *rd_gsc                 PROTO((char *filename, unsigned int *nstars));
-int        replace_match          PROTO((Average *average, Measure *measure, Stars *star));
 int        resort_catalogs        PROTO((AddstarClientOptions *options, SkyTable *sky));
 int        resort_catalogs_parallel PROTO((AddstarClientOptions *options, SkyList *sky));
@@ -249,12 +266,14 @@
 void       resort_catalog_old     PROTO((Catalog *catalog));
 
-Stars     *ReadStarsFITS          PROTO((FILE *f, Header *header, Header *in_theader, unsigned int *nstars));
-Stars     *ReadStarsTEXT          PROTO((FILE *f, unsigned int *nstars));
-Stars     *ReadStarsSDSS          PROTO((FILE *f, char *name, Header *header, Header *in_theader, Image *images, off_t *nimages, unsigned int *nstars));
+// Stars  *ReadStarsTEXT          PROTO((FILE *f, unsigned int *nstars));
+
 int        ReadImageHeader        PROTO((Header *header, Image *image, int photcode));
-Stars     *FilterStars            PROTO((Stars *instars, Image *image, unsigned int imageID, const AddstarClientOptions *options));
-Stars     *MergeStars             PROTO((Stars *stars, unsigned int *Nstars, Stars *instars, unsigned int Ninstars));
-
-int        ReadXradFITS           PROTO((FILE *f, Header *theader, Stars *stars, unsigned int Nstars));
+
+Catalog   *ReadStarsFITS          PROTO((FILE *f, Header *header, Header *in_theader));
+Catalog   *FilterStars            PROTO((Catalog *newcat, Image *image, unsigned int imageID, const AddstarClientOptions *options));
+int        ReadXradFITS           PROTO((FILE *f, Header *theader, Catalog *catalog));
+
+Catalog   *LoadDataSDSS           PROTO((FILE *f, char *file, Image **images, off_t *nvalid, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t Nimages));
+Catalog   *ReadStarsSDSS          PROTO((FILE *f, char *name, Header *header, Header *in_theader, Image *images, off_t *nimages));
 
 double     scat_subpix            PROTO((double x, double y));
@@ -276,4 +295,9 @@
 AddstarClientOptions args_load2mass PROTO((int argc, char **argv, AddstarClientOptions options));
 AddstarClientOptions args_sedstar PROTO((int argc, char **argv, AddstarClientOptions options));
+
+SkyList   *SkyListExistingSubset  PROTO((SkyList *input, char *path));
+
+// these are all for the addstar client/server which has not been maintained
+# if (0)
 void	   args_server		  PROTO((int argc, char **argv));
 int 	   CheckPassword	  PROTO((int BindSocket));
@@ -288,5 +312,4 @@
 int 	   UpdateDatabase_Refcat  PROTO((AddstarClientOptions *options, SkyRegion *UserPatch, char *refcat));
 SkyList   *SkyListForStars	  PROTO((SkyTable *table, int depth, Stars *stars, unsigned int Nstars));
-SkyList   *SkyListExistingSubset  PROTO((SkyList *input, char *path));
 int        SkyListSetPath	  PROTO((SkyList *list, char *path));
 int 	   InitDataset		  PROTO((void));
@@ -297,16 +320,14 @@
 int 	   NewRefcat_Thread	  PROTO((int BindSocket));
 int 	   NewReflist_Thread	  PROTO((int BindSocket));
-
-int        InitStar               PROTO((Stars *star));
+# endif
 
 int args_skycells (int argc, char **argv);
 int ConfigInit_skycells (int *argc, char **argv);
-int UpdateImageIDs (Stars *stars, unsigned int Nstars, Image *images, off_t Nimages);
+int UpdateImageIDs (Catalog *catalog, Image *images, off_t Nimages);
 
 int CheckDuplicateImageIDs (Image *images, off_t Nimages);
 int ImageIndexFileInit ();
 
-int LoadDataSDSS (FILE *f, char *file, Image **images, off_t *nvalid, Stars **stars, unsigned int *Nstars, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t Nimages);
-int LoadDataPMM (FILE *f, char *file, Image **images, off_t *nvalid, Stars **stars, unsigned int *Nstars);
+Catalog *LoadDataPMM (FILE *f, char *file, Image **images, off_t *nvalid);
 
 PhotCode *LoadMetadataPMM (char *datafile, Image *image);
@@ -330,7 +351,11 @@
 void saveMosaicCoords (Coords *input);
 
-
-Stars *ReadStarsUKIRT (FILE *f, char *name, Header *header, Image *images, off_t *nimages, unsigned int *nstars);
-int LoadDataUKIRT (FILE *f, char *file, Image **images, off_t *nimages, Stars **stars, unsigned int *Nstars, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t NheaderSets);
+Catalog *ReadStarsUKIRT (FILE *f, char *name, Header *header, Image *images, off_t *nimages);
+Catalog *LoadDataUKIRT (FILE *f, char *file, Image **images, off_t *nimages, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t NheaderSets);
+
+AddstarFile *LoadFilenames (int *nfile, char *filename, AddstarClientOptions *options);
+void AddstarFileFree (AddstarFile *file, int Nfile);
+
+Catalog *addstar_catalog_init (int Nstars);
 
 /** 
Index: trunk/Ohana/src/addstar/include/loadgalphot.h
===================================================================
--- trunk/Ohana/src/addstar/include/loadgalphot.h	(revision 38553)
+++ trunk/Ohana/src/addstar/include/loadgalphot.h	(revision 38553)
@@ -0,0 +1,65 @@
+
+typedef struct {
+  double **s;
+  double **b;
+  double **c;
+  double **C;
+  double  *B;
+  double *Cii;
+  int order;
+  int nterm;
+  int wterm;
+  int mterm;
+  float mean;
+  float sigma;
+  double c00;
+  double c10;
+  double c20;
+  double c01;
+  double c11;
+  double c02;
+  int ClipNiter;
+  float ClipNsigma;
+} Fit2D;
+
+typedef struct {
+  double R, D;
+  GalPhot galphot;
+  int flag; // in a subset?
+  int found; // assigned to an object?
+} GalPhot_Stars;
+
+typedef struct {
+  int *ID;
+  int *type;
+  int  N;
+} GalPhotIDset;
+
+AddstarClientOptions args_loadgalphot (int argc, char **argv, AddstarClientOptions options);
+
+int loadgalphot_table (SkyList *skylistInput, HostTable *hosts, char *filename, AddstarClientOptions *options);
+
+GalPhot_Stars *loadgalphot_readstars (char *filename, int *nstars);
+
+int loadgalphot_sortStars (GalPhot_Stars *stars, int Nstars);
+
+GalPhot_Stars *loadgalphot_make_subset (GalPhot_Stars *stars, int Nstars, int start, SkyRegion *region, int *nsubset);
+
+int loadgalphot_catalog (GalPhot_Stars *stars, int Nstars, SkyRegion *region, char *filename, AddstarClientOptions *options);
+
+int find_matches_galphot (SkyRegion *region, GalPhot_Stars *stars, int Nstars, Catalog *catalog, AddstarClientOptions *options);
+
+int FitChisqMinimum (Fit2D *fit, GalPhot *galphot, 
+		     float *chisq, float *flux, float *fluxErr, int Npts, 
+		     float MajorMin, float MajorMax, float MajorDel, 
+		     float MinorMin, float MinorMax, float MinorDel);
+
+Fit2D *fit2d_init (int order);
+void fit2d_free (Fit2D *fit);
+int fit2d (Fit2D *fit, float *xval, float *yval, float *zval, float *zfit, char *mask, int Npts);
+int fit2d_reset (Fit2D *fit);
+
+int *join_IDs (GalPhotIDset *gal, GalPhotIDset *fit);
+int strhash (char *string, int module);
+
+void sort_IDs_seqonly (int *X, int *S, int N);
Index: trunk/Ohana/src/addstar/src/ConfigInit.c
===================================================================
--- trunk/Ohana/src/addstar/src/ConfigInit.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/ConfigInit.c	(revision 38553)
@@ -224,4 +224,5 @@
   }
 
+  FreeConfigFile();
   free (config);
   free (file);
@@ -240,2 +241,6 @@
   return;
 }
+
+void FreeConfig (void) {
+  FREE (CATDIR);
+}
Index: trunk/Ohana/src/addstar/src/FilterStars.c
===================================================================
--- trunk/Ohana/src/addstar/src/FilterStars.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/FilterStars.c	(revision 38553)
@@ -10,9 +10,8 @@
 // the imageID supplied here is the sequence **within this set**
 // this value is updated based on the image table later (in UpdateImageIDs)
-Stars *FilterStars (Stars *instars, Image *image, unsigned int imageID, const AddstarClientOptions *options) {
+Catalog *FilterStars (Catalog *newcat, Image *image, unsigned int imageID, const AddstarClientOptions *options) {
 
   int j, N;
   float MTIME, dMs, dMx;
-  Stars *stars;
   float RMIN, RMAX, DMIN, DMAX;
 
@@ -26,43 +25,58 @@
 
   /* modify resulting star list */
-  ALLOCATE (stars, Stars, image[0].nstar);
-  for (N = j = 0; j < image[0].nstar; j++) {
-
-    if (instars[j].measure.photFlags & options->detectionFilter) continue;
+  Catalog *outcat = addstar_catalog_init (newcat->Nmeasure);
+  ALLOCATE (outcat->average, Average, newcat->Nmeasure);
+  if (newcat->lensing) {
+    ALLOCATE (outcat->lensing, Lensing, newcat->Nlensing);
+  }
+  
+  for (N = j = 0; j < newcat->Nmeasure; j++) {
+
+    if (newcat->measure[j].photFlags & options->detectionFilter) continue;
 
     /* allow for some dynamic filtering of star list */
-    if (SNLIMIT && instars[j].measure.dM > SNLIMIT) continue;
-    if (XMAX && (instars[j].measure.Xccd > XMAX)) continue;
-    if (XMIN && (instars[j].measure.Xccd < XMIN)) continue;
-    if (YMAX && (instars[j].measure.Yccd > YMAX)) continue;
-    if (YMIN && (instars[j].measure.Yccd < YMIN)) continue;
-    if (PHOTFLAG_EXCLUDE && (instars[j].measure.photFlags & PHOTFLAG_EXCLUDE)) continue;
-
-    stars[N] = instars[j];
-
-    XY_to_RD (&stars[N].average.R, &stars[N].average.D, stars[N].measure.Xccd, stars[N].measure.Yccd, &image[0].coords);
-    stars[N].average.R = ohana_normalize_angle (stars[N].average.R);
-    stars[N].measure.R = stars[N].average.R;
-    stars[N].measure.D = stars[N].average.D;
-
-    stars[N].measure.photcode = image[0].photcode;
+    if (SNLIMIT && newcat->measure[j].dM > SNLIMIT) continue;
+    if (XMAX && (newcat->measure[j].Xccd > XMAX)) continue;
+    if (XMIN && (newcat->measure[j].Xccd < XMIN)) continue;
+    if (YMAX && (newcat->measure[j].Yccd > YMAX)) continue;
+    if (YMIN && (newcat->measure[j].Yccd < YMIN)) continue;
+    if (PHOTFLAG_EXCLUDE && (newcat->measure[j].photFlags & PHOTFLAG_EXCLUDE)) continue;
+
+    dvo_average_init (&outcat->average[N]);
+    outcat->measure[N] = newcat->measure[j];
+
+    if (newcat->lensing) {
+      outcat->lensing[N] = newcat->lensing[j];
+      outcat->average[N].Nlensing = 1;
+      outcat->average[N].lensingOffset = N;
+    }
+
+    outcat->average[N].Nmeasure = 1;
+    outcat->average[N].measureOffset = N;
+
+    XY_to_RD (&outcat->average[N].R, &outcat->average[N].D, outcat->measure[N].Xccd, outcat->measure[N].Yccd, &image[0].coords);
+    outcat->average[N].R = ohana_normalize_angle (outcat->average[N].R);
+    outcat->measure[N].R = outcat->average[N].R;
+    outcat->measure[N].D = outcat->average[N].D;
+
+    outcat->measure[N].photcode = image[0].photcode;
 
     // determine the full coverage of this set of measurements
-    RMIN = MIN (RMIN, stars[N].average.R);
-    RMAX = MAX (RMAX, stars[N].average.R);
-    DMIN = MIN (DMIN, stars[N].average.D);
-    DMAX = MAX (DMAX, stars[N].average.D);
+    RMIN = MIN (RMIN, outcat->average[N].R);
+    RMAX = MAX (RMAX, outcat->average[N].R);
+    DMIN = MIN (DMIN, outcat->average[N].D);
+    DMAX = MAX (DMAX, outcat->average[N].D);
 
     /** additional quantities to supply to Stars based on the image data **/
 
     /* calculate accurate per-star airmass and azimuth */
-    stars[N].measure.airmass = airmass (image[0].secz, stars[N].average.R, stars[N].average.D, image[0].sidtime, image[0].latitude);
-    stars[N].measure.az      = azimuth (15.0*image[0].sidtime - stars[N].average.R, stars[N].average.D, image[0].latitude);
-    stars[N].measure.Mcal    = image[0].Mcal;
-    stars[N].measure.t       = image[0].tzero + 1e-4*stars[N].measure.Yccd*image[0].trate;  /* trate is in 0.1 msec / row */
-    stars[N].measure.dt      = MTIME;
+    outcat->measure[N].airmass = airmass (image[0].secz, outcat->average[N].R, outcat->average[N].D, image[0].sidtime, image[0].latitude);
+    outcat->measure[N].az      = azimuth (15.0*image[0].sidtime - outcat->average[N].R, outcat->average[N].D, image[0].latitude);
+    outcat->measure[N].Mcal    = image[0].Mcal;
+    outcat->measure[N].t       = image[0].tzero + 1e-4*outcat->measure[N].Yccd*image[0].trate;  /* trate is in 0.1 msec / row */
+    outcat->measure[N].dt      = MTIME;
 
     // watch out for any strange values:
-    if ((stars[N].measure.M > 25.0) && (stars[N].measure.M < 32.0)) {
+    if ((outcat->measure[N].M > 25.0) && (outcat->measure[N].M < 32.0)) {
       fprintf (stderr, "*");
     }
@@ -73,58 +87,54 @@
     dMx = 0.0;
     if (SUBPIX) {
-      dMs =  get_subpix (stars[N].measure.Xccd, stars[N].measure.Yccd);
-      dMx = scat_subpix (stars[N].measure.Xccd, stars[N].measure.Yccd);
-      if (!isnan(stars[N].measure.dM)) {
-	stars[N].measure.dM = hypot (stars[N].measure.dM, dMx);
+      dMs =  get_subpix (outcat->measure[N].Xccd, outcat->measure[N].Yccd);
+      dMx = scat_subpix (outcat->measure[N].Xccd, outcat->measure[N].Yccd);
+      if (!isnan(outcat->measure[N].dM)) {
+	outcat->measure[N].dM = hypot (outcat->measure[N].dM, dMx);
       }
     }
 
-    if (!isnan(stars[N].measure.M)) {
-      stars[N].measure.M   += MTIME - dMs;
-    }
-    if (!isnan(stars[N].measure.Map)) {
-      stars[N].measure.Map += MTIME - dMs;
-    }
-    if (!isnan(stars[N].measure.Mkron)) {
-      stars[N].measure.Mkron += MTIME - dMs;
-    }
-    if (!isnan(stars[N].measure.FluxPSF)) {
-      stars[N].measure.FluxPSF /= image[0].exptime;
-    }
-    if (!isnan(stars[N].measure.dFluxPSF)) {
-      stars[N].measure.dFluxPSF /= image[0].exptime;
-    }
-    if (!isnan(stars[N].measure.FluxKron)) {
-      stars[N].measure.FluxKron /= image[0].exptime;
-    }
-    if (!isnan(stars[N].measure.dFluxKron)) {
-      stars[N].measure.dFluxKron /= image[0].exptime;
-    }
-    if (!isnan(stars[N].measure.FluxAp)) {
-      stars[N].measure.FluxAp /= image[0].exptime;
-    }
-    if (!isnan(stars[N].measure.dFluxAp)) {
-      stars[N].measure.dFluxAp /= image[0].exptime;
-    }
-    if (stars[N].lensing) {
-      if (!isnan(stars[N].lensing-> F_ApR5)) stars[N].lensing-> F_ApR5 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->dF_ApR5)) stars[N].lensing->dF_ApR5 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->sF_ApR5)) stars[N].lensing->sF_ApR5 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->fF_ApR5)) stars[N].lensing->fF_ApR5 /= image[0].exptime;
-
-      if (!isnan(stars[N].lensing-> F_ApR6)) stars[N].lensing-> F_ApR6 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->dF_ApR6)) stars[N].lensing->dF_ApR6 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->sF_ApR6)) stars[N].lensing->sF_ApR6 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->fF_ApR6)) stars[N].lensing->fF_ApR6 /= image[0].exptime;
-
-      if (!isnan(stars[N].lensing-> F_ApR7)) stars[N].lensing-> F_ApR7 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->dF_ApR7)) stars[N].lensing->dF_ApR7 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->sF_ApR7)) stars[N].lensing->sF_ApR7 /= image[0].exptime;
-      if (!isnan(stars[N].lensing->fF_ApR7)) stars[N].lensing->fF_ApR7 /= image[0].exptime;
+    if (!isnan(outcat->measure[N].M)) {
+      outcat->measure[N].M   += MTIME - dMs;
+    }
+    if (!isnan(outcat->measure[N].Map)) {
+      outcat->measure[N].Map += MTIME - dMs;
+    }
+    if (!isnan(outcat->measure[N].Mkron)) {
+      outcat->measure[N].Mkron += MTIME - dMs;
+    }
+    if (!isnan(outcat->measure[N].FluxPSF)) {
+      outcat->measure[N].FluxPSF /= image[0].exptime;
+    }
+    if (!isnan(outcat->measure[N].dFluxPSF)) {
+      outcat->measure[N].dFluxPSF /= image[0].exptime;
+    }
+    if (!isnan(outcat->measure[N].FluxKron)) {
+      outcat->measure[N].FluxKron /= image[0].exptime;
+    }
+    if (!isnan(outcat->measure[N].dFluxKron)) {
+      outcat->measure[N].dFluxKron /= image[0].exptime;
+    }
+    if (!isnan(outcat->measure[N].FluxAp)) {
+      outcat->measure[N].FluxAp /= image[0].exptime;
+    }
+    if (!isnan(outcat->measure[N].dFluxAp)) {
+      outcat->measure[N].dFluxAp /= image[0].exptime;
+    }
+    if (outcat->lensing) {
+      // correct things which scale like exptime with the exptime
+      if (!isnan(outcat->lensing[N]. F_ApR5)) outcat->lensing[N]. F_ApR5 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N].dF_ApR5)) outcat->lensing[N].dF_ApR5 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N].sF_ApR5)) outcat->lensing[N].sF_ApR5 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N]. F_ApR6)) outcat->lensing[N]. F_ApR6 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N].dF_ApR6)) outcat->lensing[N].dF_ApR6 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N].sF_ApR6)) outcat->lensing[N].sF_ApR6 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N]. F_ApR7)) outcat->lensing[N]. F_ApR7 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N].dF_ApR7)) outcat->lensing[N].dF_ApR7 /= image[0].exptime;
+      if (!isnan(outcat->lensing[N].sF_ApR7)) outcat->lensing[N].sF_ApR7 /= image[0].exptime;
     }
     
     // the external ID is supplied, but do we trust it?
     if (!EXTERNAL_ID) {
-      stars[N].measure.detID = N; // sequence number within image
+      outcat->measure[N].detID = N; // sequence number within image
     }
 
@@ -135,17 +145,17 @@
 
       if (isStack) {
-	stars[N].measure.extID = CreatePSPSStackDetectionID(image[0].sourceID, image[0].externID, stars[N].measure.detID);
+	outcat->measure[N].extID = CreatePSPSStackDetectionID(image[0].sourceID, image[0].externID, outcat->measure[N].detID);
       } else {
-	stars[N].measure.extID = CreatePSPSDetectionID(mjd, image[0].ccdnum, stars[N].measure.detID);
+	outcat->measure[N].extID = CreatePSPSDetectionID(mjd, image[0].ccdnum, outcat->measure[N].detID);
       }
     } else {
-      stars[N].measure.extID = 0;
-    }
-
-    stars[N].measure.imageID = imageID; // this value is updated in UpdateImageIDs
+      outcat->measure[N].extID = 0;
+    }
+
+    outcat->measure[N].imageID = imageID; // this value is updated in UpdateImageIDs
 
     // add imageID to lensing entry, if it exists
-    if (stars[N].lensing) {
-      stars[N].lensing->imageID = imageID;
+    if (outcat->lensing) {
+      outcat->lensing[N].imageID = imageID;
     }
 
@@ -156,12 +166,24 @@
   
   image[0].nstar = N;
-  REALLOCATE (stars, Stars, image[0].nstar);
-  free (instars);
-
-  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", image[0].nstar);
+
+  REALLOCATE (outcat->measure, Measure, N);
+  REALLOCATE (outcat->average, Average, N);
+  if (outcat->lensing) {
+    REALLOCATE (outcat->average, Average, N);
+  }
+  dvo_catalog_free (newcat);
+  free (newcat);
+
+  outcat->Naverage = N;
+  outcat->Nmeasure = N;
+  outcat->Nlensing = outcat->lensing ? N : 0;
+
+  if (VERBOSE) fprintf (stderr, "read %d stars from target file\n", N);
   if (VERBOSE) fprintf (stderr, "stars cover region %f,%f - %f,%f\n", RMIN, DMIN, RMAX, DMAX);
-  return (stars);
+
+  return (outcat);
 }
 
+# if (0)
 Stars *MergeStars (Stars *stars, unsigned int *Nstars, Stars *instars, unsigned int Ninstars) {
 
@@ -181,2 +203,3 @@
   return (stars);
 }
+# endif
Index: trunk/Ohana/src/addstar/src/ImageIndex.c
===================================================================
--- trunk/Ohana/src/addstar/src/ImageIndex.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/ImageIndex.c	(revision 38553)
@@ -1,3 +1,11 @@
 # include "addstar.h"
+
+void ImageIndexFree (ImageIndex *index) {
+  if (!index) return;
+  FREE (index->externID);
+  FREE (index->imageID);
+  FREE (index->found);
+  FREE (index);
+}
 
 ImageIndex *ImageIndexLoad (char *filename) {
@@ -16,4 +24,5 @@
   if (!f) {
     fprintf (stderr, "ERROR: cannot open image index file %s\n", filename);
+    FREE (index);
     return NULL;
   }
@@ -23,4 +32,5 @@
     if (VERBOSE) fprintf (stderr, "can't read image index header\n");
     fclose (f);
+    FREE (index);
     return NULL;
   }
@@ -28,8 +38,8 @@
     if (VERBOSE) fprintf (stderr, "can't read image index matrix\n");
     gfits_free_header (&header);
-    fclose (f);
-    return NULL;
-  }
-
+    FREE (index);
+    fclose (f);
+    return NULL;
+  }
   ftable.header = &theader;
 
@@ -37,4 +47,6 @@
   if (!gfits_load_header (f, &theader)) {
     fclose (f);
+    gfits_free_header (&header);
+    FREE (index);
     return NULL;
   }
@@ -43,4 +55,7 @@
   if (!gfits_fread_ftable_data (f, &ftable, FALSE)) {
     fclose (f);
+    gfits_free_header (&header);
+    gfits_free_header (&theader);
+    FREE (index);
     return (NULL);
   }
@@ -76,4 +91,9 @@
   }
 
+  gfits_free_header (&header);
+  gfits_free_matrix (&matrix);
+  gfits_free_header (&theader);
+  gfits_free_table (&ftable);
+
   return index;
 }
@@ -179,4 +199,5 @@
   
   // extend the storage arrays
+  // no reason to extend 'found'
   REALLOCATE (index->imageID,  IDTYPE, index->Nimage + Nimages);
   REALLOCATE (index->externID, IDTYPE, index->Nimage + Nimages);
@@ -192,4 +213,5 @@
   // do this as an 'extend' operation
   ImageIndexSave (filename, index);
+  ImageIndexFree (index);
   return TRUE;
 }
@@ -205,8 +227,10 @@
   ALLOCATE (index->imageID,  IDTYPE, 1);
   ALLOCATE (index->externID, IDTYPE, 1);
+  ALLOCATE (index->found, char, 1);
   index->Nimage = 0;
 
   // do this as an 'extend' operation
   ImageIndexSave (filename, index);
+  ImageIndexFree (index);
   return TRUE;
 }
Index: trunk/Ohana/src/addstar/src/LoadData.c
===================================================================
--- trunk/Ohana/src/addstar/src/LoadData.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/LoadData.c	(revision 38553)
@@ -1,15 +1,18 @@
 # include "addstar.h"
 
-// XXX this function is somewhat specific to the elixir format output files 
-// it is capable of distinguishing several format versions defined for elixir/psphot
+// load photometry data from psphot, sextractor, and a few other formats
+// examine the header sets and set the Image entries for the the valid images
+Catalog *LoadData (FILE *f, AddstarFile *file, Image **images, off_t *nvalid, Header **headers, off_t *extsize, HeaderSet *headerSets, int Nimages, AddstarClientOptions *options) {
 
-// examine the header sets and set the Image entries for the the valid images
-int LoadData (FILE *f, char *file, Image **images, off_t *nvalid, Stars **stars, unsigned int *Nstars, Header **headers, off_t *extsize, HeaderSet *headerSets, int Nimages, AddstarClientOptions *options) {
-
-  char *name;
   off_t Nskip, Nvalid, NVALID;
   int i, j, Nhead, Ndata;
   uint32_t parentID = UINT32_MAX;
-  Stars *inStars;
+
+  Catalog *catalog = NULL;
+  ALLOCATE (catalog, Catalog, 1);
+  dvo_catalog_init (catalog, TRUE);
+  ALLOCATE (catalog->average, Average, 1);
+  ALLOCATE (catalog->measure, Measure, 1);
+  ALLOCATE (catalog->lensing, Lensing, 1);
 
   if (images[0] == NULL) {
@@ -22,11 +25,4 @@
     REALLOCATE (images[0], Image, NVALID);
   }    
-
-  // find image rootname
-  if (USE_NAME) {
-      name = filebasename (USE_NAME);
-  } else {
-      name = filebasename (file);
-  }
 
   // if zero points are calculated for the full exposure using more than just the matched chip header,
@@ -58,7 +54,7 @@
     // XXX use something to set the chip name? EXTNAME?
     if (!strcmp(headerSets[i].exthead, "PHU") && (Nimages == 1)) {
-      snprintf (images[0][Nvalid].name, DVO_IMAGE_NAME_LEN, "%s", name);
+      snprintf (images[0][Nvalid].name, DVO_IMAGE_NAME_LEN, "%s", file->imagename);
     } else {
-      snprintf (images[0][Nvalid].name, DVO_IMAGE_NAME_LEN, "%s[%s]", name, headerSets[i].exthead);
+      snprintf (images[0][Nvalid].name, DVO_IMAGE_NAME_LEN, "%s[%s]", file->imagename, headerSets[i].exthead);
     }
 
@@ -84,9 +80,9 @@
     fseeko (f, Nskip, SEEK_SET); 
 	 
-    inStars = ReadStarsFITS (f, headers[Nhead], headers[Ndata], &images[0][Nvalid].nstar);
-    if (!inStars) {
-      // XXX need to free the data here or in ReadStarsFITS on error
-      continue;
-    }
+    // ReadStarsFITS populates catalog->measure,Nmeasure 
+    Catalog *newcat = ReadStarsFITS (f, headers[Nhead], headers[Ndata]);
+    if (!newcat) continue;
+
+    images[0][Nvalid].nstar = newcat->Nmeasure;
 
     // XRAD : if we want to read the xrad table, skip to that table here:
@@ -99,11 +95,31 @@
       fseeko (f, Nskip, SEEK_SET); 
       
-      if (!ReadXradFITS (f, headers[Nxrad], inStars, images[0][Nvalid].nstar)) {
+      if (!ReadXradFITS (f, headers[Nxrad], newcat)) {
 	fprintf (stderr, "problem reading the radial flux data for %s\n", headerSets[i].extdata);
       }
     }
 
-    inStars = FilterStars (inStars, &images[0][Nvalid], Nvalid, options);
-    *stars = MergeStars (*stars, Nstars, inStars, images[0][Nvalid].nstar);
+    // replace full input catalog newcat with subset version
+    newcat = FilterStars (newcat, &images[0][Nvalid], Nvalid, options);
+
+    double Rref, Dref;
+    XY_to_RD (&Rref, &Dref, 0.0, 0.0, &images[0][Nvalid].coords);
+    SkyRegion region;
+    region.Rmin = Rref - 180.0;
+    region.Rmax = Rref + 180.0;
+    region.Dmin = Dref -  90.0;
+    region.Dmax = Dref +  90.0;
+    
+    AddstarClientOptions matchOptions = *options;
+    matchOptions.radius = 0.4; // tight radius at this stage
+    matchOptions.calibrate = FALSE;
+    matchOptions.only_match = FALSE;
+    matchOptions.nosort = FALSE;
+    matchOptions.photcode = 0; // use an invalid photcode to avoid touching secfilt
+
+    find_matches_closest (&region, newcat, catalog, matchOptions);
+    dvo_catalog_free (newcat);
+    free (newcat);
+
     Nvalid++;
     CHECK_REALLOCATE (images[0], Image, NVALID, Nvalid, 10);
@@ -111,14 +127,15 @@
 
   if (isfinite(OFFSET_ZPT)) {
-    for (i = 0; i < *Nstars; i++) {
-      stars[0][i].measure.M   += OFFSET_ZPT;
-      stars[0][i].measure.Map += OFFSET_ZPT;
+    for (i = 0; i < catalog->Nmeasure; i++) {
+      catalog->measure[i].M   += OFFSET_ZPT;
+      catalog->measure[i].Map += OFFSET_ZPT;
     }
-
   }
 
-  free (name);
   *nvalid = Nvalid;
-  return (TRUE);
+  return catalog;
 }
 
+// thoughts:
+// 1) I read the data from a single image file into a catalog structure (instead of Stars)
+// 2) merge these into a single catalog here or in LoadData above?
Index: trunk/Ohana/src/addstar/src/LoadDataPMM.c
===================================================================
--- trunk/Ohana/src/addstar/src/LoadDataPMM.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/LoadDataPMM.c	(revision 38553)
@@ -15,12 +15,11 @@
 # define MAG_INDEX_ASC 22
 
-int LoadDataPMM (FILE *f, char *file, Image **images, off_t *nvalid, Stars **stars, unsigned int *Nstars) {
+Catalog *LoadDataPMM (FILE *f, char *imagename, Image **images, off_t *nvalid) {
 
   off_t Nvalid, NVALID;
-  char *name, *buffer;
+  char *buffer;
   int i, fd, Nbyte, Nline, code;
   double ra, dec, mag, airmass, az, ZeroPoint, ZeroPt;
   unsigned int Ninstars, NINSTARS;
-  Stars *inStars;
   PhotCode *photcode;
   gzFile gz;
@@ -38,14 +37,11 @@
   }    
 
-  // find image rootname
-  name = filebasename (file);
-
   // there is only one PMM image per file
-  if (VERBOSE) fprintf (stderr, "reading data for %s\n", file);
+  if (VERBOSE) fprintf (stderr, "reading data for %s\n", imagename);
 
   ZeroPt = GetZeroPoint();
 
   // need to get the metadata from the PMM_CCD_TABLE
-  photcode = LoadMetadataPMM (name, &images[0][Nvalid]);
+  photcode = LoadMetadataPMM (imagename, &images[0][Nvalid]);
   code = photcode[0].code;
   ZeroPoint = 0.001*photcode[0].C;
@@ -61,5 +57,10 @@
 
   NINSTARS = 10000;
-  ALLOCATE (inStars, Stars, NINSTARS);
+  Catalog *catalog = addstar_catalog_init (NINSTARS);
+  ALLOCATE (catalog->average, Average, NINSTARS);
+  for (i = 0; i < NINSTARS; i++) {
+    dvo_measure_init (&catalog->measure[i]);
+    dvo_average_init (&catalog->average[i]);
+  }
 
   minR0 = minR1 = 360.0;
@@ -85,6 +86,4 @@
       dparse (&dec, 2, &buffer[i*NBYTE_ASC_TABLE]);
       dparse (&mag, 3, &buffer[i*NBYTE_ASC_TABLE]);
-
-      InitStar (&inStars[Ninstars]);
 
       if (ra > 180) {
@@ -98,18 +97,34 @@
       maxD = MAX(maxD, dec);
 
-      inStars[Ninstars].average.R        = ra;
-      inStars[Ninstars].average.D        = dec;
-
-      inStars[Ninstars].measure.M        = mag - ZeroPoint + ZeroPt;
-      inStars[Ninstars].measure.t        = images[0][0].tzero;
-      inStars[Ninstars].measure.dt       = images[0][0].exptime;
-      inStars[Ninstars].measure.photcode = code;
-      inStars[Ninstars].measure.airmass  = airmass;
-      inStars[Ninstars].measure.az       = az;
+      catalog->average[Ninstars].R        = ra;
+      catalog->average[Ninstars].D        = dec;
+      catalog->average[Ninstars].Nmeasure = 1;
+      catalog->average[Ninstars].measureOffset = Ninstars;
+
+      catalog->measure[Ninstars].R        = ra;
+      catalog->measure[Ninstars].D        = dec;
+      catalog->measure[Ninstars].M        = mag - ZeroPoint + ZeroPt;
+      catalog->measure[Ninstars].t        = images[0][0].tzero;
+      catalog->measure[Ninstars].dt       = images[0][0].exptime;
+      catalog->measure[Ninstars].photcode = code;
+      catalog->measure[Ninstars].airmass  = airmass;
+      catalog->measure[Ninstars].az       = az;
+
+      // imageID, detID ?
 
       Ninstars++;
-      CHECK_REALLOCATE (inStars, Stars, NINSTARS, Ninstars, 10000);
+      if (Ninstars == NINSTARS) {
+	NINSTARS += 10000;
+	REALLOCATE (catalog->measure, Measure, NINSTARS);
+	REALLOCATE (catalog->average, Average, NINSTARS);
+	for (i = Ninstars; i < NINSTARS; i++) {
+	  dvo_measure_init (&catalog->measure[i]);
+	  dvo_average_init (&catalog->average[i]);
+	}
+      }
     }
   }
+  catalog->Nmeasure = Ninstars;
+  catalog->Naverage = Ninstars;
 
   fprintf (stderr, "ra ranges: %f - %f, %f - %f; dec ranges: %f - %f\n", minR0, maxR0, minR1, maxR1, minD, maxD);
@@ -118,13 +133,10 @@
   images[0][0].imageID = 0;
 
-  *stars = MergeStars (*stars, Nstars, inStars, Ninstars);
-
-  free (inStars);
-  free (name);
   *nvalid = Nvalid + 1;
 
   gzclose (gz);
   free (buffer);
-  return (TRUE);
+
+  return (catalog);
 }
 
Index: trunk/Ohana/src/addstar/src/LoadDataSDSS.c
===================================================================
--- trunk/Ohana/src/addstar/src/LoadDataSDSS.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/LoadDataSDSS.c	(revision 38553)
@@ -4,11 +4,8 @@
 // there should only be a single data set (phu + table) in this file
 // each SDSS data set corresponds to 5 images (ugriz)
-int LoadDataSDSS (FILE *f, char *file, Image **images, off_t *nvalid, Stars **stars, unsigned int *Nstars, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t Nimages) {
+Catalog *LoadDataSDSS (FILE *f, char *imagename, Image **images, off_t *nvalid, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t Nimages) {
 
   off_t Nskip, Nvalid, NVALID;
-  char *name;
   int j, Nhead, Ndata;
-  unsigned int Ninstars;
-  Stars *inStars;
 
   if (images[0] == NULL) {
@@ -21,7 +18,4 @@
     REALLOCATE (images[0], Image, NVALID);
   }    
-
-  // find image rootname
-  name = filebasename (file);
 
   // there is only one SDSS image per file (TRUE?)
@@ -39,11 +33,9 @@
   fseeko (f, Nskip, SEEK_SET); 
 	 
-  // XXX I think this is an error?  should this be &images[0][Nvalid] ??
-  inStars = ReadStarsSDSS (f, name, headers[Nhead], headers[Ndata], images[0], &Nvalid, &Ninstars);
-  *stars = MergeStars (*stars, Nstars, inStars, Ninstars);
+  // we pass in images[0] so the function updates the end of the array
+  Catalog *catalog = ReadStarsSDSS (f, imagename, headers[Nhead], headers[Ndata], images[0], &Nvalid);
 
-  free (name);
   *nvalid = Nvalid;
-  return (TRUE);
+  return (catalog);
 }
 
Index: trunk/Ohana/src/addstar/src/LoadDataUKIRT.c
===================================================================
--- trunk/Ohana/src/addstar/src/LoadDataUKIRT.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/LoadDataUKIRT.c	(revision 38553)
@@ -3,11 +3,17 @@
 // examine the header sets and set the Image entries for the the valid images
 // UKIRT data has the WCS/image metadata header intermixed with the bintable header
-int LoadDataUKIRT (FILE *f, char *file, Image **images, off_t *nimages, Stars **stars, unsigned int *Nstars, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t NheaderSets) {
+
+int MergeCatalogs (Catalog *tgt, Catalog *src);
+
+Catalog *LoadDataUKIRT (FILE *f, char *imagename, Image **images, off_t *nimages, Header **headers, off_t *extsize, HeaderSet *headerSets, off_t NheaderSets) {
 
   off_t Nskip, Nvalid, NVALID;
-  char *name;
   int i, j, Nhead, Ndata;
-  unsigned int Ninstars;
-  Stars *inStars;
+
+  Catalog *catalog = NULL;
+  ALLOCATE (catalog, Catalog, 1);
+  dvo_catalog_init (catalog, TRUE);
+  ALLOCATE (catalog->average, Average, 1);
+  ALLOCATE (catalog->measure, Measure, 1);
 
   // create or update image table 
@@ -21,7 +27,4 @@
     REALLOCATE (images[0], Image, NVALID);
   }    
-
-  // find image rootname
-  name = filebasename (file);
 
   // validate the number of headers sets == 4
@@ -38,10 +41,38 @@
     fseeko (f, Nskip, SEEK_SET); 
 
-    inStars = ReadStarsUKIRT (f, name, headers[Nhead], images[0], &Nvalid, &Ninstars);
-    *stars = MergeStars (*stars, Nstars, inStars, Ninstars);
+    Catalog *newcat = ReadStarsUKIRT (f, imagename, headers[Nhead], images[0], &Nvalid);
+    MergeCatalogs (catalog, newcat);
+
+    dvo_catalog_free (newcat);
+    free (newcat);
 
     *nimages = Nvalid;
   }    
-  return (TRUE);
+  return (catalog);
 }
 
+int MergeCatalogs (Catalog *tgt, Catalog *src) {
+
+  // this function assumes the src and tgt catalog do NOT overlap (otherwise just use find_match_closest) 
+
+  off_t Naverage_tgt = tgt->Naverage;
+  off_t Nmeasure_tgt = tgt->Nmeasure;
+
+  tgt->Naverage += src->Naverage;
+  tgt->Nmeasure += src->Nmeasure;
+
+  REALLOCATE (tgt->average, Average, tgt->Naverage);
+  REALLOCATE (tgt->measure, Measure, tgt->Nmeasure);
+
+  off_t i;
+  for (i = 0; i < src->Naverage; i++) {
+    tgt->average[i+Naverage_tgt] = src->average[i];
+    tgt->average[i+Naverage_tgt].measureOffset += Nmeasure_tgt;
+  }
+
+  for (i = 0; i < src->Nmeasure; i++) {
+    tgt->measure[i+Nmeasure_tgt] = src->measure[i];
+  }
+
+  return TRUE;
+}
Index: trunk/Ohana/src/addstar/src/LoadFilenames.c
===================================================================
--- trunk/Ohana/src/addstar/src/LoadFilenames.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/LoadFilenames.c	(revision 38553)
@@ -0,0 +1,94 @@
+# include "addstar.h"
+
+AddstarFile *LoadFilenames (int *nfile, char *filename, AddstarClientOptions *options) {
+
+  int i, n, Nfile, NFILE;
+  glob_t globList;
+  AddstarFile *file;
+  char line[4096], word1[4096], word2[4096], sep[4096];
+
+  if (options[0].filelist) {
+    // read the list of input files from the supplied file
+    FILE *f = fopen (filename, "r");
+    if (f == NULL) {
+      fprintf (stderr, "can't read input list %s, giving up\n", filename);
+      exit (1);
+    }
+
+    Nfile = 0;
+    NFILE = 10;
+    ALLOCATE (file, AddstarFile, NFILE);
+    for (i = 0; (scan_line (f, line) != EOF); i++) {
+      // find first non-whitespace char & skip commented lines
+      for (n = 0; OHANA_WHITESPACE (line[n]); n++);
+      if (line[n] == '#') continue;
+      if (line[n] == 0) continue;
+
+      // file lines may have:
+      // filename
+      // filename = nebname
+      // filename limited to 4096 chars
+      int Nfield = sscanf (line, "%s %s %s", word1, sep, word2);
+      if ((Nfield != 1) && (Nfield != 3)) {
+	fprintf (stderr, "invalid line: %s\n", line);
+	exit (3);
+      }
+
+      if (Nfield == 3) {
+	if (strcmp(sep, "=") && strcmp (sep, ":")) {
+	  fprintf (stderr, "ERROR: unexpected filename separator in list: %s\n", sep);
+	  exit (3);
+	}
+	file[Nfile].filename  = strcreate (word1);
+	file[Nfile].imagename = filebasename (word2);
+      } else {
+	file[Nfile].filename  = strcreate (word1);
+	file[Nfile].imagename = filebasename (word1);
+      }
+      ohana_memcheck (TRUE);
+      fprintf (stderr, "file: %s = %s\n", file[Nfile].filename, file[Nfile].imagename);
+      Nfile ++;
+      CHECK_REALLOCATE (file, AddstarFile, NFILE, Nfile, 10);
+    }
+    fclose (f);
+  } else {
+    // parse the filename as a glob
+    globList.gl_offs = 0;
+    glob (filename, 0, NULL, &globList);
+
+    // if the glob does not match, save the literal word:
+    // otherwise save all glob matches
+    if (globList.gl_pathc == 0) {
+      Nfile = 1;
+      ALLOCATE (file, AddstarFile, Nfile);
+      file->filename  = strcreate (filename);
+      file->imagename = USE_NAME ? filebasename (USE_NAME) : filebasename (filename);
+    } else {
+      Nfile = globList.gl_pathc;
+      if ((Nfile > 1) && USE_NAME) {
+	fprintf (stderr, "ERROR: -use-name supplied but more than one file matches glob\n");
+	exit (3);
+      }
+      ALLOCATE (file, AddstarFile, Nfile);
+      for (i = 0; i < Nfile; i++) {
+	file[i].filename  = strcreate (globList.gl_pathv[i]);
+	file[i].imagename = filebasename (file[i].filename);
+      }
+    }
+  }
+  *nfile = Nfile;
+  return (file);
+}
+
+void AddstarFileFree (AddstarFile *file, int Nfile) {
+
+  if (!file) return;
+
+  int i;
+  for (i = 0; i < Nfile; i++) {
+    free (file[i].filename);
+    free (file[i].imagename);
+  }
+  FREE (file);
+}
+
Index: trunk/Ohana/src/addstar/src/LoadHeaders.c
===================================================================
--- trunk/Ohana/src/addstar/src/LoadHeaders.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/LoadHeaders.c	(revision 38553)
@@ -17,4 +17,6 @@
     status = gfits_fread_header (f, headers[i]);
     if (!status) { 
+      gfits_free_header (headers[i]);
+      FREE (headers[i]);
       *Nheaders = i;
       return (headers);
Index: trunk/Ohana/src/addstar/src/LoadStars.c
===================================================================
--- trunk/Ohana/src/addstar/src/LoadStars.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/LoadStars.c	(revision 38553)
@@ -1,71 +1,40 @@
 # include "addstar.h"
 
-Stars *LoadStars (char *filename, unsigned int *Nstars, Image **images, off_t *Nimages, AddstarClientOptions *options) {
+Catalog *LoadStars (char *filename, Image **images, off_t *Nimages, AddstarClientOptions *options) {
 
-  off_t *extsize, NheaderSets;
-  int i, Nfile, NFILE, Nheaders, mode;
-  char **file, line[1024];
-  FILE *f;
-  glob_t globList;
-  Header **headers;
-  Stars *stars;
-  HeaderSet *headerSets;
+  off_t *extsize;
+  int i, Nfile, mode;
 
-  if (options[0].filelist) {
-    // read the list of input files from the supplied file
-    f = fopen (filename, "r");
-    if (f == NULL) {
-      fprintf (stderr, "can't read input list %s, giving up\n", filename);
-      exit (1);
-    }
-
-    NFILE = 10;
-    ALLOCATE (file, char *, NFILE);
-    for (i = 0; (fscanf (f, "%s", line) != EOF); i++) {
-      // filename limited to 1024 chars
-      fprintf (stderr, "file: %s\n", line);
-      file[i] = strcreate (line);
-      if (i == NFILE - 1) {
-	NFILE += 10;
-	REALLOCATE (file, char *, NFILE);
-      }
-    }
-    Nfile = i;
-  } else {
-    // parse the filename as a glob
-    globList.gl_offs = 0;
-    glob (filename, 0, NULL, &globList);
-
-    // if the glob does not match, save the literal word:
-    // otherwise save all glob matches
-    if (globList.gl_pathc == 0) {
-      Nfile = 1;
-      ALLOCATE (file, char *, Nfile);
-      file[0] = strcreate (filename);
-    } else {
-      Nfile = globList.gl_pathc;
-      ALLOCATE (file, char *, Nfile);
-      for (i = 0; i < Nfile; i++) {
-	file[i] = strcreate (globList.gl_pathv[i]);
-      }
-    }
-  }
+  AddstarFile *file = LoadFilenames (&Nfile, filename, options);
 
   *Nimages = 0;
-  *Nstars = 0;
   *images = NULL;
-  stars = NULL;
+
+  Catalog *catalog = NULL;
+  ALLOCATE (catalog, Catalog, 1);
+  dvo_catalog_init (catalog, TRUE);
+  ALLOCATE (catalog->average, Average, 1);
+  ALLOCATE (catalog->measure, Measure, 1);
+  ALLOCATE (catalog->lensing, Lensing, 1);
 
   for (i = 0; i < Nfile; i++) {
-    f = fopen (file[i], "r");
+    FILE *f = fopen (file[i].filename, "r");
     if (f == NULL) {
-      fprintf (stderr, "can't read file %s, skipping\n", file[i]);
+      fprintf (stderr, "can't read file %s, skipping\n", file[i].filename);
       continue;
     }
 
+    int Nheaders = 0;
+    Header **headers = NULL;
+    off_t NheaderSets = 0;
+    HeaderSet *headerSets = NULL;
+
+    off_t NimagesStart = *Nimages;
+    Catalog *newcat = NULL;
+
     // load PMM data if specified (these are not stored as FITS-tables)
     if (PMM_CCD_TABLE != NULL) {
-      LoadDataPMM (f, file[i], images, Nimages, &stars, Nstars);
-      continue;
+      newcat = LoadDataPMM (f, file[i].imagename, images, Nimages);
+      goto next_file;
     }
 
@@ -74,12 +43,12 @@
     headerSets = MatchHeaders (&extsize, &NheaderSets, mode, headers, Nheaders);
     if (headerSets == NULL) {
-      fprintf (stderr, "ERROR: can't read headers for %s\n", file[i]);
-      continue;
+      fprintf (stderr, "ERROR: can't read headers for %s\n", file[i].filename);
+      goto next_file;
     }
     if (NheaderSets == 0) {
-      fprintf (stderr, "no object data in file %s, skipping\n", file[i]);
-      continue;
+      fprintf (stderr, "no object data in file %s, skipping\n", file[i].filename);
+      goto next_file;
     }
-    if (VERBOSE) fprintf (stderr, "file %s has %d headers, including "OFF_T_FMT" images\n", file[i], Nheaders,  NheaderSets);
+    if (VERBOSE) fprintf (stderr, "file %s has %d headers, including "OFF_T_FMT" images\n", file[i].filename, Nheaders,  NheaderSets);
 
     /* supplied photcode is incompatible with multi-chip images */
@@ -96,27 +65,51 @@
     // if these are SDSS data, load with SDSS-specific wrapper
     if (headerSets[0].exttype && !strcmp (headerSets[0].exttype, "SDSS_OBJ")) {
-      LoadDataSDSS (f, file[i], images, Nimages, &stars, Nstars, headers, extsize, headerSets, NheaderSets);
-      continue;
+      newcat = LoadDataSDSS (f, file[i].imagename, images, Nimages, headers, extsize, headerSets, NheaderSets);
+      goto next_file;
     }
 
     // if these are SDSS data, load with SDSS-specific wrapper
     if (headerSets[0].exttype && !strcmp (headerSets[0].exttype, "UKIRT_OBJ")) {
-      LoadDataUKIRT (f, file[i], images, Nimages, &stars, Nstars, headers, extsize, headerSets, NheaderSets);
-      continue;
+      newcat = LoadDataUKIRT (f, file[i].imagename, images, Nimages, headers, extsize, headerSets, NheaderSets);
+      goto next_file;
     }
 
-    LoadData (f, file[i], images, Nimages, &stars, Nstars, headers, extsize, headerSets, NheaderSets, options);
+    newcat = LoadData (f, &file[i], images, Nimages, headers, extsize, headerSets, NheaderSets, options);
 
-    // XXX add a function to (optionally) load the extended source measurements
-    # if (0)
-    if (extSources) {
-      // not sure how to link the measurements here to the psf measurements above (though there is an ID in the det list)
-      LoadDataXSRC (f, file[i], images, Nimages, &stars, Nstars, headers, extsize, headerSets, NheaderSets);
+  next_file:
+
+    // if we added data from an image, then we can merge it in
+    if (*Nimages > NimagesStart) {
+      double Rref, Dref;
+      XY_to_RD (&Rref, &Dref, 0.0, 0.0, &images[0][*Nimages-1].coords);
+      SkyRegion region;
+      region.Rmin = Rref - 180.0;
+      region.Rmax = Rref + 180.0;
+      region.Dmin = Dref -  90.0;
+      region.Dmax = Dref +  90.0;
+      
+      AddstarClientOptions matchOptions = *options;
+      matchOptions.radius = 0.4; // tight radius at this stage
+      matchOptions.calibrate = FALSE;
+      matchOptions.only_match = FALSE;
+      matchOptions.nosort = FALSE;
+      matchOptions.photcode = 0; // use an invalid photcode to avoid touching secfilt
+      
+      find_matches_closest (&region, newcat, catalog, matchOptions);
     }
-    if (extFits) {
-      LoadDataXFIT (f, file[i], images, Nimages, &stars, Nstars, headers, extsize, headerSets, NheaderSets);
+
+    if (newcat) {
+      dvo_catalog_free (newcat);
+      free (newcat);
     }
-    # endif
 
+    HeaderSetFree (headerSets, NheaderSets);
+    int j;
+    for (j = 0; j < Nheaders; j++) {
+      gfits_free_header (headers[j]);
+      FREE (headers[j]);
+    }
+    FREE (headers);
+    FREE (extsize);
   }
 
@@ -129,5 +122,6 @@
   }
 
-  return stars;
+  AddstarFileFree (file, Nfile);
+  return catalog;
 }
 
Index: trunk/Ohana/src/addstar/src/MatchHeaders.c
===================================================================
--- trunk/Ohana/src/addstar/src/MatchHeaders.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/MatchHeaders.c	(revision 38553)
@@ -2,4 +2,17 @@
 
 // XXX largely psphot specific
+
+void HeaderSetFree (HeaderSet *headerSets, off_t NheaderSets) {
+  int i;
+
+  if (!headerSets) return;
+  for (i = 0; i < NheaderSets; i++) {
+    FREE (headerSets[i].exthead);
+    FREE (headerSets[i].exttype);
+    FREE (headerSets[i].extdata);
+    FREE (headerSets[i].extxrad);
+  }
+  FREE (headerSets);
+}
 
 HeaderSet *MatchHeaders (off_t **extsize, off_t *nimage, int mode, Header **headers, int Nheaders) {
@@ -22,4 +35,6 @@
     headerSets[Nimage].exthead     = strcreate ("PHU");
     headerSets[Nimage].extdata     = strcreate ("NONE");
+    headerSets[Nimage].exttype     = NULL;
+    headerSets[Nimage].extxrad     = NULL;
     headerSets[Nimage].extnum_data = -1;
     headerSets[Nimage].extnum_head =  0;
@@ -34,4 +49,5 @@
     headerSets[0].exttype     = strcreate ("SDSS_OBJ");
     headerSets[0].exthead     = strcreate ("PHU");
+    headerSets[0].extxrad     = NULL;
     headerSets[0].extnum_head = 0;
     headerSets[0].extnum_data = 1;
@@ -112,9 +128,8 @@
 
   keep:
-    headerSets[Nimage].exttype = strcreate (exttype);
-
     gfits_scan (headers[i], ExtnameKeyword, "%s", 1, extname);
     gfits_scan (headers[i], "EXTHEAD", "%s", 1, exthead);
 
+    headerSets[Nimage].exttype     = strcreate (exttype);
     headerSets[Nimage].extdata     = strcreate (extname);
     headerSets[Nimage].exthead     = strcreate (exthead);
@@ -171,4 +186,5 @@
       headerSets[Nimage].exttype     = strcreate ("SMPDATA");
       headerSets[Nimage].exthead     = strcreate ("PHU");
+      headerSets[Nimage].extxrad     = NULL;
       headerSets[Nimage].extnum_head = 0;
       headerSets[Nimage].extnum_data = 1;
Index: trunk/Ohana/src/addstar/src/ReadStarsFITS.c
===================================================================
--- trunk/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 38553)
@@ -4,35 +4,48 @@
 // (excluding SDSS data and reference database info, such as 2MASS)
 // NOTE: these must also be listed in MatchHeaders.c (line ~ 62)
-Stars     *Convert_SMPDATA	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_DEV_0	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_DEV_1	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V1	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V1_Alt	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V2	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V3	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V4	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V5	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V5_R0_Lensing PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V5_R1_Lensing PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_V5_R2_Lensing PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_SV1	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_SV1_Alt	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_SV2	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_SV3	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_SV4	     PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_DV3           PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_DV4           PROTO((FTable *table, unsigned int *nstars));
-Stars     *Convert_PS1_DV5           PROTO((FTable *table, unsigned int *nstars));
+Catalog *Convert_SMPDATA           PROTO((FTable *table));
+Catalog *Convert_PS1_DEV_0         PROTO((FTable *table));
+Catalog *Convert_PS1_DEV_1         PROTO((FTable *table));
+Catalog *Convert_PS1_V1            PROTO((FTable *table));
+Catalog *Convert_PS1_V1_Alt        PROTO((FTable *table));
+Catalog *Convert_PS1_V2            PROTO((FTable *table));
+Catalog *Convert_PS1_V3            PROTO((FTable *table));
+Catalog *Convert_PS1_V4            PROTO((FTable *table));
+Catalog *Convert_PS1_V5            PROTO((FTable *table));
+Catalog *Convert_PS1_V5_R0_Lensing PROTO((FTable *table));
+Catalog *Convert_PS1_V5_R1_Lensing PROTO((FTable *table));
+Catalog *Convert_PS1_V5_R2_Lensing PROTO((FTable *table));
+Catalog *Convert_PS1_SV1           PROTO((FTable *table));
+Catalog *Convert_PS1_SV1_Alt       PROTO((FTable *table));
+Catalog *Convert_PS1_SV2           PROTO((FTable *table));
+Catalog *Convert_PS1_SV3           PROTO((FTable *table));
+Catalog *Convert_PS1_SV4           PROTO((FTable *table));
+Catalog *Convert_PS1_DV3           PROTO((FTable *table));
+Catalog *Convert_PS1_DV4           PROTO((FTable *table));
+Catalog *Convert_PS1_DV5           PROTO((FTable *table));
+
+Catalog *addstar_catalog_init (int Nstars) {
+  Catalog *catalog = NULL;
+  ALLOCATE (catalog, Catalog, 1);
+  dvo_catalog_init (catalog, TRUE);
+
+  ALLOCATE (catalog->measure, Measure, Nstars);
+
+  int i;
+  for (i = 0; i < Nstars; i++) {
+    dvo_measure_init (&catalog->measure[i]);
+  }
+  catalog->Nmeasure = Nstars;
+  return catalog;
+}
 
 // given a file with the pointer at the start of the table block and the 
 // corresponding image header, load the stars from the table
-Stars *ReadStarsFITS (FILE *f, Header *header, Header *in_theader, unsigned int *nstars) {
+Catalog *ReadStarsFITS (FILE *f, Header *header, Header *in_theader) {
 
   off_t Nskip;
-  unsigned int Nstars;
   char type[80];
   Header theader;
   FTable table;
-  Stars *stars; // Stars contains Average and Measure
   
   if (in_theader == NULL) {
@@ -55,16 +68,16 @@
   }
 
-  stars = NULL;
+  Catalog *catalog = NULL;
   if (!strcmp (type, "SMPDATA")) {
-    stars = Convert_SMPDATA (&table, &Nstars);
+    catalog = Convert_SMPDATA (&table);
   }
   if (!strcmp (type, "PS1_DEV_0")) {
-    stars = Convert_PS1_DEV_0 (&table, &Nstars);
+    catalog = Convert_PS1_DEV_0 (&table);
   }
   if (!strcmp (type, "PS1_DEV_1")) {
-    stars = Convert_PS1_DEV_1 (&table, &Nstars);
+    catalog = Convert_PS1_DEV_1 (&table);
   }
   if (!strcmp (type, "PS1_V1")) {
-    stars = Convert_PS1_V1 (&table, &Nstars);
+    catalog = Convert_PS1_V1 (&table);
   }
   if (!strcmp (type, "PS1_V2")) {
@@ -73,61 +86,59 @@
       return (NULL);
     }
-    stars = Convert_PS1_V2 (&table, &Nstars);
+    catalog = Convert_PS1_V2 (&table);
   }
   if (!strcmp (type, "PS1_V3")) {
-    stars = Convert_PS1_V3 (&table, &Nstars);
+    catalog = Convert_PS1_V3 (&table);
   }
   if (!strcmp (type, "PS1_V4")) {
-    stars = Convert_PS1_V4 (&table, &Nstars);
+    catalog = Convert_PS1_V4 (&table);
   }
   if (!strcmp (type, "PS1_V5")) {
     switch (table.header[0].Naxis[0]) {
       case 232:
-	stars = Convert_PS1_V5 (&table, &Nstars);
-	break;
+        catalog = Convert_PS1_V5 (&table);
+        break;
       case 312:
-	stars = Convert_PS1_V5_R0_Lensing (&table, &Nstars);
-	break;
+        catalog = Convert_PS1_V5_R0_Lensing (&table);
+        break;
       case 320:
-	stars = Convert_PS1_V5_R1_Lensing (&table, &Nstars);
-	break;
+        catalog = Convert_PS1_V5_R1_Lensing (&table);
+        break;
       case 328:
-	stars = Convert_PS1_V5_R2_Lensing (&table, &Nstars);
-	break;
+        catalog = Convert_PS1_V5_R2_Lensing (&table);
+        break;
       default:
-	fprintf (stderr, "invalid PS1_V5 table size %d\n", (int) table.header[0].Naxis[0]);
-	return NULL;
+        fprintf (stderr, "invalid PS1_V5 table size %d\n", (int) table.header[0].Naxis[0]);
+        return NULL;
     }
   }
   if (!strcmp (type, "PS1_SV1")) {
-    stars = Convert_PS1_SV1 (&table, &Nstars);
+    catalog = Convert_PS1_SV1 (&table);
   }
   if (!strcmp (type, "PS1_SV2")) {
-    stars = Convert_PS1_SV2 (&table, &Nstars);
+    catalog = Convert_PS1_SV2 (&table);
   }
   if (!strcmp (type, "PS1_SV3")) {
-    stars = Convert_PS1_SV3 (&table, &Nstars);
+    catalog = Convert_PS1_SV3 (&table);
   }
   if (!strcmp (type, "PS1_SV4")) {
-    stars = Convert_PS1_SV4 (&table, &Nstars);
+    catalog = Convert_PS1_SV4 (&table);
   }
   if (!strcmp (type, "PS1_DV3")) {
-    stars = Convert_PS1_DV3 (&table, &Nstars);
+    catalog = Convert_PS1_DV3 (&table);
   }
   if (!strcmp (type, "PS1_DV4")) {
-    stars = Convert_PS1_DV4 (&table, &Nstars);
+    catalog = Convert_PS1_DV4 (&table);
   }
   if (!strcmp (type, "PS1_DV5")) {
-    stars = Convert_PS1_DV5 (&table, &Nstars);
-  }
-  if (stars == NULL) {
+    catalog = Convert_PS1_DV5 (&table);
+  }
+  if (catalog == NULL) {
     fprintf (stderr, "invalid table type %s\n", type);
     return (NULL);
   }
-  // Nstars is not necessarily == *nstars (The former is the number of detections, the
-  // latter are the 'good' detections reported by the photometry system.
-  *nstars = Nstars;
-
-  return stars;
+
+  gfits_free_table (&table);
+  return catalog;
 }
 
@@ -149,10 +160,9 @@
 }
 
-Stars *Convert_SMPDATA (FTable *table, unsigned int *nstars) {
+Catalog *Convert_SMPDATA (FTable *table) {
 
   off_t Nstars;
   unsigned int i;
   double ZeroPt;
-  Stars *stars = NULL;
   SMPData *smpdata = NULL;
 
@@ -164,65 +174,62 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-
-    stars[i].measure.Xccd       = smpdata[i].X;
-    stars[i].measure.Yccd       = smpdata[i].Y;
-    stars[i].measure.dXccd    	= NAN_S_SHORT; // not provided by SMPDATA:
-    stars[i].measure.dYccd    	= NAN_S_SHORT; // not provided by SMPDATA:
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = smpdata[i].X;
+    catalog->measure[i].Yccd       = smpdata[i].Y;
+    catalog->measure[i].dXccd      = NAN_S_SHORT; // not provided by SMPDATA:
+    catalog->measure[i].dYccd      = NAN_S_SHORT; // not provided by SMPDATA:
    
-    stars[i].measure.posangle 	= NAN_S_SHORT; // not provided by SMPDATA:
-    stars[i].measure.pltscale 	= NAN;         // not provided by SMPDATA:
+    catalog->measure[i].posangle   = NAN_S_SHORT; // not provided by SMPDATA:
+    catalog->measure[i].pltscale   = NAN;         // not provided by SMPDATA:
 
     if ((smpdata[i].M >= ZeroPt) || isnan(smpdata[i].M)) {
-      stars[i].measure.M        = NAN;
-      stars[i].measure.Map      = NAN;
-      stars[i].measure.FluxPSF  = NAN;
-      stars[i].measure.dFluxPSF = NAN;
-    } else {
-      stars[i].measure.M        = smpdata[i].M;
-      stars[i].measure.Map      = smpdata[i].M;
-      stars[i].measure.FluxPSF  = pow(10.0, -0.4*smpdata[i].M);
-      stars[i].measure.dFluxPSF = stars[i].measure.FluxPSF * smpdata[i].dM;
-    }
-    stars[i].measure.dM         = smpdata[i].dM*0.001;
-    stars[i].measure.dMcal    	= NAN; // not provided by SMPDATA:
-
-    stars[i].measure.Mkron    	= NAN; // not provided by SMPDATA:
-    stars[i].measure.dMkron   	= NAN; // not provided by SMPDATA:
-    stars[i].measure.FluxKron   = NAN; // not provided by SMPDATA:
-    stars[i].measure.dFluxKron  = NAN; // not provided by SMPDATA:
-
-    stars[i].measure.Sky      	= NAN; // not provided by SMPDATA:
-    stars[i].measure.dSky     	= NAN; // not provided by SMPDATA:
-
-    stars[i].measure.psfChisq 	= NAN;	     // not provided by SMPDATA:
-    stars[i].measure.psfQF  	= NAN;	     // not provided by SMPDATA:
-    stars[i].measure.psfNdof    = NAN_S_INT; // not provided by SMPDATA:
-    stars[i].measure.psfNpix    = NAN_S_INT; // not provided by SMPDATA:
-    stars[i].measure.extNsigma  = NAN;	     // not provided by SMPDATA:
-
-    stars[i].measure.FWx        = ToShortPixels (smpdata[i].fx);
-    stars[i].measure.FWy        = ToShortPixels (smpdata[i].fy);
-    stars[i].measure.theta      = ToShortDegrees (smpdata[i].df);
-
-    stars[i].measure.Mxx        = NAN_S_SHORT; // not provided by SMPDATA:
-    stars[i].measure.Mxy        = NAN_S_SHORT; // not provided by SMPDATA:
-    stars[i].measure.Myy        = NAN_S_SHORT; // not provided by SMPDATA:
+      catalog->measure[i].M        = NAN;
+      catalog->measure[i].Map      = NAN;
+      catalog->measure[i].FluxPSF  = NAN;
+      catalog->measure[i].dFluxPSF = NAN;
+    } else {
+      catalog->measure[i].M        = smpdata[i].M;
+      catalog->measure[i].Map      = smpdata[i].M;
+      catalog->measure[i].FluxPSF  = pow(10.0, -0.4*smpdata[i].M);
+      catalog->measure[i].dFluxPSF = catalog->measure[i].FluxPSF * smpdata[i].dM;
+    }
+    catalog->measure[i].dM         = smpdata[i].dM*0.001;
+    catalog->measure[i].dMcal      = NAN; // not provided by SMPDATA:
+
+    catalog->measure[i].Mkron      = NAN; // not provided by SMPDATA:
+    catalog->measure[i].dMkron     = NAN; // not provided by SMPDATA:
+    catalog->measure[i].FluxKron   = NAN; // not provided by SMPDATA:
+    catalog->measure[i].dFluxKron  = NAN; // not provided by SMPDATA:
+
+    catalog->measure[i].Sky        = NAN; // not provided by SMPDATA:
+    catalog->measure[i].dSky       = NAN; // not provided by SMPDATA:
+
+    catalog->measure[i].psfChisq   = NAN;       // not provided by SMPDATA:
+    catalog->measure[i].psfQF      = NAN;       // not provided by SMPDATA:
+    catalog->measure[i].psfNdof    = NAN_S_INT; // not provided by SMPDATA:
+    catalog->measure[i].psfNpix    = NAN_S_INT; // not provided by SMPDATA:
+    catalog->measure[i].extNsigma  = NAN;       // not provided by SMPDATA:
+
+    catalog->measure[i].FWx        = ToShortPixels (smpdata[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels (smpdata[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees (smpdata[i].df);
+
+    catalog->measure[i].Mxx        = NAN_S_SHORT; // not provided by SMPDATA:
+    catalog->measure[i].Mxy        = NAN_S_SHORT; // not provided by SMPDATA:
+    catalog->measure[i].Myy        = NAN_S_SHORT; // not provided by SMPDATA:
                         
     // the dophot type information gets pushed into the upper 2 bytes of photFlags
-    stars[i].measure.photFlags  = (smpdata[i].dophot << 16);
-  }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_DEV_0 (FTable *table, unsigned int *nstars) {
+    catalog->measure[i].photFlags  = (smpdata[i].dophot << 16);
+  }    
+  return catalog;
+}
+
+Catalog *Convert_PS1_DEV_0 (FTable *table) {
 
   off_t Nstars;
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   PS1_DEV_0 *ps1data;
 
@@ -234,66 +241,64 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd     	= ps1data[i].X;
-    stars[i].measure.Yccd     	= ps1data[i].Y;
-    stars[i].measure.dXccd    	= ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd    	= ToShortPixels(ps1data[i].dY);
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
    
-    stars[i].measure.posangle 	= NAN_S_SHORT; // not provided by PS1_DEV_0:
-    stars[i].measure.pltscale 	= NAN;         // not provided by PS1_DEV_0:
+    catalog->measure[i].posangle   = NAN_S_SHORT; // not provided by PS1_DEV_0:
+    catalog->measure[i].pltscale   = NAN;         // not provided by PS1_DEV_0:
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      	= NAN;
-      stars[i].measure.FluxPSF  = NAN;
-      stars[i].measure.dFluxPSF = NAN;
-    } else {
-      stars[i].measure.M      	= ps1data[i].M + ZeroPt;
-      stars[i].measure.FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
-      stars[i].measure.dFluxPSF = stars[i].measure.FluxPSF * ps1data[i].dM;
-    }
-    stars[i].measure.dM       	= ps1data[i].dM;
-    stars[i].measure.dMcal    	= NAN; // not provided by PS1_DEV_0:
-    stars[i].measure.Map      	= NAN; // not provided by PS1_DEV_0:
-
-    stars[i].measure.Mkron    	= NAN; // not provided by PS1_DEV_0:
-    stars[i].measure.dMkron   	= NAN; // not provided by PS1_DEV_0:
-    stars[i].measure.FluxKron   = NAN; // not provided by PS1_DEV_0:
-    stars[i].measure.dFluxKron  = NAN; // not provided by PS1_DEV_0:
-
-    stars[i].measure.Sky      	= ps1data[i].sky;
-    stars[i].measure.dSky     	= ps1data[i].dSky;
-
-    stars[i].measure.psfChisq 	= ps1data[i].psfChisq;
-    stars[i].measure.psfQF  	= ps1data[i].psfQF;
-    stars[i].measure.psfNdof    = NAN_S_INT; // not provided by PS1_DEV_0:
-    stars[i].measure.psfNpix    = NAN_S_INT; // not provided by PS1_DEV_0:
-    stars[i].measure.extNsigma  = NAN;        // not provided by PS1_DEV_0:
-
-    stars[i].measure.FWx      	= ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy      	= ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta    	= ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = NAN_S_SHORT; // not provided by PS1_DEV_0:
-    stars[i].measure.Mxy        = NAN_S_SHORT; // not provided by PS1_DEV_0:
-    stars[i].measure.Myy        = NAN_S_SHORT; // not provided by PS1_DEV_0:
-                        
-    stars[i].measure.photFlags  = 0; // not provided by PS1_DEV_0:
-
-    stars[i].measure.detID      = ps1data[i].detID;
-  }    
-  *nstars = Nstars;
-  return (stars);
+      catalog->measure[i].M        = NAN;
+      catalog->measure[i].FluxPSF  = NAN;
+      catalog->measure[i].dFluxPSF = NAN;
+    } else {
+      catalog->measure[i].M        = ps1data[i].M + ZeroPt;
+      catalog->measure[i].FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
+      catalog->measure[i].dFluxPSF = catalog->measure[i].FluxPSF * ps1data[i].dM;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = NAN; // not provided by PS1_DEV_0:
+    catalog->measure[i].Map        = NAN; // not provided by PS1_DEV_0:
+
+    catalog->measure[i].Mkron      = NAN; // not provided by PS1_DEV_0:
+    catalog->measure[i].dMkron     = NAN; // not provided by PS1_DEV_0:
+    catalog->measure[i].FluxKron   = NAN; // not provided by PS1_DEV_0:
+    catalog->measure[i].dFluxKron  = NAN; // not provided by PS1_DEV_0:
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfNdof    = NAN_S_INT; // not provided by PS1_DEV_0:
+    catalog->measure[i].psfNpix    = NAN_S_INT; // not provided by PS1_DEV_0:
+    catalog->measure[i].extNsigma  = NAN;        // not provided by PS1_DEV_0:
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = NAN_S_SHORT; // not provided by PS1_DEV_0:
+    catalog->measure[i].Mxy        = NAN_S_SHORT; // not provided by PS1_DEV_0:
+    catalog->measure[i].Myy        = NAN_S_SHORT; // not provided by PS1_DEV_0:
+                        
+    catalog->measure[i].photFlags  = 0; // not provided by PS1_DEV_0:
+
+    catalog->measure[i].detID      = ps1data[i].detID;
+  }    
+  return catalog;
 }
 
 // XXX I need to make the IPP I/O functions and these functions
 // consistent wrt ZERO_POINT....
-Stars *Convert_PS1_DEV_1 (FTable *table, unsigned int *nstars) {
+Catalog *Convert_PS1_DEV_1 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   PS1_DEV_1 *ps1data;
 
@@ -305,65 +310,63 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = NAN_S_SHORT; // not provided by PS1_DEV_1:
-    stars[i].measure.pltscale   = NAN;         // not provided by PS1_DEV_1:
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = NAN_S_SHORT; // not provided by PS1_DEV_1:
+    catalog->measure[i].pltscale   = NAN;         // not provided by PS1_DEV_1:
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-      stars[i].measure.FluxPSF  = NAN;
-      stars[i].measure.dFluxPSF = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-      stars[i].measure.FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
-      stars[i].measure.dFluxPSF = stars[i].measure.FluxPSF * ps1data[i].dM;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = NAN; // not provided by PS1_DEV_1:
-    stars[i].measure.Map        = NAN; // not provided by PS1_DEV_1:
-
-    stars[i].measure.Mkron      = NAN; // not provided by PS1_DEV_1:
-    stars[i].measure.dMkron     = NAN; // not provided by PS1_DEV_1:
-    stars[i].measure.FluxKron   = NAN; // not provided by PS1_DEV_1:
-    stars[i].measure.dFluxKron  = NAN; // not provided by PS1_DEV_1:
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfNdof    = NAN_S_INT; // not provided by PS1_DEV_1:
-    stars[i].measure.psfNpix    = NAN_S_INT; // not provided by PS1_DEV_1:
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = NAN_S_SHORT; // not provided by PS1_DEV_1:
-    stars[i].measure.Mxy        = NAN_S_SHORT; // not provided by PS1_DEV_1:
-    stars[i].measure.Myy        = NAN_S_SHORT; // not provided by PS1_DEV_1:
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID;
-  }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V1 (FTable *table, unsigned int *nstars) {
+      catalog->measure[i].M      = NAN;
+      catalog->measure[i].FluxPSF  = NAN;
+      catalog->measure[i].dFluxPSF = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+      catalog->measure[i].FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
+      catalog->measure[i].dFluxPSF = catalog->measure[i].FluxPSF * ps1data[i].dM;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = NAN; // not provided by PS1_DEV_1:
+    catalog->measure[i].Map        = NAN; // not provided by PS1_DEV_1:
+
+    catalog->measure[i].Mkron      = NAN; // not provided by PS1_DEV_1:
+    catalog->measure[i].dMkron     = NAN; // not provided by PS1_DEV_1:
+    catalog->measure[i].FluxKron   = NAN; // not provided by PS1_DEV_1:
+    catalog->measure[i].dFluxKron  = NAN; // not provided by PS1_DEV_1:
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfNdof    = NAN_S_INT; // not provided by PS1_DEV_1:
+    catalog->measure[i].psfNpix    = NAN_S_INT; // not provided by PS1_DEV_1:
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = NAN_S_SHORT; // not provided by PS1_DEV_1:
+    catalog->measure[i].Mxy        = NAN_S_SHORT; // not provided by PS1_DEV_1:
+    catalog->measure[i].Myy        = NAN_S_SHORT; // not provided by PS1_DEV_1:
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID;
+  }    
+  return catalog;
+}
+
+Catalog *Convert_PS1_V1 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V1 *ps1data;
 
@@ -377,6 +380,6 @@
 
   if (table[0].header[0].Naxis[0] == 136) {
-    stars = Convert_PS1_V1_Alt (table, nstars);
-    return (stars);
+    Catalog *catalog = Convert_PS1_V1_Alt (table);
+    return catalog;
   }
 
@@ -388,55 +391,55 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-      stars[i].measure.FluxPSF  = NAN;
-      stars[i].measure.dFluxPSF = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-      stars[i].measure.FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
-      stars[i].measure.dFluxPSF = stars[i].measure.FluxPSF * ps1data[i].dM;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = ps1data[i].dM; // a proxy measure
-                        
-    stars[i].measure.Mkron      = NAN; // not provided by PS1_V1:
-    stars[i].measure.dMkron     = NAN; // not provided by PS1_V1:
-    stars[i].measure.FluxKron   = NAN; // not provided by PS1_V1:
-    stars[i].measure.dFluxKron  = NAN; // not provided by PS1_V1:
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+      catalog->measure[i].M      = NAN;
+      catalog->measure[i].FluxPSF  = NAN;
+      catalog->measure[i].dFluxPSF = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+      catalog->measure[i].FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
+      catalog->measure[i].dFluxPSF = catalog->measure[i].FluxPSF * ps1data[i].dM;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = ps1data[i].dM; // a proxy measure
+                        
+    catalog->measure[i].Mkron      = NAN; // not provided by PS1_V1:
+    catalog->measure[i].dMkron     = NAN; // not provided by PS1_V1:
+    catalog->measure[i].FluxKron   = NAN; // not provided by PS1_V1:
+    catalog->measure[i].dFluxKron  = NAN; // not provided by PS1_V1:
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -446,14 +449,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V1_Alt (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V1_Alt (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V2 *ps1data;
 
@@ -466,5 +467,5 @@
   // call a special conversion function if it is found.
 
-  ps1data = gfits_table_get_CMF_PS1_V1_Alt (table, &Nstars, NULL);
+  ps1data = gfits_table_get_CMF_PS1_V1_Alt (table, &Nstars, NULL); 
   if (!ps1data) {
     fprintf (stderr, "skipping inconsistent entry\n");
@@ -473,55 +474,55 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-      stars[i].measure.FluxPSF  = NAN;
-      stars[i].measure.dFluxPSF = NAN;
-    } else {
-      stars[i].measure.M        = ps1data[i].M + ZeroPt;
-      stars[i].measure.FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
-      stars[i].measure.dFluxPSF = stars[i].measure.FluxPSF * ps1data[i].dM;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = ps1data[i].dM; // a proxy measure
-                        
-    stars[i].measure.Mkron      = NAN; // not provided by PS1_V1_Alt:
-    stars[i].measure.dMkron     = NAN; // not provided by PS1_V1_Alt:
-    stars[i].measure.FluxKron   = NAN; // not provided by PS1_V1_Alt:
-    stars[i].measure.dFluxKron  = NAN; // not provided by PS1_V1_Alt:
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+      catalog->measure[i].M      = NAN;
+      catalog->measure[i].FluxPSF  = NAN;
+      catalog->measure[i].dFluxPSF = NAN;
+    } else {
+      catalog->measure[i].M        = ps1data[i].M + ZeroPt;
+      catalog->measure[i].FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
+      catalog->measure[i].dFluxPSF = catalog->measure[i].FluxPSF * ps1data[i].dM;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = ps1data[i].dM; // a proxy measure
+                        
+    catalog->measure[i].Mkron      = NAN; // not provided by PS1_V1_Alt:
+    catalog->measure[i].dMkron     = NAN; // not provided by PS1_V1_Alt:
+    catalog->measure[i].FluxKron   = NAN; // not provided by PS1_V1_Alt:
+    catalog->measure[i].dFluxKron  = NAN; // not provided by PS1_V1_Alt:
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -531,14 +532,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V2 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V2 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V2 *ps1data;
 
@@ -550,55 +549,55 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M        = NAN;
-      stars[i].measure.FluxPSF  = NAN;
-      stars[i].measure.dFluxPSF = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-      stars[i].measure.FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
-      stars[i].measure.dFluxPSF = stars[i].measure.FluxPSF * ps1data[i].dM;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = ps1data[i].dM; // a proxy measure
-                        
-    stars[i].measure.Mkron      = NAN; // not provided by PS1_V2:
-    stars[i].measure.dMkron     = NAN; // not provided by PS1_V2:
-    stars[i].measure.FluxKron   = NAN; // not provided by PS1_V2:
-    stars[i].measure.dFluxKron  = NAN; // not provided by PS1_V2:
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+      catalog->measure[i].M        = NAN;
+      catalog->measure[i].FluxPSF  = NAN;
+      catalog->measure[i].dFluxPSF = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+      catalog->measure[i].FluxPSF  = pow(10.0, -0.4*ps1data[i].M);
+      catalog->measure[i].dFluxPSF = catalog->measure[i].FluxPSF * ps1data[i].dM;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = ps1data[i].dM; // a proxy measure
+                        
+    catalog->measure[i].Mkron      = NAN; // not provided by PS1_V2:
+    catalog->measure[i].dMkron     = NAN; // not provided by PS1_V2:
+    catalog->measure[i].FluxKron   = NAN; // not provided by PS1_V2:
+    catalog->measure[i].dFluxKron  = NAN; // not provided by PS1_V2:
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -608,14 +607,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V3 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V3 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V3 *ps1data;
 
@@ -627,59 +624,59 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = ps1data[i].dM; // a proxy measure
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = ps1data[i].dM; // a proxy measure
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (NAN, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (NAN, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (NAN, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (NAN, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -692,14 +689,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V4 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V4 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V4 *ps1data;
 
@@ -711,60 +706,60 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -777,14 +772,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V5 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V5 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V5 *ps1data;
 
@@ -796,60 +789,60 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -862,14 +855,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V5_R0_Lensing (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V5_R0_Lensing (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V5_R0_Lensing *ps1data;
 
@@ -881,100 +872,101 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+  ALLOCATE (catalog->lensing, Lensing, Nstars);
+  catalog->Nlensing = Nstars;
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
-
-    ALLOCATE (stars[i].lensing, Lensing, 1);
-    dvo_lensing_init (stars[i].lensing);
-
-    stars[i].lensing->X11_sm_obj  = ps1data[i].X11_sm_obj;
-    stars[i].lensing->X12_sm_obj  = ps1data[i].X12_sm_obj;
-    stars[i].lensing->X22_sm_obj  = ps1data[i].X22_sm_obj;
-    stars[i].lensing->E1_sm_obj   = ps1data[i].E1_sm_obj;
-    stars[i].lensing->E2_sm_obj   = ps1data[i].E2_sm_obj;
-
-    stars[i].lensing->X11_sh_obj  = ps1data[i].X11_sh_obj;
-    stars[i].lensing->X12_sh_obj  = ps1data[i].X12_sh_obj;
-    stars[i].lensing->X22_sh_obj  = ps1data[i].X22_sh_obj;
-    stars[i].lensing->E1_sh_obj   = ps1data[i].E1_sh_obj;
-    stars[i].lensing->E2_sh_obj   = ps1data[i].E2_sh_obj;
-
-    stars[i].lensing->X11_sm_psf  = ps1data[i].X11_sm_psf;
-    stars[i].lensing->X12_sm_psf  = ps1data[i].X12_sm_psf;
-    stars[i].lensing->X22_sm_psf  = ps1data[i].X22_sm_psf;
-    stars[i].lensing->E1_sm_psf   = ps1data[i].E1_sm_psf;
-    stars[i].lensing->E2_sm_psf   = ps1data[i].E2_sm_psf;
-
-    stars[i].lensing->X11_sh_psf  = ps1data[i].X11_sh_psf;
-    stars[i].lensing->X12_sh_psf  = ps1data[i].X12_sh_psf;
-    stars[i].lensing->X22_sh_psf  = ps1data[i].X22_sh_psf;
-    stars[i].lensing->E1_sh_psf   = ps1data[i].E1_sh_psf;
-    stars[i].lensing->E2_sh_psf   = ps1data[i].E2_sh_psf;
-
-    // stars[i].lensing->F_ApR5    = ps1data[i].F_ApR5;
-    // stars[i].lensing->dF_ApR5   = ps1data[i].dF_ApR5;
-    // stars[i].lensing->sF_ApR5   = ps1data[i].sF_ApR5;
-    // stars[i].lensing->fF_ApR5   = ps1data[i].fF_ApR5;
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
+
+    dvo_lensing_init (&catalog->lensing[i]);
+
+    catalog->lensing[i].X11_sm_obj  = ps1data[i].X11_sm_obj;
+    catalog->lensing[i].X12_sm_obj  = ps1data[i].X12_sm_obj;
+    catalog->lensing[i].X22_sm_obj  = ps1data[i].X22_sm_obj;
+    catalog->lensing[i].E1_sm_obj   = ps1data[i].E1_sm_obj;
+    catalog->lensing[i].E2_sm_obj   = ps1data[i].E2_sm_obj;
+
+    catalog->lensing[i].X11_sh_obj  = ps1data[i].X11_sh_obj;
+    catalog->lensing[i].X12_sh_obj  = ps1data[i].X12_sh_obj;
+    catalog->lensing[i].X22_sh_obj  = ps1data[i].X22_sh_obj;
+    catalog->lensing[i].E1_sh_obj   = ps1data[i].E1_sh_obj;
+    catalog->lensing[i].E2_sh_obj   = ps1data[i].E2_sh_obj;
+
+    catalog->lensing[i].X11_sm_psf  = ps1data[i].X11_sm_psf;
+    catalog->lensing[i].X12_sm_psf  = ps1data[i].X12_sm_psf;
+    catalog->lensing[i].X22_sm_psf  = ps1data[i].X22_sm_psf;
+    catalog->lensing[i].E1_sm_psf   = ps1data[i].E1_sm_psf;
+    catalog->lensing[i].E2_sm_psf   = ps1data[i].E2_sm_psf;
+
+    catalog->lensing[i].X11_sh_psf  = ps1data[i].X11_sh_psf;
+    catalog->lensing[i].X12_sh_psf  = ps1data[i].X12_sh_psf;
+    catalog->lensing[i].X22_sh_psf  = ps1data[i].X22_sh_psf;
+    catalog->lensing[i].E1_sh_psf   = ps1data[i].E1_sh_psf;
+    catalog->lensing[i].E2_sh_psf   = ps1data[i].E2_sh_psf;
+
+    // catalog->lensing[i].F_ApR5    = ps1data[i].F_ApR5;
+    // catalog->lensing[i].dF_ApR5   = ps1data[i].dF_ApR5;
+    // catalog->lensing[i].sF_ApR5   = ps1data[i].sF_ApR5;
+    // catalog->lensing[i].fF_ApR5   = ps1data[i].fF_ApR5;
     // 
-    // stars[i].lensing->F_ApR6    = ps1data[i].F_ApR6;
-    // stars[i].lensing->dF_ApR6   = ps1data[i].dF_ApR6;
-    // stars[i].lensing->sF_ApR6   = ps1data[i].sF_ApR6;
-    // stars[i].lensing->fF_ApR6   = ps1data[i].fF_ApR6;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].lensing->detID      = ps1data[i].detID; 
+    // catalog->lensing[i].F_ApR6    = ps1data[i].F_ApR6;
+    // catalog->lensing[i].dF_ApR6   = ps1data[i].dF_ApR6;
+    // catalog->lensing[i].sF_ApR6   = ps1data[i].sF_ApR6;
+    // catalog->lensing[i].fF_ApR6   = ps1data[i].fF_ApR6;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->lensing[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -987,14 +979,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V5_R1_Lensing (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V5_R1_Lensing (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V5_R1_Lensing *ps1data;
 
@@ -1006,100 +996,101 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+  ALLOCATE (catalog->lensing, Lensing, Nstars);
+  catalog->Nlensing = Nstars;
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
-
-    ALLOCATE (stars[i].lensing, Lensing, 1);
-    dvo_lensing_init (stars[i].lensing);
-
-    stars[i].lensing->X11_sm_obj  = ps1data[i].X11_sm_obj;
-    stars[i].lensing->X12_sm_obj  = ps1data[i].X12_sm_obj;
-    stars[i].lensing->X22_sm_obj  = ps1data[i].X22_sm_obj;
-    stars[i].lensing->E1_sm_obj   = ps1data[i].E1_sm_obj;
-    stars[i].lensing->E2_sm_obj   = ps1data[i].E2_sm_obj;
-
-    stars[i].lensing->X11_sh_obj  = ps1data[i].X11_sh_obj;
-    stars[i].lensing->X12_sh_obj  = ps1data[i].X12_sh_obj;
-    stars[i].lensing->X22_sh_obj  = ps1data[i].X22_sh_obj;
-    stars[i].lensing->E1_sh_obj   = ps1data[i].E1_sh_obj;
-    stars[i].lensing->E2_sh_obj   = ps1data[i].E2_sh_obj;
-
-    stars[i].lensing->X11_sm_psf  = ps1data[i].X11_sm_psf;
-    stars[i].lensing->X12_sm_psf  = ps1data[i].X12_sm_psf;
-    stars[i].lensing->X22_sm_psf  = ps1data[i].X22_sm_psf;
-    stars[i].lensing->E1_sm_psf   = ps1data[i].E1_sm_psf;
-    stars[i].lensing->E2_sm_psf   = ps1data[i].E2_sm_psf;
-
-    stars[i].lensing->X11_sh_psf  = ps1data[i].X11_sh_psf;
-    stars[i].lensing->X12_sh_psf  = ps1data[i].X12_sh_psf;
-    stars[i].lensing->X22_sh_psf  = ps1data[i].X22_sh_psf;
-    stars[i].lensing->E1_sh_psf   = ps1data[i].E1_sh_psf;
-    stars[i].lensing->E2_sh_psf   = ps1data[i].E2_sh_psf;
-
-    // stars[i].lensing->F_ApR5    = ps1data[i].F_ApR5;
-    // stars[i].lensing->dF_ApR5   = ps1data[i].dF_ApR5;
-    // stars[i].lensing->sF_ApR5   = ps1data[i].sF_ApR5;
-    // stars[i].lensing->fF_ApR5   = ps1data[i].fF_ApR5;
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
+
+    dvo_lensing_init (&catalog->lensing[i]);
+
+    catalog->lensing[i].X11_sm_obj  = ps1data[i].X11_sm_obj;
+    catalog->lensing[i].X12_sm_obj  = ps1data[i].X12_sm_obj;
+    catalog->lensing[i].X22_sm_obj  = ps1data[i].X22_sm_obj;
+    catalog->lensing[i].E1_sm_obj   = ps1data[i].E1_sm_obj;
+    catalog->lensing[i].E2_sm_obj   = ps1data[i].E2_sm_obj;
+
+    catalog->lensing[i].X11_sh_obj  = ps1data[i].X11_sh_obj;
+    catalog->lensing[i].X12_sh_obj  = ps1data[i].X12_sh_obj;
+    catalog->lensing[i].X22_sh_obj  = ps1data[i].X22_sh_obj;
+    catalog->lensing[i].E1_sh_obj   = ps1data[i].E1_sh_obj;
+    catalog->lensing[i].E2_sh_obj   = ps1data[i].E2_sh_obj;
+
+    catalog->lensing[i].X11_sm_psf  = ps1data[i].X11_sm_psf;
+    catalog->lensing[i].X12_sm_psf  = ps1data[i].X12_sm_psf;
+    catalog->lensing[i].X22_sm_psf  = ps1data[i].X22_sm_psf;
+    catalog->lensing[i].E1_sm_psf   = ps1data[i].E1_sm_psf;
+    catalog->lensing[i].E2_sm_psf   = ps1data[i].E2_sm_psf;
+
+    catalog->lensing[i].X11_sh_psf  = ps1data[i].X11_sh_psf;
+    catalog->lensing[i].X12_sh_psf  = ps1data[i].X12_sh_psf;
+    catalog->lensing[i].X22_sh_psf  = ps1data[i].X22_sh_psf;
+    catalog->lensing[i].E1_sh_psf   = ps1data[i].E1_sh_psf;
+    catalog->lensing[i].E2_sh_psf   = ps1data[i].E2_sh_psf;
+
+    // catalog->lensing[i].F_ApR5    = ps1data[i].F_ApR5;
+    // catalog->lensing[i].dF_ApR5   = ps1data[i].dF_ApR5;
+    // catalog->lensing[i].sF_ApR5   = ps1data[i].sF_ApR5;
+    // catalog->lensing[i].fF_ApR5   = ps1data[i].fF_ApR5;
     // 
-    // stars[i].lensing->F_ApR6    = ps1data[i].F_ApR6;
-    // stars[i].lensing->dF_ApR6   = ps1data[i].dF_ApR6;
-    // stars[i].lensing->sF_ApR6   = ps1data[i].sF_ApR6;
-    // stars[i].lensing->fF_ApR6   = ps1data[i].fF_ApR6;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].lensing->detID      = ps1data[i].detID; 
+    // catalog->lensing[i].F_ApR6    = ps1data[i].F_ApR6;
+    // catalog->lensing[i].dF_ApR6   = ps1data[i].dF_ApR6;
+    // catalog->lensing[i].sF_ApR6   = ps1data[i].sF_ApR6;
+    // catalog->lensing[i].fF_ApR6   = ps1data[i].fF_ApR6;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->lensing[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1112,17 +1103,38 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_V5_R2_Lensing (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_V5_R2_Lensing (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_V5_R2_Lensing *ps1data;
 
-  ps1data = gfits_table_get_CMF_PS1_V5_R2_Lensing (table, &Nstars, NULL);
+  // this code expects the output cmf files to have a fixed column order
+  // unfortunatly, psphot is not consistent for the obj lensing values:
+  // if the first object in the list is not a valid object for the lensing measurement, then
+  // the lensingOBJ structure is not allocated for that source and the corresponding rows
+  // are not added to the output metadata until an object which does include the
+  // measurement.
+
+  char field[128];
+  gfits_scan (table->header, "TTYPE45", "%s", 1, field);
+
+  int mode = 0;
+  if (!strcmp (field, "LENS_X11_SM_OBJ")) { mode = 1; }
+  if (!strcmp (field, "LENS_X11_SM_PSF")) { mode = 2; }
+  myAssert (mode, "invalid table layout\n");
+
+  if (mode == 1) {
+    ps1data = gfits_table_get_CMF_PS1_V5_R2_Lensing (table, &Nstars, NULL);
+    fprintf (stderr, "PS1_V5_R2_Lensing mode 1\n");
+  } 
+  if (mode == 2) {
+    ps1data = gfits_table_get_CMF_PS1_V5_R2x_Lensing (table, &Nstars, NULL);
+    fprintf (stderr, "PS1_V5_R2_Lensing mode 2\n");
+  } 
+
   if (!ps1data) {
     fprintf (stderr, "skipping inconsistent entry\n");
@@ -1131,103 +1143,94 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+  ALLOCATE (catalog->lensing, Lensing, Nstars);
+  catalog->Nlensing = Nstars;
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
-
-    ALLOCATE (stars[i].lensing, Lensing, 1);
-    dvo_lensing_init (stars[i].lensing);
-
-    stars[i].lensing->X11_sm_obj  = ps1data[i].X11_sm_obj;
-    stars[i].lensing->X12_sm_obj  = ps1data[i].X12_sm_obj;
-    stars[i].lensing->X22_sm_obj  = ps1data[i].X22_sm_obj;
-    stars[i].lensing->E1_sm_obj   = ps1data[i].E1_sm_obj;
-    stars[i].lensing->E2_sm_obj   = ps1data[i].E2_sm_obj;
-
-    stars[i].lensing->X11_sh_obj  = ps1data[i].X11_sh_obj;
-    stars[i].lensing->X12_sh_obj  = ps1data[i].X12_sh_obj;
-    stars[i].lensing->X22_sh_obj  = ps1data[i].X22_sh_obj;
-    stars[i].lensing->E1_sh_obj   = ps1data[i].E1_sh_obj;
-    stars[i].lensing->E2_sh_obj   = ps1data[i].E2_sh_obj;
-
-    stars[i].lensing->X11_sm_psf  = ps1data[i].X11_sm_psf;
-    stars[i].lensing->X12_sm_psf  = ps1data[i].X12_sm_psf;
-    stars[i].lensing->X22_sm_psf  = ps1data[i].X22_sm_psf;
-    stars[i].lensing->E1_sm_psf   = ps1data[i].E1_sm_psf;
-    stars[i].lensing->E2_sm_psf   = ps1data[i].E2_sm_psf;
-
-    stars[i].lensing->X11_sh_psf  = ps1data[i].X11_sh_psf;
-    stars[i].lensing->X12_sh_psf  = ps1data[i].X12_sh_psf;
-    stars[i].lensing->X22_sh_psf  = ps1data[i].X22_sh_psf;
-    stars[i].lensing->E1_sh_psf   = ps1data[i].E1_sh_psf;
-    stars[i].lensing->E2_sh_psf   = ps1data[i].E2_sh_psf;
-
-    stars[i].lensing->E1_psf      = ps1data[i].E1_psf;
-    stars[i].lensing->E2_psf      = ps1data[i].E2_psf;
-
-    // stars[i].lensing->F_ApR5    = ps1data[i].F_ApR5;
-    // stars[i].lensing->dF_ApR5   = ps1data[i].dF_ApR5;
-    // stars[i].lensing->sF_ApR5   = ps1data[i].sF_ApR5;
-    // stars[i].lensing->fF_ApR5   = ps1data[i].fF_ApR5;
-    // 
-    // stars[i].lensing->F_ApR6    = ps1data[i].F_ApR6;
-    // stars[i].lensing->dF_ApR6   = ps1data[i].dF_ApR6;
-    // stars[i].lensing->sF_ApR6   = ps1data[i].sF_ApR6;
-    // stars[i].lensing->fF_ApR6   = ps1data[i].fF_ApR6;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].lensing->detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
+
+    dvo_lensing_init (&catalog->lensing[i]);
+
+    catalog->lensing[i].X11_sm_obj  = ps1data[i].X11_sm_obj;
+    catalog->lensing[i].X12_sm_obj  = ps1data[i].X12_sm_obj;
+    catalog->lensing[i].X22_sm_obj  = ps1data[i].X22_sm_obj;
+    catalog->lensing[i].E1_sm_obj   = ps1data[i].E1_sm_obj;
+    catalog->lensing[i].E2_sm_obj   = ps1data[i].E2_sm_obj;
+
+    catalog->lensing[i].X11_sh_obj  = ps1data[i].X11_sh_obj;
+    catalog->lensing[i].X12_sh_obj  = ps1data[i].X12_sh_obj;
+    catalog->lensing[i].X22_sh_obj  = ps1data[i].X22_sh_obj;
+    catalog->lensing[i].E1_sh_obj   = ps1data[i].E1_sh_obj;
+    catalog->lensing[i].E2_sh_obj   = ps1data[i].E2_sh_obj;
+
+    catalog->lensing[i].X11_sm_psf  = ps1data[i].X11_sm_psf;
+    catalog->lensing[i].X12_sm_psf  = ps1data[i].X12_sm_psf;
+    catalog->lensing[i].X22_sm_psf  = ps1data[i].X22_sm_psf;
+    catalog->lensing[i].E1_sm_psf   = ps1data[i].E1_sm_psf;
+    catalog->lensing[i].E2_sm_psf   = ps1data[i].E2_sm_psf;
+
+    catalog->lensing[i].X11_sh_psf  = ps1data[i].X11_sh_psf;
+    catalog->lensing[i].X12_sh_psf  = ps1data[i].X12_sh_psf;
+    catalog->lensing[i].X22_sh_psf  = ps1data[i].X22_sh_psf;
+    catalog->lensing[i].E1_sh_psf   = ps1data[i].E1_sh_psf;
+    catalog->lensing[i].E2_sh_psf   = ps1data[i].E2_sh_psf;
+
+    catalog->lensing[i].E1_psf      = ps1data[i].E1_psf;
+    catalog->lensing[i].E2_psf      = ps1data[i].E2_psf;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->lensing[i].detID       = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1240,19 +1243,17 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_SV1 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_SV1 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_SV1 *ps1data;
 
   if (table[0].header[0].Naxis[0] == 196) {
-    stars = Convert_PS1_SV1_Alt (table, nstars);
-    return (stars);
+    Catalog *catalog = Convert_PS1_SV1_Alt (table);
+    return catalog;
   }
 
@@ -1264,60 +1265,60 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = ps1data[i].dM; // a proxy measure
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = ps1data[i].dM; // a proxy measure
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
 
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (NAN, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (NAN, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (NAN, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (NAN, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1327,18 +1328,15 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_SV1_Alt (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_SV1_Alt (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_SV1 *ps1data;
 
   // some test output files were produced called CMF_PS1_SV1 but with mismatch byte boundaries
-
   ps1data = gfits_table_get_CMF_PS1_SV1_Alt (table, &Nstars, NULL);
   if (!ps1data) {
@@ -1348,58 +1346,58 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = ps1data[i].dM; // a proxy measure
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = ps1data[i].dM; // a proxy measure
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
 
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (NAN, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (NAN, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (NAN, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (NAN, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1409,14 +1407,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_SV2 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_SV2 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_SV2 *ps1data;
 
@@ -1428,60 +1424,60 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
 
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1491,14 +1487,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_SV3 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_SV3 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_SV3 *ps1data;
 
@@ -1510,60 +1504,60 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
 
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1573,14 +1567,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_SV4 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_SV4 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_SV4 *ps1data;
 
@@ -1592,60 +1584,60 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
 
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1655,14 +1647,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_DV3 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_DV3 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_DV3 *ps1data;
 
@@ -1674,59 +1664,59 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1739,14 +1729,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_DV4 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_DV4 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_DV4 *ps1data;
 
@@ -1760,59 +1748,59 @@
   fprintf (stderr, "WARNING: Convert_PS1_DV4 not yet updated to match real format\n");
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1825,14 +1813,12 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-Stars *Convert_PS1_DV5 (FTable *table, unsigned int *nstars) {
+  return catalog;
+}
+
+Catalog *Convert_PS1_DV5 (FTable *table) {
 
   off_t Nstars; 
   unsigned int i;
   double ZeroPt;
-  Stars *stars;
   CMF_PS1_DV5 *ps1data;
 
@@ -1844,59 +1830,59 @@
   ZeroPt = GetZeroPoint();
 
-  ALLOCATE (stars, Stars, Nstars);
-  for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-    stars[i].measure.Xccd       = ps1data[i].X;
-    stars[i].measure.Yccd       = ps1data[i].Y;
-    stars[i].measure.dXccd      = ToShortPixels(ps1data[i].dX);
-    stars[i].measure.dYccd      = ToShortPixels(ps1data[i].dY);
-
-    stars[i].measure.posangle   = ToShortDegrees(ps1data[i].posangle);
-    stars[i].measure.pltscale   = ps1data[i].pltscale;
+  Catalog *catalog = addstar_catalog_init (Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    catalog->measure[i].Xccd       = ps1data[i].X;
+    catalog->measure[i].Yccd       = ps1data[i].Y;
+    catalog->measure[i].dXccd      = ToShortPixels(ps1data[i].dX);
+    catalog->measure[i].dYccd      = ToShortPixels(ps1data[i].dY);
+
+    catalog->measure[i].posangle   = ToShortDegrees(ps1data[i].posangle);
+    catalog->measure[i].pltscale   = ps1data[i].pltscale;
 
     if ((ps1data[i].M >= 0.0) || isnan(ps1data[i].M)) {
-      stars[i].measure.M      = NAN;
-    } else {
-      stars[i].measure.M      = ps1data[i].M + ZeroPt;
-    }
-    stars[i].measure.dM         = ps1data[i].dM;
-    stars[i].measure.dMcal      = ps1data[i].dMcal;
-    stars[i].measure.Map        = ps1data[i].Map + ZeroPt;
-    stars[i].measure.dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
-                        
-    stars[i].measure.Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
-    stars[i].measure.dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
+      catalog->measure[i].M      = NAN;
+    } else {
+      catalog->measure[i].M      = ps1data[i].M + ZeroPt;
+    }
+    catalog->measure[i].dM         = ps1data[i].dM;
+    catalog->measure[i].dMcal      = ps1data[i].dMcal;
+    catalog->measure[i].Map        = ps1data[i].Map + ZeroPt;
+    catalog->measure[i].dMap       = (ps1data[i].apFlux > 0.0) ? fabs(ps1data[i].apFluxErr / ps1data[i].apFlux) : NAN;
+                        
+    catalog->measure[i].Mkron      = (ps1data[i].kronFlux > 0.0) ? -2.5*log10(ps1data[i].kronFlux) + ZeroPt : NAN;
+    catalog->measure[i].dMkron     = (ps1data[i].kronFlux > 0.0) ? ps1data[i].kronFluxErr / ps1data[i].kronFlux : NAN;
                         
     // these fluxes are converted from counts to counts/sec in FilterStars.c
-    stars[i].measure.FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
-    stars[i].measure.dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, stars[i].measure.FluxPSF, ps1data[i].dM);
-    stars[i].measure.FluxKron   = ps1data[i].kronFlux;
-    stars[i].measure.dFluxKron  = ps1data[i].kronFluxErr;
-    stars[i].measure.FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
-    stars[i].measure.dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, stars[i].measure.FluxAp, stars[i].measure.dMap);
-
-    stars[i].measure.Sky        = ps1data[i].sky;
-    stars[i].measure.dSky       = ps1data[i].dSky;
-                        
-    stars[i].measure.psfChisq   = ps1data[i].psfChisq;
-    stars[i].measure.psfQF      = ps1data[i].psfQF;
-    stars[i].measure.psfQFperf  = ps1data[i].psfQFperf;
-    stars[i].measure.psfNdof    = ps1data[i].psfNdof;
-    stars[i].measure.psfNpix    = ps1data[i].psfNpix;
-    stars[i].measure.extNsigma  = ps1data[i].extNsigma;
-
-    stars[i].measure.FWx        = ToShortPixels(ps1data[i].fx);
-    stars[i].measure.FWy        = ToShortPixels(ps1data[i].fy);
-    stars[i].measure.theta      = ToShortDegrees(ps1data[i].df);
-
-    stars[i].measure.Mxx        = ToShortPixels(ps1data[i].Mxx);
-    stars[i].measure.Mxy        = ToShortPixels(ps1data[i].Mxy);
-    stars[i].measure.Myy        = ToShortPixels(ps1data[i].Myy);
-                        
-    stars[i].measure.photFlags  = ps1data[i].flags;
-    stars[i].measure.photFlags2 = ps1data[i].flags2;
-
-    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
-    stars[i].measure.detID      = ps1data[i].detID; 
+    catalog->measure[i].FluxPSF    = GetFluxFromFluxOrMag (ps1data[i].Flux, ps1data[i].M); 
+    catalog->measure[i].dFluxPSF   = GetFluxErrFromFluxOrMag (ps1data[i].dFlux, catalog->measure[i].FluxPSF, ps1data[i].dM);
+    catalog->measure[i].FluxKron   = ps1data[i].kronFlux;
+    catalog->measure[i].dFluxKron  = ps1data[i].kronFluxErr;
+    catalog->measure[i].FluxAp     = GetFluxFromFluxOrMag (ps1data[i].apFlux, ps1data[i].Map); 
+    catalog->measure[i].dFluxAp    = GetFluxErrFromFluxOrMag (ps1data[i].apFluxErr, catalog->measure[i].FluxAp, catalog->measure[i].dMap);
+
+    catalog->measure[i].Sky        = ps1data[i].sky;
+    catalog->measure[i].dSky       = ps1data[i].dSky;
+                        
+    catalog->measure[i].psfChisq   = ps1data[i].psfChisq;
+    catalog->measure[i].psfQF      = ps1data[i].psfQF;
+    catalog->measure[i].psfQFperf  = ps1data[i].psfQFperf;
+    catalog->measure[i].psfNdof    = ps1data[i].psfNdof;
+    catalog->measure[i].psfNpix    = ps1data[i].psfNpix;
+    catalog->measure[i].extNsigma  = ps1data[i].extNsigma;
+
+    catalog->measure[i].FWx        = ToShortPixels(ps1data[i].fx);
+    catalog->measure[i].FWy        = ToShortPixels(ps1data[i].fy);
+    catalog->measure[i].theta      = ToShortDegrees(ps1data[i].df);
+
+    catalog->measure[i].Mxx        = ToShortPixels(ps1data[i].Mxx);
+    catalog->measure[i].Mxy        = ToShortPixels(ps1data[i].Mxy);
+    catalog->measure[i].Myy        = ToShortPixels(ps1data[i].Myy);
+                        
+    catalog->measure[i].photFlags  = ps1data[i].flags;
+    catalog->measure[i].photFlags2 = ps1data[i].flags2;
+
+    // this is may optionally be replaced by the internal sequence (see FilterStars.c)
+    catalog->measure[i].detID      = ps1data[i].detID; 
 
     // the Average fields and the following Measure fields are set in FilterStars after
@@ -1909,8 +1895,4 @@
     // the following fields are currently not being set anywhere: t_msec
   }    
-  *nstars = Nstars;
-  return (stars);
-}
-
-
-
+  return catalog;
+}
Index: trunk/Ohana/src/addstar/src/ReadStarsSDSS.c
===================================================================
--- trunk/Ohana/src/addstar/src/ReadStarsSDSS.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/ReadStarsSDSS.c	(revision 38553)
@@ -1,5 +1,5 @@
 # include "addstar.h"
 
-int SetSDSSFlags (Stars *star, unsigned int flags1, unsigned int flags2);
+int SetSDSSFlags (Measure *measure, unsigned int flags1, unsigned int flags2);
 
 # define NFILTER 5
@@ -33,5 +33,5 @@
 // given a file with the pointer at the start of the table block and the 
 // corresponding image header, load the stars from the table
-Stars *ReadStarsSDSS (FILE *f, char *name, Header *header, Header *in_theader, Image *images, off_t *nimages, unsigned int *nstars) {
+Catalog *ReadStarsSDSS (FILE *f, char *name, Header *header, Header *in_theader, Image *images, off_t *nimages) {
 
   off_t Nskip, Nrow;
@@ -40,5 +40,4 @@
   Header theader;
   FTable table;
-  Stars *stars;
   double clockRate, mjd[5], jd, sidtime, alt, az;
   float seeing[5], photErr[5], zeropt[5], ZeroPt;
@@ -113,5 +112,18 @@
   // create a Star entry for each filter and detection
   Nstars = table.header[0].Naxis[1];
-  ALLOCATE (stars, Stars, NFILTER*Nstars);
+
+  Catalog *catalog = NULL;
+  ALLOCATE (catalog, Catalog, 1);
+  dvo_catalog_init (catalog, TRUE);
+
+  ALLOCATE (catalog->average, Average, Nstars);
+  ALLOCATE (catalog->measure, Measure, NFILTER*Nstars);
+
+  for (i = 0; i < Nstars; i++) {
+    for (j = 0; j < NFILTER; j++) {
+      dvo_measure_init (&catalog->measure[i*NFILTER + j]);
+    }
+    dvo_average_init (&catalog->average[i]);
+  }
 
   GET_COLUMN_5 (rowc, float);
@@ -145,37 +157,38 @@
 
   for (i = 0; i < Nstars; i++) {
+    // any values not explicitly set are left at 0.0
+    catalog->average[i].R             = ra[i] + dCOS(dec[i]) * offsetRa[i*NFILTER] / 3600.0;
+    catalog->average[i].D             = dec[i] + offsetDec[i*NFILTER] / 3600.0;
+    catalog->average[i].dR            = NAN;
+    catalog->average[i].dD            = NAN;
+    catalog->average[i].Nmeasure      = NFILTER;
+    catalog->average[i].measureOffset = i*NFILTER;
+
     for (j = 0; j < NFILTER; j++) {
       N = NFILTER*i + j;
-      InitStar (&stars[N]);
       
-      // any values not explicitly set are left at 0.0
-      stars[N].average.R         = ra[i] + dCOS(dec[i]) * offsetRa[N] / 3600.0;
-      stars[N].average.D         = dec[i] + offsetDec[N] / 3600.0;
-      stars[N].average.dR        = NAN;
-      stars[N].average.dD        = NAN;
-
-      stars[N].measure.R         = stars[N].average.R;
-      stars[N].measure.D         = stars[N].average.D;
-      stars[N].measure.Xccd      = colc[N];
-      stars[N].measure.Yccd      = rowc[N];
-      stars[N].measure.dXccd     = ToShortPixels(colcErr[N]);
-      stars[N].measure.dYccd     = ToShortPixels(rowcErr[N]);
-      stars[N].measure.M         = psfCounts[N] + ZeroPt - zeropt[j];
-      stars[N].measure.dM        = psfCountsErr[N];
-      stars[N].measure.Map       = fiberCounts[N] + ZeroPt - zeropt[j];
-      stars[N].measure.Sky       = sky[N]; // adjust this to counts?
-      stars[N].measure.dSky      = skyErr[N];
-      stars[N].measure.FWx       = ToShortPixels(seeing[j]); // reported in arcsec?
-      stars[N].measure.FWy       = ToShortPixels(seeing[j]);
+      catalog->measure[N].R         = catalog->average[i].R;
+      catalog->measure[N].D         = catalog->average[i].D;
+      catalog->measure[N].Xccd      = colc[N];
+      catalog->measure[N].Yccd      = rowc[N];
+      catalog->measure[N].dXccd     = ToShortPixels(colcErr[N]);
+      catalog->measure[N].dYccd     = ToShortPixels(rowcErr[N]);
+      catalog->measure[N].M         = psfCounts[N] + ZeroPt - zeropt[j];
+      catalog->measure[N].dM        = psfCountsErr[N];
+      catalog->measure[N].Map       = fiberCounts[N] + ZeroPt - zeropt[j];
+      catalog->measure[N].Sky       = sky[N]; // adjust this to counts?
+      catalog->measure[N].dSky      = skyErr[N];
+      catalog->measure[N].FWx       = ToShortPixels(seeing[j]); // reported in arcsec?
+      catalog->measure[N].FWy       = ToShortPixels(seeing[j]);
       if (prob_psf) {
-          stars[N].measure.psfChisq  = prob_psf[N]; // XXX not really the correct value...
+          catalog->measure[N].psfChisq  = prob_psf[N]; // XXX not really the correct value...
       } else {
-          stars[N].measure.psfChisq  = NAN;
+          catalog->measure[N].psfChisq  = NAN;
       }
-      stars[N].measure.detID     = N;
-      stars[N].measure.t         = tzero[j] + clockRate*rowc[N]; // time since row 0
-      stars[N].measure.dt        = 4.32912209; // 2.5 * log(53.907456) the sdss exposure time // old comment is 53907456 is this 2048*clockRate ?
-
-      SetSDSSFlags (&stars[N], flags[N], flags2[N]);
+      catalog->measure[N].detID     = N;
+      catalog->measure[N].t         = tzero[j] + clockRate*rowc[N]; // time since row 0
+      catalog->measure[N].dt        = 4.32912209; // 2.5 * log(53.907456) the sdss exposure time // old comment is 53907456 is this 2048*clockRate ?
+
+      SetSDSSFlags (&catalog->measure[N], flags[N], flags2[N]);
 
       // longitude and latitude for SDSS:
@@ -187,12 +200,12 @@
       double Latitude = 32.7803611755; // degrees
 
-      jd = ohana_sec_to_jd (stars[N].measure.t);
+      jd = ohana_sec_to_jd (catalog->measure[N].t);
       sidtime  = 15.0*ohana_lst (jd, Longitude); // sidtime in degrees
-      altaz (&alt, &az, sidtime - stars[N].average.R, stars[N].average.D, Latitude);
-
-      stars[N].measure.airmass   = 1.0 / dCOS(90.0 - alt);
-      stars[N].measure.az        = az;
-      stars[N].measure.photcode  = photcode[j];
-      stars[N].measure.imageID   = j + *nimages; // set imageID to entry for this filter
+      altaz (&alt, &az, sidtime - catalog->average[i].R, catalog->average[i].D, Latitude);
+
+      catalog->measure[N].airmass   = 1.0 / dCOS(90.0 - alt);
+      catalog->measure[N].az        = az;
+      catalog->measure[N].photcode  = photcode[j];
+      catalog->measure[N].imageID   = j + *nimages; // set imageID to entry for this filter
     }
   }    
@@ -204,8 +217,8 @@
     // XXX for now, we define a totally fake coordinate system centered on the first listed star
     InitCoords (&images[N].coords, "DEC--TAN");
-    images[N].coords.crval1 = stars[0].average.R;
-    images[N].coords.crval2 = stars[0].average.D;
-    images[N].coords.crpix1 = stars[0].measure.Xccd;
-    images[N].coords.crpix2 = stars[0].measure.Yccd;
+    images[N].coords.crval1 = catalog->average[0].R;
+    images[N].coords.crval2 = catalog->average[0].D;
+    images[N].coords.crpix1 = catalog->measure[0].Xccd;
+    images[N].coords.crpix2 = catalog->measure[0].Yccd;
     images[N].coords.cdelt1 = images[N].coords.cdelt2 = 0.4 / 3600.0;
 
@@ -244,5 +257,5 @@
 
     images[N].trate = clockRate * 1e-4;
-    images[N].secz = stars[0].measure.airmass;
+    images[N].secz = catalog->measure[0].airmass;
     images[N].ccdnum = camcol;
 
@@ -263,28 +276,26 @@
   }
 
-  NSTAR_GROUP = NFILTER;
   *nimages += NFILTER;
-  *nstars = Nstars*NFILTER;
-  return (stars);
+  return (catalog);
 }
 
-int SetSDSSFlags (Stars *star, unsigned int flags1, unsigned int flags2) {
+int SetSDSSFlags (Measure *measure, unsigned int flags1, unsigned int flags2) {
 
   // XXX this is wrong, need to roll left to set the correct bit 
-  if (flags1 & 0x00000002) star[0].measure.photFlags |= 0x0001; // BRIGHT            - 1  1
-  if (flags1 & 0x00000004) star[0].measure.photFlags |= 0x0002; // EDGE              - 1  2
-  if (flags1 & 0x00000008) star[0].measure.photFlags |= 0x0004; // BLENDED           - 1  3
-  if (flags1 & 0x00000010) star[0].measure.photFlags |= 0x0008; // CHILD             - 1  4
-  if (flags1 & 0x00000020) star[0].measure.photFlags |= 0x0010; // PEAKCENTER        - 1  5
-  if (flags1 & 0x00000040) star[0].measure.photFlags |= 0x0020; // NODEBLEND         - 1  6
-  if (flags1 & 0x00040000) star[0].measure.photFlags |= 0x0040; // SATUR             - 1 18
-  if (flags1 & 0x00080000) star[0].measure.photFlags |= 0x0080; // NOTCHECKED        - 1 19
-  if (flags1 & 0x10000000) star[0].measure.photFlags |= 0x0100; // BINNED1           - 1 28
-  if (flags1 & 0x20000000) star[0].measure.photFlags |= 0x0200; // BINNED2           - 1 29
-  if (flags1 & 0x40000000) star[0].measure.photFlags |= 0x0400; // BINNED4           - 1 30
-  if (flags2 & 0x00000040) star[0].measure.photFlags |= 0x0800; // LOCAL_EDGE        - 2  7
-  if (flags2 & 0x00000800) star[0].measure.photFlags |= 0x1000; // INTERP_CENTER     - 2 12
-  if (flags2 & 0x00002000) star[0].measure.photFlags |= 0x2000; // DEBLEND_NOPEAK    - 2 14
-  if (flags2 & 0x02000000) star[0].measure.photFlags |= 0x4000; // NOTCHECKED_CENTER - 2 26
+  if (flags1 & 0x00000002) measure->photFlags |= 0x0001; // BRIGHT            - 1  1
+  if (flags1 & 0x00000004) measure->photFlags |= 0x0002; // EDGE              - 1  2
+  if (flags1 & 0x00000008) measure->photFlags |= 0x0004; // BLENDED           - 1  3
+  if (flags1 & 0x00000010) measure->photFlags |= 0x0008; // CHILD             - 1  4
+  if (flags1 & 0x00000020) measure->photFlags |= 0x0010; // PEAKCENTER        - 1  5
+  if (flags1 & 0x00000040) measure->photFlags |= 0x0020; // NODEBLEND         - 1  6
+  if (flags1 & 0x00040000) measure->photFlags |= 0x0040; // SATUR             - 1 18
+  if (flags1 & 0x00080000) measure->photFlags |= 0x0080; // NOTCHECKED        - 1 19
+  if (flags1 & 0x10000000) measure->photFlags |= 0x0100; // BINNED1           - 1 28
+  if (flags1 & 0x20000000) measure->photFlags |= 0x0200; // BINNED2           - 1 29
+  if (flags1 & 0x40000000) measure->photFlags |= 0x0400; // BINNED4           - 1 30
+  if (flags2 & 0x00000040) measure->photFlags |= 0x0800; // LOCAL_EDGE        - 2  7
+  if (flags2 & 0x00000800) measure->photFlags |= 0x1000; // INTERP_CENTER     - 2 12
+  if (flags2 & 0x00002000) measure->photFlags |= 0x2000; // DEBLEND_NOPEAK    - 2 14
+  if (flags2 & 0x02000000) measure->photFlags |= 0x4000; // NOTCHECKED_CENTER - 2 26
   return (TRUE);
 
Index: trunk/Ohana/src/addstar/src/ReadStarsUKIRT.c
===================================================================
--- trunk/Ohana/src/addstar/src/ReadStarsUKIRT.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/ReadStarsUKIRT.c	(revision 38553)
@@ -8,5 +8,5 @@
 // given a file with the pointer at the start of the table block and the 
 // corresponding image header, load the stars from the table
-Stars *ReadStarsUKIRT (FILE *f, char *name, Header *header, Image *images, off_t *nimages, unsigned int *nstars) {
+Catalog *ReadStarsUKIRT (FILE *f, char *imagename, Header *header, Image *images, off_t *nimages) {
 
   off_t Nrow;
@@ -14,8 +14,5 @@
   char type[80];
   FTable table;
-  Stars *stars;
-  
-  // ohana_memcheck_func (TRUE);
-
+  
   // the FITS binary table header is the same as the image header
   table.header = header;
@@ -30,6 +27,4 @@
     exit (1);
   }
-
-  // ohana_memcheck_func (TRUE);
 
   Coords coords;
@@ -110,5 +105,5 @@
   }
 
-  // ohana_memcheck_func (TRUE);
+  // ohana_memcheck (TRUE);
 
   double mjd;
@@ -129,9 +124,21 @@
   float ZeroPt = GetZeroPoint();
 
-  // ohana_memcheck_func (TRUE);
+  // ohana_memcheck (TRUE);
 
   // create a Star entry for each filter and detection
   int Nstars = table.header[0].Naxis[1];
-  ALLOCATE (stars, Stars, Nstars);
+
+  Catalog *catalog = NULL;
+  ALLOCATE (catalog, Catalog, 1);
+  dvo_catalog_init (catalog, TRUE);
+
+  ALLOCATE (catalog->average, Average, Nstars);
+  ALLOCATE (catalog->measure, Measure, Nstars);
+
+  int i;
+  for (i = 0; i < Nstars; i++) {
+    dvo_measure_init (&catalog->measure[i]);
+    dvo_average_init (&catalog->average[i]);
+  }
 
   GET_COLUMN (X_coordinate, float);
@@ -155,48 +162,48 @@
   double R, D, alt, az;
 
-  // ohana_memcheck_func (TRUE);
-
-  int i;
+  // ohana_memcheck (TRUE);
+
   for (i = 0; i < Nstars; i++) {
-    InitStar (&stars[i]);
-      
+
     // any values not explicitly set are left at 0.0
     XY_to_RD (&R, &D, X_coordinate[i], Y_coordinate[i], &coords);
 
-    stars[i].average.R         = R;
-    stars[i].average.D         = D;
-    stars[i].average.dR        = NAN;
-    stars[i].average.dD        = NAN;
-
-    stars[i].measure.R         = stars[i].average.R;
-    stars[i].measure.D         = stars[i].average.D;
-    stars[i].measure.Xccd      = X_coordinate[i];
-    stars[i].measure.Yccd      = Y_coordinate[i];
-    stars[i].measure.dXccd     = ToShortPixels(X_coordinate_err[i]);
-    stars[i].measure.dYccd     = ToShortPixels(Y_coordinate_err[i]);
-
-    stars[i].measure.M         = -2.5*log10(Aper_flux_4[i]) + ZeroPt + magtime + ApCor4;
-    stars[i].measure.dM        = Aper_flux_4_err[i] / Aper_flux_4[i];
-    stars[i].measure.Map       = -2.5*log10(Aper_flux_7[i]) + ZeroPt + magtime + ApCor7;
-    stars[i].measure.dMap      = Aper_flux_7_err[i] / Aper_flux_7[i];
-    stars[i].measure.Mkron     = -2.5*log10(Kron_flux[i]) + ZeroPt + magtime;
-    stars[i].measure.dMkron    = Kron_flux_err[i] / Kron_flux[i];
-    stars[i].measure.Sky       = Sky_level[i]; // adjust this to counts?
-    stars[i].measure.dSky      = Sky_rms[i];
-    stars[i].measure.FWx       = ToShortPixels(seeing); // reported in arcsec?
-    stars[i].measure.FWy       = ToShortPixels(seeing);
-
-    stars[i].measure.Mcal      = Mcal;
-
-    stars[i].measure.detID     = i;
-    stars[i].measure.t         = tzero; // time since row 0
-    stars[i].measure.dt        = magtime; // 2.5 * log(exptime) 
-
-    altaz (&alt, &az, sidtime_deg - stars[i].average.R, stars[i].average.D, Latitude);
-
-    stars[i].measure.airmass   = 1.0 / dCOS(90.0 - alt);
-    stars[i].measure.az        = az;
-    stars[i].measure.photcode  = photcode;
-    stars[i].measure.imageID   = *nimages; // set imageID to entry for this filter
+    catalog->average[i].R             = R;
+    catalog->average[i].D             = D;
+    catalog->average[i].dR            = NAN;
+    catalog->average[i].dD            = NAN;
+    catalog->average[i].Nmeasure      = 1;
+    catalog->average[i].measureOffset = i;
+
+    catalog->measure[i].R         = catalog->average[i].R;
+    catalog->measure[i].D         = catalog->average[i].D;
+    catalog->measure[i].Xccd      = X_coordinate[i];
+    catalog->measure[i].Yccd      = Y_coordinate[i];
+    catalog->measure[i].dXccd     = ToShortPixels(X_coordinate_err[i]);
+    catalog->measure[i].dYccd     = ToShortPixels(Y_coordinate_err[i]);
+
+    catalog->measure[i].M         = -2.5*log10(Aper_flux_4[i]) + ZeroPt + magtime + ApCor4;
+    catalog->measure[i].dM        = Aper_flux_4_err[i] / Aper_flux_4[i];
+    catalog->measure[i].Map       = -2.5*log10(Aper_flux_7[i]) + ZeroPt + magtime + ApCor7;
+    catalog->measure[i].dMap      = Aper_flux_7_err[i] / Aper_flux_7[i];
+    catalog->measure[i].Mkron     = -2.5*log10(Kron_flux[i]) + ZeroPt + magtime;
+    catalog->measure[i].dMkron    = Kron_flux_err[i] / Kron_flux[i];
+    catalog->measure[i].Sky       = Sky_level[i]; // adjust this to counts?
+    catalog->measure[i].dSky      = Sky_rms[i];
+    catalog->measure[i].FWx       = ToShortPixels(seeing); // reported in arcsec?
+    catalog->measure[i].FWy       = ToShortPixels(seeing);
+
+    catalog->measure[i].Mcal      = Mcal;
+
+    catalog->measure[i].detID     = i;
+    catalog->measure[i].t         = tzero; // time since row 0
+    catalog->measure[i].dt        = magtime; // 2.5 * log(exptime) 
+
+    altaz (&alt, &az, sidtime_deg - catalog->average[i].R, catalog->average[i].D, Latitude);
+
+    catalog->measure[i].airmass   = 1.0 / dCOS(90.0 - alt);
+    catalog->measure[i].az        = az;
+    catalog->measure[i].photcode  = photcode;
+    catalog->measure[i].imageID   = *nimages; // set imageID to entry for this filter
   }
 
@@ -204,5 +211,5 @@
     int N = *nimages;
     
-    // ohana_memcheck_func (TRUE);
+    // ohana_memcheck (TRUE);
 
     images[N].coords = coords;
@@ -254,11 +261,10 @@
 
     // save the filename
-    snprintf (images[N].name, DVO_IMAGE_NAME_LEN, "%s[%02d]", name, detID);
+    snprintf (images[N].name, DVO_IMAGE_NAME_LEN, "%s[%02d]", imagename, detID);
     *nimages = N + 1;
   }
   
-  // ohana_memcheck_func (TRUE);
-
-  *nstars = Nstars;
-  return (stars);
+  // ohana_memcheck (TRUE);
+
+  return (catalog);
 }
Index: trunk/Ohana/src/addstar/src/ReadXradFITS.c
===================================================================
--- trunk/Ohana/src/addstar/src/ReadXradFITS.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/ReadXradFITS.c	(revision 38553)
@@ -3,5 +3,5 @@
 // given a file with the pointer at the start of the table block and the 
 // corresponding image header, load the xrad data from the table
-int ReadXradFITS (FILE *f, Header *theader, Stars *stars, unsigned int Nstars) {
+int ReadXradFITS (FILE *f, Header *theader, Catalog *catalog) {
 
   FTable table;
@@ -51,24 +51,25 @@
   myAssert (Nrow == NrowAlt, "column mismatch?");
 
-  if (Nrow > Nstars) {
+  if (Nrow > catalog->Nmeasure) {
     myAbort("more radial measurements than stars?  seems like a bug\n");
   }
 
+  myAssert (catalog->lensing, "lensing is not allocated");
+  // we could allocate here, or just insist this is an error?
+  // if (!catalog->lensing) {
+  //   ALLOCATE (catalog->lensing, Lensing, catalog->Nmeasure);
+  // }
+
   int i;
   int Nap = 0;
-  for (i = 0; i < Nstars; i++) {
-    if (stars[i].measure.detID < RadID[Nap]) {
-      continue; // this star does not have an aperture
+  for (i = 0; i < catalog->Nmeasure; i++) {
+    if (catalog->measure[i].detID < RadID[Nap]) {
+      myAbort("star without radial aperture, seems like a bug"); // this star does not have an aperture
     }
-    if (stars[i].measure.detID > RadID[Nap]) {
+    if (catalog->measure[i].detID > RadID[Nap]) {
       myAbort("radial apertures out of order?  seems like a bug\n");
     }
 
-    // we could allocate here, or just insist this is an error?
-    if (!stars[i].lensing) {
-      fprintf (stderr, "!");
-      ALLOCATE (stars[i].lensing, Lensing, 1);
-      dvo_lensing_init (stars[i].lensing);
-    }
+    // we assumed we have already set up lensing in ReadStarsFITS.c
 
     // XXX this is all hard-wired and should make use of the headers. 
@@ -77,20 +78,28 @@
     // SDSS  3, 4, 5, 6, 7
 
-    stars[i].lensing-> F_ApR5 = AperFlux   [Nap*Ncol + 2];
-    stars[i].lensing->dF_ApR5 = AperFluxErr[Nap*Ncol + 2];
-    stars[i].lensing->sF_ApR5 = AperFluxStd[Nap*Ncol + 2];
-    stars[i].lensing->fF_ApR5 = AperFill   [Nap*Ncol + 2];
+    catalog->lensing[i]. F_ApR5 = AperFlux   [Nap*Ncol + 2];
+    catalog->lensing[i].dF_ApR5 = AperFluxErr[Nap*Ncol + 2];
+    catalog->lensing[i].sF_ApR5 = AperFluxStd[Nap*Ncol + 2];
+    catalog->lensing[i].fF_ApR5 = AperFill   [Nap*Ncol + 2];
 
-    stars[i].lensing-> F_ApR6 = AperFlux   [Nap*Ncol + 3];
-    stars[i].lensing->dF_ApR6 = AperFluxErr[Nap*Ncol + 3];
-    stars[i].lensing->sF_ApR6 = AperFluxStd[Nap*Ncol + 3];
-    stars[i].lensing->fF_ApR6 = AperFill   [Nap*Ncol + 3];
+    catalog->lensing[i]. F_ApR6 = AperFlux   [Nap*Ncol + 3];
+    catalog->lensing[i].dF_ApR6 = AperFluxErr[Nap*Ncol + 3];
+    catalog->lensing[i].sF_ApR6 = AperFluxStd[Nap*Ncol + 3];
+    catalog->lensing[i].fF_ApR6 = AperFill   [Nap*Ncol + 3];
 
-    stars[i].lensing-> F_ApR7 = AperFlux   [Nap*Ncol + 4];
-    stars[i].lensing->dF_ApR7 = AperFluxErr[Nap*Ncol + 4];
-    stars[i].lensing->sF_ApR7 = AperFluxStd[Nap*Ncol + 4];
-    stars[i].lensing->fF_ApR7 = AperFill   [Nap*Ncol + 4];
+    catalog->lensing[i]. F_ApR7 = AperFlux   [Nap*Ncol + 4];
+    catalog->lensing[i].dF_ApR7 = AperFluxErr[Nap*Ncol + 4];
+    catalog->lensing[i].sF_ApR7 = AperFluxStd[Nap*Ncol + 4];
+    catalog->lensing[i].fF_ApR7 = AperFill   [Nap*Ncol + 4];
     Nap ++;
   }
+  catalog->Nlensing = Nap;
+
+  gfits_free_table (&table);
+  free (AperFlux);
+  free (AperFluxErr);
+  free (AperFluxStd);
+  free (AperFill);
+  free (RadID);
 
   return TRUE;
Index: trunk/Ohana/src/addstar/src/SkyListForStars.c
===================================================================
--- trunk/Ohana/src/addstar/src/SkyListForStars.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/SkyListForStars.c	(revision 38553)
@@ -1,4 +1,5 @@
 # include "addstar.h"
 
+# if (0)
 void sort_stars_ra (Stars *stars, int N) {
 
@@ -69,2 +70,3 @@
 
 */
+# endif
Index: trunk/Ohana/src/addstar/src/UpdateImageIDs.c
===================================================================
--- trunk/Ohana/src/addstar/src/UpdateImageIDs.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/UpdateImageIDs.c	(revision 38553)
@@ -1,5 +1,5 @@
 # include "addstar.h"
 
-int UpdateImageIDs (Stars *stars, unsigned int Nstars, Image *images, off_t Nimages) {
+int UpdateImageIDs (Catalog *catalog, Image *images, off_t Nimages) {
 
   int i, status, isEmpty;
@@ -54,8 +54,13 @@
   }
 
-  for (i = 0; i < Nstars; i++) {
-    stars[i].measure.imageID += imageID;
-    if (stars[i].lensing) {
-      stars[i].lensing->imageID += imageID;
+  off_t j, m;
+  for (i = 0; i < catalog->Naverage; i++) {
+    m = catalog->average[i].measureOffset;
+    for (j = 0; j < catalog->average[i].Nmeasure; j++, m++) {
+      catalog->measure[m].imageID += imageID;
+    }
+    m = catalog->average[i].lensingOffset;
+    for (j = 0; j < catalog->average[i].Nlensing; j++, m++) {
+      catalog->lensing[m].imageID += imageID;
     }
   }
@@ -87,4 +92,5 @@
 
   dvo_image_unlock (&db);
+  gfits_db_free (&db);
 
   return TRUE;
Index: trunk/Ohana/src/addstar/src/addstar.c
===================================================================
--- trunk/Ohana/src/addstar/src/addstar.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/addstar.c	(revision 38553)
@@ -6,10 +6,7 @@
 int main (int argc, char **argv) {
 
-  unsigned int Nstars, Nsubset;
   int Nmatch, status, loadObjects;
   off_t i, Nimages;
   off_t Naverage, Nmeasure, Nlensing;
-  Stars *stars, **subset;
-  Image *images;
   Catalog catalog;
   FITS_DB db;
@@ -48,16 +45,17 @@
   MARKTIME ("init and config: %f sec\n", dtime); RESETTIME; 
 
-  stars = NULL;
+  Catalog *newcat = NULL;
+  Image *images = NULL;
 
   /*** load in the new data (images, stars) ***/
   switch (options.mode) {
     case ADDSTAR_MODE_IMAGE:
-      stars = LoadStars (argv[1], &Nstars, &images, &Nimages, &options);
+      newcat = LoadStars (argv[1], &images, &Nimages, &options);
       MARKTIME ("load smf: %f sec\n", dtime); RESETTIME; 
 
       // set and update the imageID sequence
-      UpdateImageIDs (stars, Nstars, images, Nimages);
-
-      if ((DUMP != NULL) && !strcmp (DUMP, "rawstars")) dump_rawstars (stars, Nstars);
+      UpdateImageIDs (newcat, images, Nimages);
+
+      // if ((DUMP != NULL) && !strcmp (DUMP, "rawstars")) dump_rawstars (stars, Nstars);
       for (i = 0; i < Nimages; i++) {
 	newlist = SkyListByImage (sky, -1, &images[i]);
@@ -68,4 +66,5 @@
       ImageOptions (&options, images, Nimages);
       break;
+# if (0)
     case ADDSTAR_MODE_REFLIST:
       stars = grefstars (argv[1], options.photcode, &Nstars);
@@ -81,4 +80,5 @@
       skylist[0].ownElements = FALSE;
       break;
+# endif
 
     default:
@@ -146,15 +146,16 @@
     switch (options.mode) {
       case ADDSTAR_MODE_IMAGE:
-	Nsubset = Nstars;
+	// Nsubset = Nstars;
 	if (options.closest) {
-	  Nmatch += find_matches_closest (skylist[0].regions[i], stars, Nstars, &catalog, options);
+	  Nmatch += find_matches_closest (skylist[0].regions[i], newcat, &catalog, options);
 	} else {
-	  Nmatch += find_matches (skylist[0].regions[i], stars, Nstars, &catalog, options);
+	  Nmatch += find_matches (skylist[0].regions[i], newcat, &catalog, options);
 	}
 	break;
+# if (0)
       case ADDSTAR_MODE_REFCAT:
 	stars = greference (argv[1], skylist[0].regions[i], options.photcode, &Nstars);
-      case ADDSTAR_MODE_REFLIST:
-	subset = find_subset (skylist[0].regions[i], stars, Nstars, &Nsubset);
+      case ADDSTAR_MODE_REFLIST: {
+	Stars **subset = find_subset (skylist[0].regions[i], stars, Nstars, &Nsubset);
 	if (options.closest) {
 	  Nmatch += find_matches_closest_refstars (skylist[0].regions[i], subset, Nsubset, &catalog, options);
@@ -164,4 +165,8 @@
 	if (Nsubset) free (subset);
 	break;
+      }
+# endif
+      default:
+	abort();
     }
     if (VERBOSE) MARKTIME ("match stars: %f sec\n", dtime); RESETTIME; 
@@ -173,5 +178,5 @@
 
     // write out catalog, if appropriate
-    if (Nsubset && !options.only_images) {
+    if (newcat->Naverage && !options.only_images) {
       SetProtect (TRUE);
       if (options.update) {
@@ -187,6 +192,7 @@
     if (VERBOSE) MARKTIME ("save cpt: %f sec\n", dtime); RESETTIME; 
 
-    if (options.mode == ADDSTAR_MODE_REFCAT) free (stars);
-  }
+    if (options.mode == ADDSTAR_MODE_REFCAT) dvo_catalog_free (newcat);
+  }
+  SkyListFree (skylist);
 
   // We only measure a single value for the entire mosaic (add all images to this function)
@@ -218,10 +224,23 @@
     SetProtect (FALSE);
   }
+  FREE (images);
   dvo_image_unlock (&db); /* unlock? */
+  gfits_db_free (&db); /* unlock? */
 
   gettimeofday (&stopAddstar, (void *) NULL);
   float dtime = DTIME (stopAddstar, startAddstar);
-  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec for %5d stars (%5d matches), "OFF_T_FMT" average, "OFF_T_FMT" measure, "OFF_T_FMT" lensing\n", dtime, Nstars, Nmatch,  Naverage,  Nmeasure, Nlensing);
-
+  fprintf (stderr, "SUCCESS: elapsed time %9.4f sec for "OFF_T_FMT" stars (%5d matches), "OFF_T_FMT" average, "OFF_T_FMT" measure, "OFF_T_FMT" lensing\n", dtime, newcat->Naverage, Nmatch,  Naverage,  Nmeasure, Nlensing);
+
+  if (options.mode != ADDSTAR_MODE_REFCAT) {
+    dvo_catalog_free (newcat);
+    free (newcat);
+  }
+
+  // XXX test
+  FreeConfig ();
+  FreePhotcodeTable ();
+  SkyTableFree (sky);
+  ohana_memcheck (1);
+  ohana_memdump (1);
   exit (0);
 }
Index: trunk/Ohana/src/addstar/src/args_loadgalphot.c
===================================================================
--- trunk/Ohana/src/addstar/src/args_loadgalphot.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/args_loadgalphot.c	(revision 38553)
@@ -0,0 +1,116 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+static void help (void);
+
+AddstarClientOptions args_loadgalphot (int argc, char **argv, AddstarClientOptions options) {
+  
+  int N;
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help") ||
+      get_argument (argc, argv, "-h")) {
+    help ();
+  }
+
+  /* basic mode: image, list, refcat */
+  options.mode = ADDSTAR_MODE_REFCAT;
+
+  /* we do not allow a subset to be extracted -- all or nothing, babe */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+
+  // XXX for the moment, make this selection manual.  it needs to be automatic 
+  // based on the state of the SkyTable
+  HOST_ID = 0;
+  PARALLEL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel"))) {
+    PARALLEL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  // this is a test mode : rather than launching the remote jobs and waiting for completion,
+  // relphot will simply list the remote command and wait for the user to signal completion
+  PARALLEL_MANUAL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel-manual"))) {
+    PARALLEL = TRUE; // -parallel-manual implies -parallel
+    PARALLEL_MANUAL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  // this is a test mode : rather than launching the relphot_client jobs remotely, they are 
+  // run in serial via 'system'
+  PARALLEL_SERIAL = FALSE;
+  if ((N = get_argument (argc, argv, "-parallel-serial"))) {
+    if (PARALLEL_MANUAL) {
+      fprintf (stderr, "ERROR: cannot mix -parallel-manual and -parallel-serial\n");
+      exit (1);
+    }
+    PARALLEL = TRUE; // -parallel-serial implies -parallel
+    PARALLEL_SERIAL = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* only add to existing regions */
+  options.existing_regions = FALSE;
+  if ((N = get_argument (argc, argv, "-existing-regions"))) {
+    options.existing_regions = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* only add to existing objects */
+  options.only_match = FALSE;
+  if ((N = get_argument (argc, argv, "-only-match"))) {
+    options.only_match = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  /* replace measurement, don't duplicate (ref/cat only) */
+  options.replace = FALSE;
+  if ((N = get_argument (argc, argv, "-replace"))) {
+    options.replace = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  /* other addstar options which cannot be used in loadgalphot */
+  options.photcode = 0;
+  options.timeref = 0; 
+  options.mosaic = FALSE;
+  options.skip_missed = FALSE;
+  options.closest = FALSE;
+  options.nosort = FALSE;
+  options.update = FALSE;
+  options.only_images = FALSE;
+  options.calibrate = FALSE;
+  options.quality_airmass = FALSE;
+  ACCEPT_ASTROM = FALSE;
+  FORCE_READ = FALSE;
+  TEXTMODE = FALSE;
+  SUBPIX = FALSE;
+  DUMP = NULL;
+
+  if (argc < 2) {
+    fprintf (stderr, "USAGE: loadgalphot [options] (fitsfile) [..more files]\n");
+    exit (2);
+  }
+  return (options);
+}
+
+static void help () {
+
+  fprintf (stderr, "USAGE: loadgalphot [options] (file) [..more files]\n");
+  fprintf (stderr, "  add data from stellar parameter file to DVO\n\n");
+
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -only-match           	  : only add measurements to existing objects\n");
+  fprintf (stderr, "  -replace              	  : replace time/photcode measurements (no duplication)\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
Index: trunk/Ohana/src/addstar/src/find_matches.c
===================================================================
--- trunk/Ohana/src/addstar/src/find_matches.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/find_matches.c	(revision 38553)
@@ -1,11 +1,11 @@
 # include "addstar.h"
 
-int find_matches (SkyRegion *region, Stars *stars, unsigned int NstarsIn, Catalog *catalog, AddstarClientOptions options) {
-
-  off_t i, j, n, N, J, Nstars;
+int find_matches (SkyRegion *region, Catalog *srccat, Catalog *tgtcat, AddstarClientOptions options) {
+
+  off_t i, j, n, N, J, Nstars, mSrc;
   double RADIUS, RADIUS2;
   double *X1, *Y1, *X2, *Y2;
   double dX, dY, dR;
-  off_t *N1, *N2, *next_meas;
+  off_t *N1, *N2;
   off_t Nave, NAVE, Nmeas, NMEAS, Nmatch;
   int Nsecfilt, Nsec, status;
@@ -13,9 +13,4 @@
   Coords tcoords;
 
-  if (NSTAR_GROUP <= 0) {
-    fprintf (stderr, "ERROR: NSTAR_GROUP NOT SET!\n");
-    exit (1);
-  }
-
   /* photcode data - must by of type DEP; options.photcode is equiv photcode for all input
      images this function requires incoming stars to have the same photcode.equiv value.  if
@@ -27,23 +22,39 @@
 
   /** allocate local arrays (stars) **/
-  ALLOCATE (X1, double, NstarsIn);
-  ALLOCATE (Y1, double, NstarsIn);
-  ALLOCATE (N1, off_t,  NstarsIn);
-
-  /** allocate local arrays (catalog) **/
-  NAVE = Nave = catalog[0].Naverage;
+  ALLOCATE (X1, double, srccat->Naverage);
+  ALLOCATE (Y1, double, srccat->Naverage);
+  ALLOCATE (N1, off_t,  srccat->Naverage);
+
+  myAbort ("figure out if found_t needs to be tracking Naverage or Nmeasure"); 
+  if (!srccat->found_t) {
+    ALLOCATE (srccat->found_t, off_t, srccat->Naverage);
+    for (i = 0; i < srccat->Naverage; i++) {
+      srccat->found_t[i] = -1;
+    }
+  }
+
+  /** allocate local arrays (tgtcat) **/
+  NAVE = Nave = tgtcat[0].Naverage;
   ALLOCATE (X2, double, NAVE);
   ALLOCATE (Y2, double, NAVE);
   ALLOCATE (N2, off_t,  NAVE);
-  ALLOCATE (catalog[0].found_t, off_t, NAVE);
+
+  if (!tgtcat->found_t) {
+    ALLOCATE (tgtcat[0].found_t, off_t, NAVE);
+    for (i = 0; i < NAVE; i++) {
+      tgtcat->found_t[i] = -1;
+    }
+  }
   /* for secfilt j and star i, secfilt[i*Nsecfilt+j] */
 
   /* internal counters */
   Nmatch = 0;
-  NMEAS = Nmeas = catalog[0].Nmeasure;
+  NMEAS = Nmeas = tgtcat[0].Nmeasure;
   
-  // current max obj ID for this catalog
-  objID = catalog[0].objID;
-  catID = catalog[0].catID;
+  off_t *next_meas = NULL;
+
+  // current max obj ID for this tgtcat
+  objID = tgtcat[0].objID;
+  catID = tgtcat[0].catID;
 
   /* project onto rectilinear grid with 1 arcsec pixels. the choice of ZEA projection has the
@@ -51,5 +62,5 @@
    * possible X,Y points map back to R,D and the local plate scale changes substantially far from
    * the projection pole.  a better mapping might be ARC, not yet implemented (see
-   * coordops.update.c).  We use the center of the region (catalog) for crval1,2. 
+   * coordops.update.c).  We use the center of the region (tgtcat) for crval1,2. 
    */
   InitCoords (&tcoords, "DEC--ARC");
@@ -64,6 +75,6 @@
   /* build spatial index (RA sort) referencing input array sequence */
   Nstars = 0;
-  for (i = 0; i < NstarsIn; i++) {
-    status = RD_to_XY (&X1[Nstars], &Y1[Nstars], stars[i].average.R, stars[i].average.D, &tcoords);
+  for (i = 0; i < srccat->Naverage; i++) {
+    status = RD_to_XY (&X1[Nstars], &Y1[Nstars], srccat->average[i].R, srccat->average[i].D, &tcoords);
     if (!status) continue;
     N1[Nstars] = i;
@@ -71,5 +82,5 @@
   }
   if (Nstars < 1) {
-    if (VERBOSE) fprintf (stderr, "skipping %s, no overlapping stars\n", catalog[0].filename);
+    if (VERBOSE) fprintf (stderr, "skipping %s, no overlapping stars\n", tgtcat[0].filename);
     free (X1);
     free (Y1);
@@ -84,15 +95,15 @@
   /* build spatial index (RA sort) */
   for (i = 0; i < Nave; i++) {
-    RD_to_XY (&X2[i], &Y2[i], catalog[0].average[i].R, catalog[0].average[i].D, &tcoords);
+    RD_to_XY (&X2[i], &Y2[i], tgtcat[0].average[i].R, tgtcat[0].average[i].D, &tcoords);
     N2[i] = i;
-    catalog[0].found_t[N2[i]] = -1;
+    tgtcat[0].found_t[N2[i]] = -1;
   }
   if (Nave > 1) sort_coords_index (X2, Y2, N2, Nave);
 
   /* set up pointers for linked list of measure */
-  if (catalog[0].sorted && (catalog[0].Nmeasure == catalog[0].Nmeasure_disk)) {
-    next_meas = init_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
+  if (tgtcat[0].sorted && (tgtcat[0].Nmeasure == tgtcat[0].Nmeasure_disk)) {
+    next_meas = init_measure_links (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas);
   } else {
-    next_meas = build_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
+    next_meas = build_measure_links (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas);
   }    
 
@@ -102,5 +113,4 @@
 
   /** find matched stars **/
-  // XXX could use NSTAR_GROUP to do this match more quicky if NSTAR_GROUP > 1
   for (i = j = 0; (i < Nstars) && (j < Nave); ) {
     if (!finite(X1[i]) || !finite(Y1[i])) { 
@@ -138,91 +148,96 @@
 
       /* make sure there is space for next entry */
-      if (Nmeas >= NMEAS) {
-	NMEAS = Nmeas + 1000;
+      if (Nmeas >= NMEAS - srccat->average[N].Nmeasure) {
+	NMEAS = Nmeas + 1000 + srccat->average[N].Nmeasure;
 	REALLOCATE (next_meas, off_t, NMEAS);
-
-	REALLOCATE (catalog[0].measure, Measure, NMEAS);
-      }
-
-      /* add to end of measurement list */
-      add_meas_link (&catalog[0].average[n], next_meas, Nmeas, NMEAS);
+	REALLOCATE (tgtcat[0].measure, Measure, NMEAS);
+      }
 
       /** add measurements for this star **/
-
-      // set the new measurements
-      catalog[0].measure[Nmeas]          = stars[N].measure;
-
-      // the following measure elements cannot be set until here:
-      catalog[0].measure[Nmeas].dbFlags  = 0;
-      catalog[0].measure[Nmeas].averef   = n; // this must be an absolute sequence number, if partial average is loaded 
-      catalog[0].measure[Nmeas].objID    = catalog[0].average[n].objID;
-      catalog[0].measure[Nmeas].catID    = catalog[0].catID;
-
-      float dRoff = dvoOffsetR(&catalog[0].measure[Nmeas], &catalog[0].average[n]);
-
-      // rationalize R:
-      if (dRoff > +180.0*3600.0) {
-	// average on high end of boundary, move star up
-	catalog[0].measure[Nmeas].R += 360.0;
-	dRoff -= 360.0*3600.0;
-      }
-      if (dRoff < -180.0*3600.0) {
-	// average on low end of boundary, move star down
-	catalog[0].measure[Nmeas].R -= 360.0;
-	dRoff += 360.0*3600.0;
-      }
-      if (fabs(dRoff) > 10*RADIUS) {
-	// take declination into account and check again.
-	double cosD = cos(RAD_DEG*catalog[0].average[n].D);
-	if (fabs(dRoff*cosD) > 10*RADIUS) {
-	  fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
-		   catalog[0].average[n].R, catalog[0].average[n].D, 
-		   stars[N].average.R, stars[N].average.D,
-		   X1[i], X2[J], 
-		   Y1[i], Y2[J]);
-	}
-      }
-
-      /* adds the measurement to the calibration if appropriate color terms are found */
-      /* we call this before (optionally) setting the average magnitude to avoid auto-correlations */
-      if (options.calibrate) {
-	AddToCalibration (&catalog[0].average[n], &catalog[0].secfilt[n*Nsecfilt], catalog[0].measure, &catalog[0].measure[Nmeas], next_meas, N);
-      }
-
-      /* set the average magnitude if not already set and if photcode.equiv is not 0 */
-      /* in UPDATE mode, this value is not saved; use relphot to recalculate */
-      if (Nsec > -1) { 
-	if (isnan(catalog[0].secfilt[n*Nsecfilt+Nsec].M)) {
-	  catalog[0].secfilt[n*Nsecfilt+Nsec].M = PhotCat (&catalog[0].measure[Nmeas], MAG_CLASS_PSF);
-	}
-      }
-
-      /*** flag multiple stars */
-      /* this image star matches more than one catalog star */
-      if (stars[N].found > -1) {
-	catalog[0].measure[stars[N].found].dbFlags |= ID_MEAS_BLEND_MEAS;
-	catalog[0].measure[Nmeas].dbFlags |= ID_MEAS_BLEND_MEAS;
-      } 
-      if (stars[N].found == -2) { /* this image star matches a catalog star on a neighboring catalog */
-	catalog[0].measure[Nmeas].dbFlags |= ID_MEAS_BLEND_MEAS_X;
-      } 
-      if (stars[N].found == -1) { /* this image star matches only this catalog star */
-	stars[N].found = Nmeas;  /* save first match, in case coincidences are found */
-      }
-      /* this catalog star matches more than one image star */
-      if (catalog[0].found_t[n] > -1) {
-	catalog[0].measure[catalog[0].found_t[n]].dbFlags |= ID_MEAS_BLEND_OBJ;
-	catalog[0].measure[Nmeas].dbFlags |= ID_MEAS_BLEND_OBJ;
-      } else {
-	catalog[0].found_t[n] = Nmeas;
-      }
-      /* Nm is updated, but not written out in -update mode (for existing entries)
-	 Nm is recalculated in build_meas_links if loaded table is not sorted */
-      catalog[0].average[n].Nmeasure ++;
-      Nmeas ++;
+      off_t mOff = srccat->average[N].measureOffset;
+      for (mSrc = 0; mSrc < srccat->average[N].Nmeasure; mSrc++) {
+	/* add to end of measurement list */
+	add_meas_link (&tgtcat[0].average[n], next_meas, Nmeas, NMEAS);
+	
+	/** add measurements for this star **/
+	
+	// set the new measurements
+	tgtcat[0].measure[Nmeas]          = srccat->measure[mSrc + mOff];
+	
+	// the following measure elements cannot be set until here:
+	tgtcat[0].measure[Nmeas].dbFlags  = 0;
+	tgtcat[0].measure[Nmeas].averef   = n; // this must be an absolute sequence number, if partial average is loaded 
+	tgtcat[0].measure[Nmeas].objID    = tgtcat[0].average[n].objID;
+	tgtcat[0].measure[Nmeas].catID    = tgtcat[0].catID;
+
+	float dRoff = dvoOffsetR(&tgtcat[0].measure[Nmeas], &tgtcat[0].average[n]);
+
+	// rationalize R:
+	if (dRoff > +180.0*3600.0) {
+	  // average on high end of boundary, move star up
+	  tgtcat[0].measure[Nmeas].R += 360.0;
+	  dRoff -= 360.0*3600.0;
+	}
+	if (dRoff < -180.0*3600.0) {
+	  // average on low end of boundary, move star down
+	  tgtcat[0].measure[Nmeas].R -= 360.0;
+	  dRoff += 360.0*3600.0;
+	}
+	if (fabs(dRoff) > 10*RADIUS) {
+	  // take declination into account and check again.
+	  double cosD = cos(RAD_DEG*tgtcat[0].average[n].D);
+	  if (fabs(dRoff*cosD) > 10*RADIUS) {
+	    fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
+		     tgtcat[0].average[n].R, tgtcat[0].average[n].D, 
+		     srccat->average[N].R, srccat->average[N].D,
+		     X1[i], X2[J], 
+		     Y1[i], Y2[J]);
+	  }
+	}
+
+	/* adds the measurement to the calibration if appropriate color terms are found */
+	/* we call this before (optionally) setting the average magnitude to avoid auto-correlations */
+	if (options.calibrate) {
+	  AddToCalibration (&tgtcat[0].average[n], &tgtcat[0].secfilt[n*Nsecfilt], tgtcat[0].measure, &tgtcat[0].measure[Nmeas], next_meas, N);
+	}
+
+	/* set the average magnitude if not already set and if photcode.equiv is not 0 */
+	/* in UPDATE mode, this value is not saved; use relphot to recalculate */
+	if (Nsec > -1) { 
+	  if (isnan(tgtcat[0].secfilt[n*Nsecfilt+Nsec].M)) {
+	    tgtcat[0].secfilt[n*Nsecfilt+Nsec].M = PhotCat (&tgtcat[0].measure[Nmeas], MAG_CLASS_PSF);
+	  }
+	}
+
+	myAbort ("fix logic on multiple detections");
+
+	/*** flag multiple stars */
+	/* this image star matches more than one tgtcat star */
+	if (srccat->found_t[N] > -1) {
+	  tgtcat[0].measure[srccat->found_t[N]].dbFlags |= ID_MEAS_BLEND_MEAS;
+	  tgtcat[0].measure[Nmeas].dbFlags |= ID_MEAS_BLEND_MEAS;
+	} 
+	if (srccat->found_t[N] == -2) { /* this image star matches a tgtcat star on a neighboring tgtcat */
+	  tgtcat[0].measure[Nmeas].dbFlags |= ID_MEAS_BLEND_MEAS_X;
+	} 
+	if (srccat->found_t[N] == -1) { /* this image star matches only this tgtcat star */
+	  srccat->found_t[N] = Nmeas;  /* save first match, in case coincidences are found */
+	}
+	/* this tgtcat star matches more than one image star */
+	if (tgtcat[0].found_t[n] > -1) {
+	  tgtcat[0].measure[tgtcat[0].found_t[n]].dbFlags |= ID_MEAS_BLEND_OBJ;
+	  tgtcat[0].measure[Nmeas].dbFlags |= ID_MEAS_BLEND_OBJ;
+	} else {
+	  tgtcat[0].found_t[n] = Nmeas;
+	}
+	/* Nm is updated, but not written out in -update mode (for existing entries)
+	   Nm is recalculated in build_meas_links if loaded table is not sorted */
+	tgtcat[0].average[n].Nmeasure ++;
+	Nmeas ++;
+      }
 
       if (!options.update) {
 	/* in UPDATE mode, newly calculated coordinates are not saved */
-	update_coords (&catalog[0].average[n], &catalog[0].measure[0], next_meas);
+	update_coords (&tgtcat[0].average[n], &tgtcat[0].measure[0], next_meas);
       }
     }
@@ -230,91 +245,95 @@
   }
 
-/* incorporate unmatched image stars, if this star is in field of this catalog */
+/* incorporate unmatched image stars, if this star is in field of this tgtcat */
 /* these new entries are all written out in UPDATE mode */ 
-  for (i = 0; (i < Nstars) && !options.only_match; i += NSTAR_GROUP) {
+  for (i = 0; (i < Nstars) && !options.only_match; i ++) {
     /* make sure there is space for next entry */
-    if (Nmeas >= NMEAS - NSTAR_GROUP) {
-      NMEAS = Nmeas + 1000;
+    if (Nmeas >= NMEAS - srccat->average[i].Nmeasure) {
+      NMEAS = Nmeas + 1000 + srccat->average[i].Nmeasure;
       REALLOCATE (next_meas, off_t, NMEAS);
-      REALLOCATE (catalog[0].measure, Measure, NMEAS);
+      REALLOCATE (tgtcat[0].measure, Measure, NMEAS);
     }
     if (Nave >= NAVE) {
       NAVE = Nave + 1000;
-      REALLOCATE (catalog[0].average, Average, NAVE);
-      REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*catalog[0].Nsecfilt);
-    }
-
-    if (stars[i].found >= 0) continue;
-    if (!IN_REGION (stars[i].average.R, stars[i].average.D)) continue;
-
-    dvo_average_init (&catalog[0].average[Nave]);
-    catalog[0].average[Nave].R         	   = stars[i].average.R;
-    catalog[0].average[Nave].D         	   = stars[i].average.D;
-
-    catalog[0].average[Nave].Nmeasure      = NSTAR_GROUP;
-    catalog[0].average[Nave].measureOffset = Nmeas;
-    catalog[0].average[Nave].objID     	   = objID;
-    catalog[0].average[Nave].catID     	   = catID;
+      REALLOCATE (tgtcat[0].average, Average, NAVE);
+      if (tgtcat[0].secfilt) {
+	// we only update the secfilt table if it has been allocated for output
+	REALLOCATE (tgtcat[0].secfilt, SecFilt, NAVE*tgtcat[0].Nsecfilt);
+      }
+    }
+
+    if (srccat->found_t[i] >= 0) continue;
+    if (!IN_REGION (srccat->average[i].R, srccat->average[i].D)) continue;
+
+    dvo_average_init (&tgtcat[0].average[Nave]);
+    tgtcat[0].average[Nave].R         	   = srccat->average[i].R;
+    tgtcat[0].average[Nave].D         	   = srccat->average[i].D;
+
+    tgtcat[0].average[Nave].Nmeasure       = srccat->average[i].Nmeasure;
+    tgtcat[0].average[Nave].measureOffset  = Nmeas;
+    tgtcat[0].average[Nave].objID     	   = objID;
+    tgtcat[0].average[Nave].catID     	   = catID;
 
     if (PSPS_ID) {
-      catalog[0].average[Nave].extID = CreatePSPSObjectID(catalog[0].average[Nave].R, catalog[0].average[Nave].D);
+      tgtcat[0].average[Nave].extID = CreatePSPSObjectID(tgtcat[0].average[Nave].R, tgtcat[0].average[Nave].D);
     }
 
     objID ++;
 
-    for (j = 0; j < Nsecfilt; j++) {
-      dvo_secfilt_init (&catalog[0].secfilt[Nave*Nsecfilt+j], SECFILT_RESET_ALL);
-    }
-
-    for (j = 0; j < NSTAR_GROUP; j++) {
+    for (j = 0; tgtcat[0].secfilt && (j < Nsecfilt); j++) {
+      dvo_secfilt_init (&tgtcat[0].secfilt[Nave*Nsecfilt+j], SECFILT_RESET_ALL);
+    }
+
+    off_t mOff = srccat->average[i].measureOffset;
+    for (mSrc = 0; mSrc < srccat->average[i].Nmeasure; mSrc++) {
       // supply the measurments from this detection
-      catalog[0].measure[Nmeas]           = stars[i + j].measure;
+      dvo_measure_init (&tgtcat[0].measure[Nmeas]);
+      tgtcat[0].measure[Nmeas] = srccat->measure[mSrc + mOff];
 
       // the following measure elements cannot be set until here:
-      catalog[0].measure[Nmeas].dbFlags   = 0;
-      catalog[0].measure[Nmeas].averef    = Nave; // XXX EAM : must be absolute Nave if partial read
-      catalog[0].measure[Nmeas].objID     = catalog[0].average[Nave].objID;
-      catalog[0].measure[Nmeas].catID     = catalog[0].catID;
+      tgtcat[0].measure[Nmeas].dbFlags   = 0;
+      tgtcat[0].measure[Nmeas].averef    = Nave; // XXX EAM : must be absolute Nave if partial read
+      tgtcat[0].measure[Nmeas].objID     = tgtcat[0].average[Nave].objID;
+      tgtcat[0].measure[Nmeas].catID     = tgtcat[0].catID;
 
       /* set the average magnitude if not already set and the photcode.equiv is not 0 */
       /* in UPDATE mode, this value is not saved; use relphot to recalculate */
       if (Nsec > -1) { 
-	catalog[0].secfilt[Nave*Nsecfilt+Nsec].M = PhotCat (&catalog[0].measure[Nmeas], MAG_CLASS_PSF);
+	tgtcat[0].secfilt[Nave*Nsecfilt+Nsec].M = PhotCat (&tgtcat[0].measure[Nmeas], MAG_CLASS_PSF);
       }
 
       /* next[Nmeas] should always be -1 in this context (it is always the only
 	 measurement for the star) */
-      stars[i].found = Nmeas;
-      next_meas[Nmeas] = -1;  // initial value here update below
+      srccat->found_t[i] = Nmeas;
       Nmeas ++;
-    }
-    for (j = 0; j < NSTAR_GROUP - 1; j++) {
-      next_meas[Nmeas - NSTAR_GROUP + j] = Nmeas - NSTAR_GROUP + j + 1;
+
+      // update the next_meas pointer for this entry (last one for this star is -1)
+      next_meas[Nmeas-1] = (mSrc < srccat->average[i].Nmeasure - 1) ? Nmeas : -1;
     }
     Nave ++;
   }
       
-  REALLOCATE (catalog[0].average, Average, Nave);
-  REALLOCATE (catalog[0].measure, Measure, Nmeas);
+  REALLOCATE (tgtcat[0].average, Average, Nave);
+  REALLOCATE (tgtcat[0].measure, Measure, Nmeas);
  
   if (options.nosort) {
-    catalog[0].sorted = FALSE;
+    tgtcat[0].sorted = FALSE;
   } else {
-    catalog[0].sorted = TRUE;
-    catalog[0].measure = sort_measure (catalog[0].average, Nave, catalog[0].measure, Nmeas, next_meas);
-  }
-
-/* note stars which have been found in this catalog */
-  for (i = 0; i < NstarsIn; i++) {
-    if (stars[i].found > -1) {
-      stars[i].found = -2;
-    }
-  }
-
-/* check if the catalog has changed?  if no change, no need to write */
-  catalog[0].objID    = objID; // new max value, save on catalog close
-  catalog[0].Naverage = Nave;
-  catalog[0].Nmeasure = Nmeas;
-  catalog[0].Nsecfilt_mem = Nave*Nsecfilt;
+    tgtcat[0].sorted = TRUE;
+    tgtcat[0].measure = sort_measure (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas, next_meas);
+  }
+
+/* note stars which have been found in this tgtcat */
+  for (i = 0; i < srccat->Nmeasure; i++) {
+    if (srccat->found_t[i] > -1) {
+      srccat->found_t[i] = -2;
+    }
+  }
+
+/* check if the tgtcat has changed?  if no change, no need to write */
+  tgtcat[0].objID    = objID; // new max value, save on tgtcat close
+  tgtcat[0].Naverage = Nave;
+  tgtcat[0].Nmeasure = Nmeas;
+  tgtcat[0].Nsecfilt_mem = Nave*Nsecfilt;
   if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeas: "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT", ("OFF_T_FMT" matches)\n",  Nstars,  Nave,  Nmeas,  Nmatch);
 
@@ -333,10 +352,10 @@
    notes:
    
-   for finding if a catalog star is in an image or an image star is in the catalog:
+   for finding if a tgtcat star is in an image or an image star is in the tgtcat:
    
-   catalogs have boundaries defined by RA and DEC, but they may curve in projection
+   tgtcats have boundaries defined by RA and DEC, but they may curve in projection
    images have boundaries which are lines in pixels coords, but curve in RA and DEC
    
-   catalog[0].found[Ncat] but stars[Nstar].found
+   tgtcat[0].found[Ncat] but stars[Nstar].found
    
 */
Index: trunk/Ohana/src/addstar/src/find_matches_closest.c
===================================================================
--- trunk/Ohana/src/addstar/src/find_matches_closest.c	(revision 38543)
+++ trunk/Ohana/src/addstar/src/find_matches_closest.c	(revision 38553)
@@ -1,11 +1,11 @@
 # include "addstar.h"
 
-int find_matches_closest (SkyRegion *region, Stars *stars, unsigned int NstarsIn, Catalog *catalog, AddstarClientOptions options) {
-  
-  off_t i, j, n, N, J, Jmin, status, Nstars;
+int find_matches_closest (SkyRegion *region, Catalog *srccat, Catalog *tgtcat, AddstarClientOptions options) {
+
+  off_t i, j, n, N, J, Jmin, status, Nstars, mSrc;
   double RADIUS, RADIUS2, Rmin;
   double *X1, *Y1, *X2, *Y2;
   double dX, dY, dR;
-  off_t *N1, *N2, *next_meas, *next_lens;
+  off_t *N1, *N2;
   off_t Nave, NAVE, Nmeas, NMEAS, Nmatch, Nlens, NLENS;
   int Nsecfilt, Nsec;
@@ -13,9 +13,4 @@
   Coords tcoords;
 
-  if (NSTAR_GROUP <= 0) {
-      fprintf (stderr, "ERROR: NSTAR_GROUP NOT SET!\n");
-      exit (1);
-  }
-
   /* photcode data - must by of type DEP; options.photcode is equiv photcode for all input
      images this function requires incoming stars to have the same photcode.equiv value.  if
@@ -26,30 +21,46 @@
   Nsec     = GetPhotcodeNsec (options.photcode);
 
-  /** allocate local arrays (stars) **/
-  ALLOCATE (X1, double, NstarsIn);
-  ALLOCATE (Y1, double, NstarsIn);
-  ALLOCATE (N1, off_t,  NstarsIn);
-
-  /** allocate local arrays (catalog) **/
-  NAVE = Nave = catalog[0].Naverage;
+  /** allocate local arrays (srccat) **/
+  ALLOCATE (X1, double, srccat->Naverage);
+  ALLOCATE (Y1, double, srccat->Naverage);
+  ALLOCATE (N1, off_t,  srccat->Naverage);
+
+  if (!srccat->found_t) {
+    ALLOCATE (srccat->found_t, off_t, srccat->Naverage);
+    for (i = 0; i < srccat->Naverage; i++) {
+      srccat->found_t[i] = -1;
+    }
+  }
+
+  /** allocate local arrays (tgtcat) **/
+  NAVE = Nave = tgtcat[0].Naverage;
   ALLOCATE (X2, double, NAVE);
   ALLOCATE (Y2, double, NAVE);
   ALLOCATE (N2, off_t,  NAVE);
-  ALLOCATE (catalog[0].found_t, off_t, NAVE);
+
+  if (!tgtcat->found_t) {
+    ALLOCATE (tgtcat[0].found_t, off_t, NAVE);
+    for (i = 0; i < NAVE; i++) {
+      tgtcat->found_t[i] = -1;
+    }
+  }
   /* for secfilt j and star i, secfilt[i*Nsecfilt+j] */
 
   /* internal counters */
   Nmatch = 0;
-  NMEAS = Nmeas = catalog[0].Nmeasure;
-  NLENS = Nlens = catalog[0].Nlensing;
-
-  // current max obj ID for this catalog
-  objID = catalog[0].objID;
-  catID = catalog[0].catID;
+  NMEAS = Nmeas = tgtcat[0].Nmeasure;
+  NLENS = Nlens = tgtcat[0].Nlensing;
+
+  off_t *next_meas = NULL;
+  off_t *next_lens = NULL;
+
+  // current max obj ID for this tgtcat
+  objID = tgtcat[0].objID;
+  catID = tgtcat[0].catID;
 
   /* project onto rectilinear grid with 1 arcsec pixels. the choice of ARC projection has
    * the advantage that every point in R,D has a mapping to a unique X,Y.  However, note
    * that not all possible X,Y points map back to R,D and the local plate scale changes
-   * far from the projection pole. We use the center of the region (catalog) for crval1,2.
+   * far from the projection pole. We use the center of the region (tgtcat) for crval1,2.
    */
   InitCoords (&tcoords, "DEC--ARC");
@@ -64,6 +75,6 @@
   /* build spatial index (RA sort) referencing input array sequence */
   Nstars = 0;
-  for (i = 0; i < NstarsIn; i++) {
-    status = RD_to_XY (&X1[Nstars], &Y1[Nstars], stars[i].average.R, stars[i].average.D, &tcoords);
+  for (i = 0; i < srccat->Naverage; i++) {
+    status = RD_to_XY (&X1[Nstars], &Y1[Nstars], srccat->average[i].R, srccat->average[i].D, &tcoords);
     if (!status) continue;
     N1[Nstars] = i;
@@ -71,5 +82,5 @@
   }
   if (Nstars < 1) {
-    if (VERBOSE) fprintf (stderr, "skipping %s, no overlapping stars\n", catalog[0].filename);
+    if (VERBOSE) fprintf (stderr, "skipping %s, no overlapping stars\n", tgtcat[0].filename);
     free (X1);
     free (Y1);
@@ -79,4 +90,5 @@
     free (N2);
     return (0);
+    // XXX check on this
   }
   if (Nstars > 1) sort_coords_index (X1, Y1, N1, Nstars);
@@ -84,19 +96,19 @@
   /* build spatial index (RA sort) */
   for (i = 0; i < Nave; i++) {
-    RD_to_XY (&X2[i], &Y2[i], catalog[0].average[i].R, catalog[0].average[i].D, &tcoords);
+    RD_to_XY (&X2[i], &Y2[i], tgtcat[0].average[i].R, tgtcat[0].average[i].D, &tcoords);
     N2[i] = i;
-    catalog[0].found_t[N2[i]] = -1;
+    tgtcat[0].found_t[N2[i]] = -1;
   }
   if (Nave > 1) sort_coords_index (X2, Y2, N2, Nave);
 
   /* set up pointers for linked list of measure */
-  if (catalog[0].sorted && (catalog[0].Nmeasure == catalog[0].Nmeasure_disk)) {
-    // this version is only valid if we have done a full catalog load, and if the catalog
+  if (tgtcat[0].sorted && (tgtcat[0].Nmeasure == tgtcat[0].Nmeasure_disk)) {
+    // this version is only valid if we have done a full tgtcat load, and if the tgtcat
     // is sorted while processed
-    next_meas = init_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
-    next_lens = init_lensing_links (catalog[0].average, Nave, catalog[0].lensing, Nlens);
+    next_meas = init_measure_links (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas);
+    next_lens = init_lensing_links (tgtcat[0].average, Nave, tgtcat[0].lensing, Nlens);
   } else {
-    next_meas = build_measure_links (catalog[0].average, Nave, catalog[0].measure, Nmeas);
-    next_lens = build_lensing_links (catalog[0].average, Nave, catalog[0].lensing, Nlens);
+    next_meas = build_measure_links (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas);
+    next_lens = build_lensing_links (tgtcat[0].average, Nave, tgtcat[0].lensing, Nlens);
   }    
 
@@ -105,6 +117,6 @@
   RADIUS2 = RADIUS*RADIUS;
 
-  /** find matched stars **/
-  // XXX could use NSTAR_GROUP to do this match more quicky if NSTAR_GROUP > 1
+  /****************** find matched stars ********************/
+
   for (i = j = 0; (i < Nstars) && (j < Nave); ) {
     if (!finite(X1[i]) || !finite(Y1[i])) { 
@@ -129,6 +141,7 @@
     }
 
-    if (stars[N1[i]].found != -1) {
-        /* this star has already been assigned to an object in this or another catalog */
+    // XXX check that this is allocated
+    if (srccat->found_t[N1[i]] != -1) {
+        /* this star has already been assigned to an object in this or another tgtcat */
         i++;
         continue;
@@ -169,212 +182,224 @@
 
     /* make sure there is space for next entry */
-    if (Nmeas >= NMEAS) {
-      NMEAS = Nmeas + 1000;
+    if (Nmeas >= NMEAS - srccat->average[N].Nmeasure) {
+      NMEAS = Nmeas + 1000 + srccat->average[N].Nmeasure;
       REALLOCATE (next_meas, off_t, NMEAS);
-      REALLOCATE (catalog[0].measure, Measure, NMEAS);
-    }
-    if (Nlens >= NLENS) {
-      NLENS = Nlens + 1000;
+      REALLOCATE (tgtcat[0].measure, Measure, NMEAS);
+    }
+    if (Nlens >= NLENS - srccat->average[N].Nlensing) {
+      NLENS = Nlens + 1000 + srccat->average[N].Nlensing;
       REALLOCATE (next_lens, off_t, NLENS);
-      REALLOCATE (catalog[0].lensing, Lensing, NLENS);
-    }
-
-    /* add to end of measurement list */
-    add_meas_link (&catalog[0].average[n], next_meas, Nmeas, NMEAS);
-	
+      REALLOCATE (tgtcat[0].lensing, Lensing, NLENS);
+    }
+
     /** add measurements for this star **/
-
-    // set the new measurements
-    catalog[0].measure[Nmeas]          = stars[N].measure;
-
-    // measure now carries R,D (not dR,dD) 
-    catalog[0].measure[Nmeas].dbFlags  = 0;
-    catalog[0].measure[Nmeas].averef   = n;
-    catalog[0].measure[Nmeas].objID    = catalog[0].average[n].objID;
-    catalog[0].measure[Nmeas].catID    = catalog[0].catID;
-
-    float dRoff = dvoOffsetR(&catalog[0].measure[Nmeas], &catalog[0].average[n]);
-
-    // rationalize dR
-    if (dRoff > +180.0*3600.0) {
-      // average on high end of boundary, move star up
-      catalog[0].measure[Nmeas].R += 360.0;
-      dRoff -= 360.0*3600.0;
-    }
-    if (dRoff < -180.0*3600.0) {
-      // average on low end of boundary, move star down
-      catalog[0].measure[Nmeas].R -= 360.0;
-      dRoff += 360.0*3600.0;
-    }
-    if (fabs(dRoff) > 10*RADIUS) {
+    off_t mOff = srccat->average[N].measureOffset;
+    for (mSrc = 0; mSrc < srccat->average[N].Nmeasure; mSrc++) {
+      /* add to end of measurement list */
+      add_meas_link (&tgtcat[0].average[n], next_meas, Nmeas, NMEAS);
+
+      // set the new measurements
+      tgtcat[0].measure[Nmeas]          = srccat->measure[mSrc + mOff];
+
+      // measure now carries R,D (not dR,dD) 
+      tgtcat[0].measure[Nmeas].dbFlags  = 0;
+      tgtcat[0].measure[Nmeas].averef   = n;
+      tgtcat[0].measure[Nmeas].objID    = tgtcat[0].average[n].objID;
+      tgtcat[0].measure[Nmeas].catID    = tgtcat[0].catID;
+
+      float dRoff = dvoOffsetR(&tgtcat[0].measure[Nmeas], &tgtcat[0].average[n]);
+
+      // rationalize dR
+      if (dRoff > +180.0*3600.0) {
+	// average on high end of boundary, move star up
+	tgtcat[0].measure[Nmeas].R += 360.0;
+	dRoff -= 360.0*3600.0;
+      }
+      if (dRoff < -180.0*3600.0) {
+	// average on low end of boundary, move star down
+	tgtcat[0].measure[Nmeas].R -= 360.0;
+	dRoff += 360.0*3600.0;
+      }
+      if (fabs(dRoff) > 10*RADIUS) {
 	// take declination into account and check again.
-	double cosD = cos(RAD_DEG*catalog[0].average[n].D);
+	double cosD = cos(RAD_DEG*tgtcat[0].average[n].D);
 	if (fabs(dRoff*cosD) > 10*RADIUS) {
-	    fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
-		     catalog[0].average[n].R, catalog[0].average[n].D, 
-		     stars[N].average.R, stars[N].average.D,
-		     X1[i], X2[Jmin], 
-		     Y1[i], Y2[Jmin]);
-	    // XXX abort on this? -- this is a bad failure...
+	  fprintf (stderr, "error: %10.6f,%10.6f vs %10.6f,%10.6f (%f,%f vs %f,%f)\n", 
+		   tgtcat[0].average[n].R, tgtcat[0].average[n].D, 
+		   srccat->average[N].R, srccat->average[N].D,
+		   X1[i], X2[Jmin], 
+		   Y1[i], Y2[Jmin]);
+	  // XXX abort on this? -- this is a bad failure...
 	}
-    }
-
-    // add the lensing values if they exist
-    if (stars[N].lensing) {
-      add_lens_link (&catalog[0].average[n], next_lens, Nlens, NLENS); // ?
-      catalog[0].lensing[Nlens] = stars[N].lensing[0];
-      
-      catalog[0].lensing[Nlens].averef = n;
-      catalog[0].lensing[Nlens].objID = catalog[0].average[n].objID;
-      catalog[0].lensing[Nlens].catID = catalog[0].catID;
-      catalog[0].average[n].Nlensing ++;
-      Nlens ++;
-    }
-
-    /* adds the measurement to the calibration if appropriate color terms are found */
-    /* we call this before (optionally) setting the average magnitude to avoid auto-correlations */
-    if (options.calibrate) {
-      AddToCalibration (&catalog[0].average[n], &catalog[0].secfilt[n*Nsecfilt], catalog[0].measure, &catalog[0].measure[Nmeas], next_meas, N);
-    }
-
-    /* set the average magnitude if not already set and the photcode.equiv is not 0 */
-    /* in UPDATE mode, this value is not saved; use relphot to recalculate */
-    if (Nsec > -1) { 
-      if (isnan(catalog[0].secfilt[n*Nsecfilt+Nsec].M)) {
-	catalog[0].secfilt[n*Nsecfilt+Nsec].M = PhotCat (&catalog[0].measure[Nmeas], MAG_CLASS_PSF);
-      }
-    }
-
-    /* if we choose to flag close encounters, see find_matches.c */
-    /* if we choose to calculate RA,DEC averages, see update_coords.c */
-
-    /* Nm is updated, but not written out in -update mode (for existing entries)
-       Nm is recalculated in build_meas_links if loaded table is not sorted */
-    stars[N].found = Nmeas;
-    catalog[0].found_t[n] = Nmeas;
-    catalog[0].average[n].Nmeasure ++;
-    Nmeas ++;
-    i++;
-  }
-
-  /** incorporate unmatched image stars, if this star is in field of this catalog **/
-  /* these new entries are all written out in UPDATE mode */ 
-  for (i = 0; (i < Nstars) && !options.only_match; i += NSTAR_GROUP) {
-    /* make sure there is space for next entry */
-    if (Nmeas >= NMEAS - NSTAR_GROUP) {
-      NMEAS = Nmeas + 1000;
-      REALLOCATE (next_meas, off_t, NMEAS);
-      REALLOCATE (catalog[0].measure, Measure, NMEAS);
-    }
-    if (Nlens >= NLENS - NSTAR_GROUP) {
-      NLENS = Nlens + 1000;
-      REALLOCATE (next_lens, off_t, NLENS);
-      REALLOCATE (catalog[0].lensing, Lensing, NLENS);
-    }
-    if (Nave >= NAVE) {
-      NAVE = Nave + 1000;
-      REALLOCATE (catalog[0].average, Average, NAVE);
-      REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*catalog[0].Nsecfilt);
-    }
-
-    if (stars[i].found != -1) continue;
-    if (!IN_REGION (stars[i].average.R, stars[i].average.D)) continue;
-
-    dvo_average_init (&catalog[0].average[Nave]);
-    catalog[0].average[Nave].R         	   = stars[i].average.R;
-    catalog[0].average[Nave].D         	   = stars[i].average.D;
-
-    catalog[0].average[Nave].Nmeasure  	   = NSTAR_GROUP;
-    catalog[0].average[Nave].measureOffset = Nmeas;
-    catalog[0].average[Nave].objID     	   = objID;
-    catalog[0].average[Nave].catID     	   = catID;
-
-    if (PSPS_ID) {
-        catalog[0].average[Nave].extID = CreatePSPSObjectID(catalog[0].average[Nave].R, catalog[0].average[Nave].D);
-    }
-
-    objID ++;
-
-    for (j = 0; j < Nsecfilt; j++) {
-      dvo_secfilt_init (&catalog[0].secfilt[Nave*Nsecfilt+j], SECFILT_RESET_ALL);
-    }
-
-    for (j = 0; j < NSTAR_GROUP; j++) {
-      // supply the measurments from this detection
-      dvo_measure_init (&catalog[0].measure[Nmeas]);
-      catalog[0].measure[Nmeas]           = stars[i + j].measure;
-
-      // the following measure elements cannot be set until here:
-      catalog[0].measure[Nmeas].dbFlags  = 0;
-      catalog[0].measure[Nmeas].averef   = Nave;
-      catalog[0].measure[Nmeas].objID    = catalog[0].average[Nave].objID;
-      catalog[0].measure[Nmeas].catID    = catalog[0].catID;
+      }
+
+      /* adds the measurement to the calibration if appropriate color terms are found */
+      /* we call this before (optionally) setting the average magnitude to avoid auto-correlations */
+      if (options.calibrate) {
+	AddToCalibration (&tgtcat[0].average[n], &tgtcat[0].secfilt[n*Nsecfilt], tgtcat[0].measure, &tgtcat[0].measure[Nmeas], next_meas, N);
+      }
 
       /* set the average magnitude if not already set and the photcode.equiv is not 0 */
       /* in UPDATE mode, this value is not saved; use relphot to recalculate */
       if (Nsec > -1) { 
-	catalog[0].secfilt[Nave*Nsecfilt+Nsec].M = PhotCat (&catalog[0].measure[Nmeas], MAG_CLASS_PSF);
-      }
-
-      /* next[Nmeas] should always be -1 in this context (it is always the only
-	 measurement for the star) */
-      stars[i+j].found = Nmeas;
-      next_meas[Nmeas] = -1;  // inital value here update below
+	if (isnan(tgtcat[0].secfilt[n*Nsecfilt+Nsec].M)) {
+	  tgtcat[0].secfilt[n*Nsecfilt+Nsec].M = PhotCat (&tgtcat[0].measure[Nmeas], MAG_CLASS_PSF);
+	}
+      }
+
+      /* Nm is updated, but not written out in -update mode (for existing entries)
+	 Nm is recalculated in build_meas_links if loaded table is not sorted */
+      tgtcat[0].average[n].Nmeasure ++;
       Nmeas ++;
     }
-    for (j = 0; j < NSTAR_GROUP - 1; j++) {
-      next_meas[Nmeas - NSTAR_GROUP + j] = Nmeas - NSTAR_GROUP + j + 1;
-    }
+
+    // add the lensing values if they exist
+    if (srccat->lensing) {
+      /** add measurements for this star **/
+      off_t mOff = srccat->average[N].lensingOffset;
+      for (mSrc = 0; mSrc < srccat->average[N].Nlensing; mSrc++) {
+	/* add to end of lensing list */
+
+	add_lens_link (&tgtcat[0].average[n], next_lens, Nlens, NLENS); // ?
+	tgtcat[0].lensing[Nlens] = srccat->lensing[mSrc + mOff];
+      
+	tgtcat[0].lensing[Nlens].averef = n;
+	tgtcat[0].lensing[Nlens].objID = tgtcat[0].average[n].objID;
+	tgtcat[0].lensing[Nlens].catID = tgtcat[0].catID;
+	tgtcat[0].average[n].Nlensing ++;
+	Nlens ++;
+      }
+    }
+
+    /* if we choose to flag close encounters, see find_matches.c */
+    /* if we choose to calculate RA,DEC averages, see update_coords.c */
+
+    srccat->found_t[N] = n;
+    tgtcat[0].found_t[n] = -1;
+    i++;
+  }
+
+  /*************** add unmatched stars *************************/
+
+  /** incorporate unmatched image stars, if this star is in field of this tgtcat **/
+  /* these new entries are all written out in UPDATE mode */ 
+  for (i = 0; (i < Nstars) && !options.only_match; i++) {
+    /* make sure there is space for next entry */
+    if (Nmeas >= NMEAS - srccat->average[i].Nmeasure) {
+      NMEAS = Nmeas + 1000 + srccat->average[i].Nmeasure;
+      REALLOCATE (next_meas, off_t, NMEAS);
+      REALLOCATE (tgtcat[0].measure, Measure, NMEAS);
+    }
+    if (Nlens >= NLENS - srccat->average[i].Nlensing) {
+      NLENS = Nlens + 1000 + srccat->average[i].Nlensing;
+      REALLOCATE (next_lens, off_t, NLENS);
+      REALLOCATE (tgtcat[0].lensing, Lensing, NLENS);
+    }
+    if (Nave >= NAVE) {
+      NAVE = Nave + 1000;
+      REALLOCATE (tgtcat[0].average, Average, NAVE);
+      REALLOCATE (tgtcat[0].found_t, off_t, NAVE);
+      if (tgtcat[0].secfilt) {
+	// we only update the secfilt table if it has been allocated for output
+	REALLOCATE (tgtcat[0].secfilt, SecFilt, NAVE*tgtcat[0].Nsecfilt);
+      }
+    }
+
+    if (srccat->found_t[i] != -1) continue;
+    if (!IN_REGION (srccat->average[i].R, srccat->average[i].D)) continue;
+
+    dvo_average_init (&tgtcat[0].average[Nave]);
+    tgtcat[0].average[Nave].R         	   = srccat->average[i].R;
+    tgtcat[0].average[Nave].D         	   = srccat->average[i].D;
+
+    tgtcat[0].average[Nave].Nmeasure  	   = srccat->average[i].Nmeasure;
+    tgtcat[0].average[Nave].measureOffset  = Nmeas;
+    tgtcat[0].average[Nave].objID     	   = objID;
+    tgtcat[0].average[Nave].catID     	   = catID;
+
+    // this star has not yet been merged into another tgtcat
+    tgtcat[0].found_t[Nave]     	   = -1;
+
+    if (PSPS_ID) {
+        tgtcat[0].average[Nave].extID = CreatePSPSObjectID(tgtcat[0].average[Nave].R, tgtcat[0].average[Nave].D);
+    }
+
+    objID ++;
+
+    // we only update the secfilt table if it has been allocated for output
+    for (j = 0; tgtcat[0].secfilt && (j < Nsecfilt); j++) {
+      dvo_secfilt_init (&tgtcat[0].secfilt[Nave*Nsecfilt+j], SECFILT_RESET_ALL);
+    }
+
+    off_t mOff = srccat->average[i].measureOffset;
+    for (mSrc = 0; mSrc < srccat->average[i].Nmeasure; mSrc++) {
+      // supply the measurements from this detection
+      dvo_measure_init (&tgtcat[0].measure[Nmeas]);
+      tgtcat[0].measure[Nmeas] = srccat->measure[mSrc + mOff];
+
+      // the following measure elements cannot be set until here:
+      tgtcat[0].measure[Nmeas].dbFlags  = 0;
+      tgtcat[0].measure[Nmeas].averef   = Nave;
+      tgtcat[0].measure[Nmeas].objID    = tgtcat[0].average[Nave].objID;
+      tgtcat[0].measure[Nmeas].catID    = tgtcat[0].catID;
+
+      /* set the average magnitude if not already set and the photcode.equiv is not 0 */
+      /* in UPDATE mode, this value is not saved; use relphot to recalculate */
+      if (Nsec > -1) { 
+	tgtcat[0].secfilt[Nave*Nsecfilt+Nsec].M = PhotCat (&tgtcat[0].measure[Nmeas], MAG_CLASS_PSF);
+      }
+
+      Nmeas ++;
+
+      // update the next_meas pointer for this entry (last one for this star is -1)
+      next_meas[Nmeas-1] = (mSrc < srccat->average[i].Nmeasure - 1) ? Nmeas : -1;
+    }
+    srccat->found_t[i] = Nave;
 
     // if we have lensing data, insert that as well
-    if (stars[i].lensing) {
-      catalog[0].average[Nave].Nlensing = NSTAR_GROUP;
-      catalog[0].average[Nave].lensingOffset = Nlens;
-      for (j = 0; j < NSTAR_GROUP; j++) {
-	// add the lensing values if they exist
-	if (stars[i + j].lensing) {
-	  dvo_lensing_init (&catalog[0].lensing[Nlens]);
-	  catalog[0].lensing[Nlens] = stars[i + j].lensing[0];
+    if (srccat->lensing) {
+      tgtcat[0].average[Nave].Nlensing = srccat->average[i].Nlensing;
+      tgtcat[0].average[Nave].lensingOffset = Nlens;
+
+      off_t mOff = srccat->average[i].lensingOffset;
+      for (mSrc = 0; mSrc < srccat->average[i].Nlensing; mSrc++) {
+	dvo_lensing_init (&tgtcat[0].lensing[Nlens]);
+	tgtcat[0].lensing[Nlens] = srccat->lensing[mSrc + mOff];
 	  
-	  catalog[0].lensing[Nlens].averef = Nave;
-	  catalog[0].lensing[Nlens].objID = catalog[0].average[Nave].objID;
-	  catalog[0].lensing[Nlens].catID = catalog[0].catID;
-	  next_lens[Nlens] = -1; 
-	  Nlens ++;
-	}
-      }
-      for (j = 0; j < NSTAR_GROUP - 1; j++) {
-	next_lens[Nlens - NSTAR_GROUP + j] = Nlens - NSTAR_GROUP + j + 1;
-      }
-    }
-
+	tgtcat[0].lensing[Nlens].averef = Nave;
+	tgtcat[0].lensing[Nlens].objID = tgtcat[0].average[Nave].objID;
+	tgtcat[0].lensing[Nlens].catID = tgtcat[0].catID;
+	Nlens ++;
+	next_lens[Nlens-1] = (mSrc < srccat->average[i].Nlensing - 1) ? Nlens : -1; 
+      }
+    }
     Nave ++;
   }
-      
-  REALLOCATE (catalog[0].average, Average, Nave);
-  REALLOCATE (catalog[0].measure, Measure, Nmeas);
-  REALLOCATE (catalog[0].lensing, Lensing, Nlens);
+
+  REALLOCATE (tgtcat[0].average, Average, Nave);
+  REALLOCATE (tgtcat[0].measure, Measure, Nmeas);
+  REALLOCATE (tgtcat[0].lensing, Lensing, Nlens);
  
   if (options.nosort) {
-    catalog[0].sorted = FALSE;
+    tgtcat[0].sorted = FALSE;
   } else {
-    catalog[0].sorted = TRUE;
-    catalog[0].measure = sort_measure (catalog[0].average, Nave, catalog[0].measure, Nmeas, next_meas);
-    catalog[0].lensing = sort_lensing (catalog[0].average, Nave, catalog[0].lensing, Nlens, next_lens);
-  }
-
-  /* note stars which have been found in this catalog */
-  for (i = 0; i < NstarsIn; i++) {
-    if (stars[i].found > -1) {
-      stars[i].found = -2;
-    }
-  }
-
-  /* check if the catalog has changed?  if no change, no need to write */
-  catalog[0].objID    = objID; // new max value, save on catalog close
-  catalog[0].Naverage = Nave;
-  catalog[0].Nmeasure = Nmeas;
-  catalog[0].Nlensing = Nlens;
-  catalog[0].Nsecfilt_mem = Nave*Nsecfilt;
+    tgtcat[0].sorted = TRUE;
+    tgtcat[0].measure = sort_measure (tgtcat[0].average, Nave, tgtcat[0].measure, Nmeas, next_meas);
+    tgtcat[0].lensing = sort_lensing (tgtcat[0].average, Nave, tgtcat[0].lensing, Nlens, next_lens);
+  }
+
+  /* note stars which have been found in this tgtcat */
+  for (i = 0; i < srccat->Naverage; i++) {
+    if (srccat->found_t[i] > -1) {
+      srccat->found_t[i] = -2;
+    }
+  }
+
+  /* check if the tgtcat has changed?  if no change, no need to write */
+  tgtcat[0].objID    = objID; // new max value, save on tgtcat close
+  tgtcat[0].Naverage = Nave;
+  tgtcat[0].Nmeasure = Nmeas;
+  tgtcat[0].Nlensing = Nlens;
+  tgtcat[0].Nsecfilt_mem = tgtcat[0].secfilt ? Nave*Nsecfilt : 0;
   if (VERBOSE) fprintf (stderr, "Nstars, Nave, Nmeas, Nlens: "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT" "OFF_T_FMT", ("OFF_T_FMT" matches)\n",  Nstars,  Nave,  Nmeas,  Nlens, Nmatch);
 
@@ -394,10 +419,10 @@
    notes:
    
-   for finding if a catalog star is in an image or an image star is in the catalog:
+   for finding if a tgtcat star is in an image or an image star is in the tgtcat:
    
-   catalogs have boundaries defined by RA and DEC, but they may curve in projection
+   tgtcats have boundaries defined by RA and DEC, but they may curve in projection
    images have boundaries which are lines in pixels coords, but curve in RA and DEC
    
-   catalog[0].found[Ncat] but stars[Nstar].found
+   tgtcat[0].found[Ncat] but stars[Nstar].found
    
 */
Index: trunk/Ohana/src/addstar/src/find_matches_galphot.c
===================================================================
--- trunk/Ohana/src/addstar/src/find_matches_galphot.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/find_matches_galphot.c	(revision 38553)
@@ -0,0 +1,218 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+// we find matching stars by (R,D).  we add the galphot to the array of galphots with appropriate links.  
+int find_matches_galphot (SkyRegion *region, GalPhot_Stars *stars, int Nstars, Catalog *catalog, AddstarClientOptions *options) {
+  
+  off_t i, j, n, N, J, Jmin;
+  double RADIUS, RADIUS2, Rmin;
+  double *X1, *Y1, *X2, *Y2;
+  double dX, dY, dR;
+  off_t *N1, *N2;
+  off_t Nave, NAVE, Ngalphot, NGALPHOT, Nmatch;
+
+  /** allocate local arrays (stars) **/
+  ALLOCATE (X1, double, Nstars);
+  ALLOCATE (Y1, double, Nstars);
+  ALLOCATE (N1, off_t,  Nstars);
+
+  /** allocate local arrays (catalog) **/
+  NAVE = Nave = catalog[0].Naverage;
+  ALLOCATE (X2, double, NAVE);
+  ALLOCATE (Y2, double, NAVE);
+  ALLOCATE (N2, off_t,  NAVE);
+
+  /* internal counters */
+  Nmatch = 0;
+  NGALPHOT = Ngalphot = catalog[0].Ngalphot;
+
+  // current max obj ID for this catalog
+  unsigned int objID = catalog[0].objID;
+  unsigned int catID = catalog[0].catID;
+
+  int Nsecfilt = catalog[0].Nsecfilt;
+
+  /* project onto rectilinear grid with 1 arcsec pixels. the choice of ARC projection has
+   * the advantage that every point in R,D has a mapping to a unique X,Y.  However, note
+   * that not all possible X,Y points map back to R,D and the local plate scale changes
+   * far from the projection pole. We use the center of the region (catalog) for crval1,2.
+   */
+  Coords tcoords;
+  InitCoords (&tcoords, "DEC--ARC");
+  tcoords.crval1 = 0.5*(region[0].Rmin + region[0].Rmax);
+  tcoords.crval2 = (region[0].Dmax < 90) ? 0.5*(region[0].Dmin + region[0].Dmax) : 90.0;
+  tcoords.cdelt1 = tcoords.cdelt2 = 1.0 / 3600.0;
+
+  /* build spatial index (RA sort) referencing input array sequence */
+  for (i = 0; i < Nstars; i++) {
+    RD_to_XY (&X1[i], &Y1[i], stars[i].R, stars[i].D, &tcoords);
+    N1[i] = i;
+  }
+  sort_coords_index (X1, Y1, N1, Nstars);
+
+  /* build spatial index (RA sort) */
+  for (i = 0; i < Nave; i++) {
+    RD_to_XY (&X2[i], &Y2[i], catalog[0].average[i].R, catalog[0].average[i].D, &tcoords);
+    N2[i] = i;
+  }
+  sort_coords_index (X2, Y2, N2, Nave);
+
+  /* choose a radius for matches */
+  RADIUS = options->radius; /* provided by config */
+  RADIUS2 = RADIUS*RADIUS;
+
+  /** find matched stars **/
+  for (i = j = 0; (i < Nstars) && (j < Nave); ) {
+    if (!finite(X1[i]) || !finite(Y1[i])) { 
+      i++; 
+      continue;
+    }
+    if (!finite(X2[j]) || !finite(Y2[j])) { 
+      j++; 
+      continue;
+    }
+    
+    /* negative dX: j is too large */
+    dX = X1[i] - X2[j];
+    if (dX <= -1.02*RADIUS) {
+      i++;
+      continue;
+    }
+    /* positive dX, i is too large */
+    if (dX >= 1.02*RADIUS) {
+      j++;
+      continue;
+    }
+
+    if (stars[N1[i]].found) {
+      /* this star has already been assigned to an object in this or another catalog */
+      i++;
+      continue;
+    }
+
+    /* this block will match a given detection to the closest object within range of that detection.
+       XXX note that this matches ALL detections within range of the single object to that same object 
+       this is bad, but I cannot just go in linear order (ie, mark off each object as they are
+       used).  I should make a list of all Nobj * Ndet pairs in range and choose the matches
+       based on their separations.  UGH
+     */
+    
+    /* within match range; look for matches */
+    Jmin = -1;
+    Rmin = RADIUS2;
+    for (J = j; (dX > -1.02*RADIUS) && (J < Nave); J++) {
+      /* find closest match for this detection */
+      dX = X1[i] - X2[J];
+      dY = Y1[i] - Y2[J];
+      dR = dX*dX + dY*dY;
+      if (dR > RADIUS2) continue;
+      if (dR < Rmin) {
+	Rmin = dR;
+	Jmin  = J;
+      }
+    }
+
+    /* no match, try next detection */ 
+    if (Jmin == -1) {
+      i++;
+      continue;
+    }
+
+    /*** a match is found, add to galphot with links to average ***/
+    Nmatch ++;
+    n = N2[Jmin];
+    N = N1[i];
+
+    /* make sure there is space for next entry */
+    if (Ngalphot >= NGALPHOT) {
+      NGALPHOT = Ngalphot + 1000;
+      REALLOCATE (catalog[0].galphot, GalPhot, NGALPHOT);
+    }
+
+    /** add galphot for this star **/
+
+    // set the new galphotments
+    catalog[0].galphot[Ngalphot]          = stars[N].galphot;
+    catalog[0].galphot[Ngalphot].averef   = n;
+    catalog[0].galphot[Ngalphot].objID    = catalog[0].average[n].objID;
+    catalog[0].galphot[Ngalphot].catID    = catID;
+
+    // NOTE: include R,D in galphot?
+    // XXX if I add R,D to galphot, I should rationalize R,D to the same boundary?
+
+    stars[N].found = TRUE;
+    catalog[0].average[n].Ngalphot ++;
+    Ngalphot ++;
+    i++;
+  }
+
+# if (1)
+  /** incorporate unmatched image stars? **/
+  for (i = 0; (i < Nstars) && !options->only_match; i++) {
+
+    // skip already matched stars
+    if (stars[i].found) continue;
+    if (!IN_REGION (stars[i].R, stars[i].D)) continue;
+
+    /* make sure there is space for next entry */
+    if (Ngalphot >= NGALPHOT) {
+      NGALPHOT = Ngalphot + 1000;
+      REALLOCATE (catalog[0].galphot, GalPhot, NGALPHOT);
+    }
+    if (Nave >= NAVE) {
+      NAVE = Nave + 1000;
+      REALLOCATE (catalog[0].average, Average, NAVE);
+      REALLOCATE (catalog[0].secfilt, SecFilt, NAVE*Nsecfilt);
+    }
+
+    dvo_average_init (&catalog[0].average[Nave]);
+    catalog[0].average[Nave].R         	   = stars[i].R;
+    catalog[0].average[Nave].D         	   = stars[i].D;
+
+    catalog[0].average[Nave].Ngalphot  	   = 1;
+    catalog[0].average[Nave].galphotOffset = Ngalphot;
+    catalog[0].average[Nave].objID     	   = objID;
+    catalog[0].average[Nave].catID     	   = catID;
+
+    if (PSPS_ID) {
+      catalog[0].average[Nave].extID = CreatePSPSObjectID(catalog[0].average[Nave].R, catalog[0].average[Nave].D);
+    }
+
+    objID ++;
+
+    for (j = 0; j < Nsecfilt; j++) {
+      dvo_secfilt_init (&catalog[0].secfilt[Nave*Nsecfilt+j], SECFILT_RESET_ALL);
+    }
+
+    catalog[0].galphot[Ngalphot]        = stars[i].galphot;
+    catalog[0].galphot[Ngalphot].averef = Nave;
+    catalog[0].galphot[Ngalphot].objID  = catalog[0].average[Nave].objID;
+    catalog[0].galphot[Ngalphot].catID  = catID;
+
+    stars[i].found = TRUE;
+    Ngalphot ++;
+    Nave ++;
+  }
+# endif      
+
+  REALLOCATE (catalog[0].average, Average, Nave);
+  REALLOCATE (catalog[0].galphot, GalPhot, Ngalphot);
+ 
+  catalog[0].sorted = FALSE;
+
+  /* check if the catalog has changed?  if no change, no need to write */
+  catalog[0].objID     = objID; // new max value, save on catalog close
+  catalog[0].Naverage  = Nave;
+  catalog[0].Ngalphot  = Ngalphot;
+  catalog[0].Nsecfilt_mem = Nave*Nsecfilt;
+  if (VERBOSE) fprintf (stderr, "Nstars, Nave, Ngalphot: %d "OFF_T_FMT" "OFF_T_FMT" ("OFF_T_FMT" matches)\n",  Nstars, Nave, Ngalphot, Nmatch);
+
+  free (X1);
+  free (Y1);
+  free (N1);
+  free (N2);
+  free (X2);
+  free (Y2);
+
+  return (Nmatch);
+}
Index: trunk/Ohana/src/addstar/src/loadgalphot.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgalphot.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/loadgalphot.c	(revision 38553)
@@ -0,0 +1,30 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+/* This is the DVO program to upload fullforce summary cmf data for galaxies into a DVO database.
+
+   USAGE: loadgalphot -D CATDIR (catdir) (file.cmf)
+*/
+
+int main (int argc, char **argv) {
+
+  int i;
+  AddstarClientOptions options;
+
+  // need to construct these options with args_loadgalphot...
+  options = ConfigInit (&argc, argv);
+  options = args_loadgalphot (argc, argv, options);
+
+  // load the full sky description table (dvodb must exist)
+  SkyTable *sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, FALSE, SKY_DEPTH, VERBOSE);
+  SkyTableSetFilenames (sky, CATDIR, "cpt");
+  
+  // generate the subset matching the user-selected region
+  SkyList *skylist = SkyListByPatch (sky, -1, &UserPatch);
+
+  for (i = 1; i < argc; i++) {
+    fprintf (stderr, "loading %s\n", argv[i]);
+    loadgalphot_table (skylist, NULL, argv[i], &options);
+  }
+  exit (0);
+}  
Index: trunk/Ohana/src/addstar/src/loadgalphot_catalog.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgalphot_catalog.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/loadgalphot_catalog.c	(revision 38553)
@@ -0,0 +1,29 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+int loadgalphot_catalog (GalPhot_Stars *stars, int Nstars, SkyRegion *region, char *filename, AddstarClientOptions *options) {
+
+  Catalog catalog;
+
+  // now we have all of the loaded stars in this catalog
+  dvo_catalog_init (&catalog, TRUE);
+  catalog.filename = filename;
+  catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+  catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+  catalog.catflags = DVO_LOAD_AVERAGE | DVO_LOAD_SECFILT | DVO_LOAD_GALPHOT;
+  catalog.Nsecfilt  = GetPhotcodeNsecfilt ();
+    
+  // an error exit status here is a significant error
+  if (!dvo_catalog_open (&catalog, region, VERBOSE, "w")) {
+    fprintf (stderr, "ERROR: failure to open/create catalog file %s\n", catalog.filename);
+    exit (2);
+  }
+
+  find_matches_galphot (region, stars, Nstars, &catalog, options);
+    
+  dvo_catalog_save (&catalog, VERBOSE);
+  dvo_catalog_unlock (&catalog);
+  dvo_catalog_free (&catalog);
+
+  return (TRUE);
+}
Index: trunk/Ohana/src/addstar/src/loadgalphot_fit2d.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgalphot_fit2d.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/loadgalphot_fit2d.c	(revision 38553)
@@ -0,0 +1,262 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+# define VERY_VERBOSE 1
+
+Fit2D *fit2d_init (int order) {
+
+  int i;
+
+  Fit2D *fit;
+  ALLOCATE_ZERO (fit, Fit2D, 1);
+
+  // allocate static arrays
+  fit->order = order;
+  fit->nterm = order + 1;
+  fit->wterm = fit->nterm*(fit->nterm + 1)/2;
+  fit->mterm = 2*order + 1;
+
+  fit->ClipNiter = 1;
+  fit->ClipNsigma = 0.0;
+
+  /* allocate the summation matrices */
+  ALLOCATE (fit->s, double *, fit->mterm);
+  ALLOCATE (fit->b, double *, fit->wterm);
+  ALLOCATE (fit->B, double,   fit->wterm);
+  ALLOCATE (fit->c, double *, fit->wterm);
+  ALLOCATE (fit->C, double *, fit->wterm);
+  for (i = 0; i < fit->wterm; i++) {
+    ALLOCATE_ZERO (fit->c[i], double, fit->wterm);
+    ALLOCATE_ZERO (fit->C[i], double, fit->wterm);
+    ALLOCATE_ZERO (fit->b[i], double, 1);
+  }
+  for (i = 0; i < fit->mterm; i++) {
+    ALLOCATE_ZERO (fit->s[i], double, fit->mterm);
+  }
+  ALLOCATE_ZERO (fit->Cii, double, fit->wterm);
+  return fit;
+}
+
+int fit2d_reset (Fit2D *fit) {
+
+  int i;
+
+  for (i = 0; i < fit->wterm; i++) {
+    memset (fit->c[i], 0, fit->wterm*sizeof(double));
+    memset (fit->b[i], 0, sizeof(double));
+  }
+  for (i = 0; i < fit->mterm; i++) {
+    memset (fit->s[i], 0, fit->mterm*sizeof(double));
+  }
+  fit->c00 = 0.0;
+  fit->c10 = 0.0;
+  fit->c20 = 0.0;
+  fit->c01 = 0.0;
+  fit->c11 = 0.0;
+  fit->c02 = 0.0;
+
+  fit->mean = 0.0;
+  fit->sigma = 0.0;
+  return TRUE;
+}
+
+void fit2d_free (Fit2D *fit) {
+
+  int i;
+
+  for (i = 0; i < fit->wterm; i++) {
+    free (fit->C[i]);
+    free (fit->c[i]);
+    free (fit->b[i]);
+  }
+  free (fit->b);
+  free (fit->B);
+  free (fit->c);
+  free (fit->C);
+
+  for (i = 0; i < fit->mterm; i++) {
+    free (fit->s[i]);
+  }
+  free (fit->s);
+  free (fit);
+}
+
+// unweighted 2D 2nd order fit (6 free parameters)
+int fit2d (Fit2D *fit, float *xval, float *yval, float *zval, float *zfit, char *mask, int Npts) {
+  
+  int N, i, j, nx, ny, K, k, n, Npt, status;
+
+  double mean, sigma, maxsigma;
+
+  float *x, *y, *z, *zf;
+
+  for (N = 0; N < fit->ClipNiter; N++) {
+    fit2d_reset (fit);
+
+    // pointers which loop over datapoints
+    x = xval;
+    y = yval;
+    z = zval;
+
+    /* add up the x,y values */
+    for (i = 0; i < Npts; i++, x++, y++) {
+      if (mask[i]) continue;
+      if (!finite(*x) || !finite(*y) || !finite(*z)) continue;
+      double Y = 1.0;
+      for (ny = 0; ny < fit->mterm; ny++) {
+	double X = Y;
+	for (nx = 0; nx < fit->mterm - ny; nx++) {
+	  fit->s[nx][ny] += X;
+	  X = X * (*x);
+	}
+	Y = Y * (*y);
+      }
+    }
+
+    // pointers which loop over datapoints
+    x = xval;
+    y = yval;
+    z = zval;
+
+    /* add up the z values */
+    for (i = 0; i < Npts; i++, x++, y++, z++) {
+      if (mask[i]) continue;
+      if (!finite(*x) || !finite(*y) || !finite(*z)) continue;
+      double Y = *z;
+      for (j = 0, ny = 0; ny < fit->nterm; ny++) {
+	double X = Y;
+	for (nx = 0; nx < fit->nterm - ny; nx++, j++) {
+	  fit->b[j][0] += X;
+	  X = X * (*x);
+	}
+	Y = Y * (*y);
+      }
+    }
+
+    /* re-sort mterm x mterm matrix to wterm matrix */
+    for (k = j = 0; j < fit->nterm; j++) {
+      for (i = 0; i < fit->nterm - j; i++, k++) {
+	for (K = ny = 0; ny < fit->nterm; ny++) {
+	  for (nx = 0; nx < fit->nterm - ny; nx++, K++) {
+	    fit->c[K][k] = fit->s[nx+i][ny+j];
+	  }
+	}
+      }
+    }
+
+# if (VERY_VERBOSE)
+    for (i = 0; i < fit->wterm; i++) {
+      for (j = 0; j < fit->wterm; j++) {
+	fit->C[i][j] = fit->c[i][j];
+      }
+      fit->B[i] = fit->b[i][0];
+    }
+# endif
+
+    // invert the c,b matrix equation
+    status = dgaussjordan (fit->c, fit->b, fit->wterm, 1);
+    if (!status) {
+# if (VERY_VERBOSE)
+      for (i = 0; i < fit->wterm; i++) {
+	for (j = 0; j < fit->wterm; j++) {
+	  fprintf (stderr, "%10.3e ", fit->C[i][j]);
+	}
+	fprintf (stderr, " : %10.3e\n", fit->B[i]);
+      }
+# endif
+      return FALSE;
+    }
+
+    /* the b[][0] terms are in the following order:
+       y^0 x^0, y^0 x^1, ... y^0 x^N
+       y^1 x^0, y^1 x^1, ... y^1 x^N
+       ...
+       y^N x^0, y^N x^1, ... y^N x^N
+    */
+
+    /* generate fitted values */
+    x  = xval;
+    y  = yval;
+    zf = zfit;
+    for (n = 0; n < Npts; n++, x++, y++, zf++) {
+      if (!finite(*x) || !finite(*y) || !finite(*z)) continue;
+      *zf = 0;
+      double X = 1;
+      for (i = ny = 0; ny < fit->nterm; ny++) {
+	double Y = X;
+	for (nx = 0; nx < fit->nterm - ny; nx++, i++) {
+	  *zf += fit->b[i][0]*Y;
+	  Y = Y * (*y);
+	}
+	X = X * (*x);
+      }
+    }
+
+    /* measure fit residual scatter */
+    x  = xval;
+    y  = yval;
+    z  = zval;
+    zf = zfit;
+    float dZ  = 0.0;
+    float dZ2 = 0.0;
+    for (i = Npt = 0; i < Npts; i++, x++, y++, z++, zf++) {
+      if (mask[i]) continue;
+      if (!finite(*x) || !finite(*y) || !finite(*z)) continue;
+      float dZi = (*z - *zf);
+      dZ  += dZi;
+      dZ2 += SQ(dZi);
+      Npt ++;
+    }
+    mean  = dZ / Npt;
+    sigma = sqrt (fabs(dZ2/Npt - SQ(mean)));
+    maxsigma = fit->ClipNsigma * sigma;
+
+    // if (VERBOSE) gprint (GP_ERR, "mean: %g, sigma: %g, maxsigma: %g\n", mean, sigma, maxsigma);
+
+    /* mask outlier points */
+    x  = xval;
+    y  = yval;
+    z  = zval;
+    zf = zfit;
+    int Nmask = 0;
+    for (i = 0; fabs(fit->ClipNsigma) > 0.001 && (i < Npts); i++, x++, y++, z++, zf++) {
+      float dZi = (*z - *zf);
+      if (fabs(dZi) > maxsigma) {
+	mask[i] = TRUE;
+	Nmask ++;
+      } else {
+	mask[i] = FALSE;
+      }	
+    }
+    // if (VERBOSE) gprint (GP_ERR, "pass: %d, Nmask: %d\n", N, Nmask);
+  }
+    
+  // save the fit
+  for (i = 0; i < fit->wterm; i++) {
+    fit->Cii[i] = fit->b[i][0];
+  }
+  switch (fit->order) {
+    case 0:
+      fit->c00 = fit->Cii[0];
+      break;
+    case 1:
+      fit->c00 = fit->Cii[0];
+      fit->c10 = fit->Cii[1];
+      fit->c01 = fit->Cii[2];
+      break;
+    case 2:
+      fit->c00 = fit->Cii[0];
+      fit->c10 = fit->Cii[1];
+      fit->c20 = fit->Cii[2];
+      fit->c01 = fit->Cii[3];
+      fit->c11 = fit->Cii[4];
+      fit->c02 = fit->Cii[5];
+      break;
+    default:
+      myAbort("invalid order");
+  }
+
+  fit->mean  = mean;
+  fit->sigma = sigma;
+
+  return (TRUE);
+}
Index: trunk/Ohana/src/addstar/src/loadgalphot_join.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgalphot_join.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/loadgalphot_join.c	(revision 38553)
@@ -0,0 +1,70 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+// find the entries in 'fit' which match entries in 'gal'
+// return an index from gal -> fit (for gal[i], fit[index[i]] is a match)
+int *join_IDs (GalPhotIDset *gal, GalPhotIDset *fit) {
+  
+  int Nmatch = 0;
+  int NMATCH = gal->N;
+  int *idx_gal = NULL;
+  ALLOCATE (idx_gal, int, gal->N);
+
+  int *seq_fit, *seq_gal;
+  ALLOCATE (seq_gal, int, gal->N);
+  ALLOCATE (seq_fit, int, fit->N);
+  { 
+    int i;
+    for (i = 0; i < gal->N; i++) { seq_gal[i] = i; }
+    for (i = 0; i < fit->N; i++) { seq_fit[i] = i; }
+  }
+
+  // sort the sequences 
+  sort_IDs_seqonly (gal->ID, seq_gal, gal->N);
+  sort_IDs_seqonly (fit->ID, seq_fit, fit->N);
+
+  int ifit, igal;
+  for (ifit = igal = 0; (igal < gal->N) && (ifit < fit->N);) {
+    int Igal = seq_gal[igal];
+    int Ifit = seq_fit[ifit];
+
+    int dID = gal->ID[Igal] - fit->ID[Ifit];
+
+    if (dID < 0) { igal++; continue; }
+    if (dID > 0) { ifit++; continue; }
+
+    // look for all matches of list2() to list1(i)
+    // this allows for multiple values of ID1 or ID2
+    int ifit_first = ifit;
+    int found = FALSE;
+    for (ifit = ifit_first; (dID == 0) && (ifit < fit->N); ifit++) {
+      Ifit = seq_fit[ifit];
+      dID = gal->ID[Igal] - fit->ID[Ifit];
+      if ((dID == 0) && (gal->type[Igal] == fit->type[Ifit])){
+	idx_gal[Igal] = Ifit;
+	found = TRUE;
+	Nmatch ++;
+	if (Nmatch >= NMATCH) {
+	  NMATCH += 1000;
+	  REALLOCATE (idx_gal, int, NMATCH);
+	}
+	break;
+      }
+    }
+    myAssert (found, "gal entry not found?");
+    ifit = ifit_first;
+    igal ++;
+  }
+  free (seq_gal);
+  free (seq_fit);
+
+  myAssert (Nmatch == gal->N, "did not find matches for all galaxies");
+  
+  for (igal = 0; igal < gal->N; igal++) {
+    ifit = idx_gal[igal];
+    myAssert (fit->ID[ifit]   == gal->ID[igal],   "ID mis-match");
+    myAssert (fit->type[ifit] == gal->type[igal], "type mis-match");
+  }
+
+  return (idx_gal);
+}
Index: trunk/Ohana/src/addstar/src/loadgalphot_make_subset.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgalphot_make_subset.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/loadgalphot_make_subset.c	(revision 38553)
@@ -0,0 +1,44 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+// assign stars in the given region to the subset (NOTE: stars are sorted by RA, start is
+// first entry in stars array in this region)
+
+GalPhot_Stars *loadgalphot_make_subset (GalPhot_Stars *stars, int Nstars, int start, SkyRegion *region, int *nsubset) {
+
+  int i;
+
+  GalPhot_Stars *subset = NULL;
+
+  // collect array of (Stars *) stars in a new output catalog
+  int Nsubset = 0;
+  int NSUBSET = 3000;
+  ALLOCATE (subset, GalPhot_Stars, NSUBSET);
+
+  // find the rest of the stars in this output region
+  for (i = start; i < Nstars; i++) {
+    if (stars[i].flag) continue;
+
+    // check if in skyregion
+    if (stars[i].R < region[0].Rmin) continue;
+    if (stars[i].R > region[0].Rmax) break;
+    if (stars[i].D < region[0].Dmin) continue;
+    if (stars[i].D > region[0].Dmax) continue;
+	  
+    // check if in UserPatch (a GLOBAL)
+    if (stars[i].R < UserPatch.Rmin) continue;
+    if (stars[i].R > UserPatch.Rmax) break;
+    if (stars[i].D < UserPatch.Dmin) continue;
+    if (stars[i].D > UserPatch.Dmax) continue;
+	  
+    subset[Nsubset] = stars[i];
+    Nsubset ++;
+
+    stars[i].flag = TRUE;
+
+    CHECK_REALLOCATE (subset, GalPhot_Stars, NSUBSET, Nsubset, 10000);
+  }
+
+  *nsubset = Nsubset;
+  return subset;
+}
Index: trunk/Ohana/src/addstar/src/loadgalphot_readstars.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgalphot_readstars.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/loadgalphot_readstars.c	(revision 38553)
@@ -0,0 +1,385 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+# define GET_COLUMN(VER,OUT,NAME,TYPE)					\
+  TYPE *OUT = gfits_get_bintable_column_data (&header_##VER, &ftable_##VER, NAME, type, &NrowNew, &Ncol); \
+  myAssert (!strcmp(type, #TYPE), "wrong column type"); \
+  if (firstCol) { Nrow = NrowNew; firstCol = FALSE; } \
+  else { myAssert (Nrow == NrowNew, "table length mismatch"); }
+
+static float *Xpt = NULL;
+static float *Ypt = NULL;
+static float *Rpt = NULL;
+static float *Rsr = NULL;
+static char *mask = NULL;
+
+static float *chisqFit = NULL;
+
+GalPhot_Stars *loadgalphot_readstars (char *filename, int *nstars) {
+
+  // read in the full FITS files ('cause I don't have a partial read option)
+  FILE *f = fopen (filename, "r");
+  if (f == NULL) Shutdown ("can't read stellar parameter file: %s", filename);
+
+  int i, j, Ncol, Nsample;
+  off_t Nrow = 0;
+  off_t NrowNew;
+
+  char type[16];
+  int firstCol;
+
+  // load in PHU for astrometry
+  Header PHU;
+  if (!gfits_fread_header (f, &PHU)) {
+    if (VERBOSE) fprintf (stderr, "can't read image subset header\n");
+    fclose (f);
+    return NULL;
+  }
+
+  Header header_xfit;
+  FTable ftable_xfit;
+  if (!gfits_find_Xheader (f, &header_xfit, "SkyChip.xfit")) {
+    if (VERBOSE) fprintf (stderr, "can't read galaxy photometry header\n");
+    gfits_free_header (&header_xfit);
+    gfits_free_header (&PHU);
+    fclose (f);
+    return NULL;
+  }
+  ftable_xfit.header = &header_xfit;
+
+  // in xgal, we have numerical values to specify the model types
+  // in xfit, we have strings.  these are listed with their numerical 
+  // match in the PHU.  I need to read the list of names and set up a string hash
+
+  int ModelTypeN;
+  char **ModelTypeName;
+  int *ModelTypeNum;
+  int *ModelTypeHash;
+  if (!gfits_scan (&header_xfit, "MTNUM", "%d", 1, &ModelTypeN)) { myAbort ("fail"); }
+  ALLOCATE (ModelTypeName, char *, ModelTypeN);
+  ALLOCATE (ModelTypeNum,  int, ModelTypeN);
+  ALLOCATE (ModelTypeHash, int, ModelTypeN);
+
+  int tmpnumber, namehash[256][3];
+  for (i = 0; i < 256; i++) {
+    namehash[i][0] = -1;
+    namehash[i][1] = -1;
+    namehash[i][2] = -1;
+  }
+
+  char name[256], tmpname[256];
+  for (i = 0; i < ModelTypeN; i++) {
+    snprintf (name, 64, "MTNAM%02d", i);
+    if (!gfits_scan (&header_xfit, name, "%s", 1, tmpname)) { myAbort ("fail"); }
+    ModelTypeName[i] = strcreate (tmpname);
+    int found = FALSE;
+    int myHash = strhash (tmpname, 0xff);
+    fprintf (stderr, "model %s, hash: %d\n", tmpname, myHash);
+    ModelTypeHash[i] = myHash;
+    for (j = 0; (j < 3) && !found; j++) {
+      if (namehash[myHash][j] != -1) continue;
+      found = TRUE;
+      namehash[myHash][j] = i;
+    }
+    myAssert (found, "hash conflict");
+    snprintf (name, 64, "MTVAL%02d", i);
+    if (!gfits_scan (&header_xfit, name, "%d", 1, &tmpnumber)) { myAbort ("fail"); }
+    ModelTypeNum[i] = tmpnumber;
+  }
+
+  if (!gfits_fread_ftable_data (f, &ftable_xfit, FALSE)) {
+    if (VERBOSE) fprintf (stderr, "can't read galaxy photometry data\n");
+    gfits_free_header (&header_xfit);
+    gfits_free_header (&PHU);
+    fclose (f);
+    return (NULL);
+  }
+
+  firstCol = TRUE;
+  GET_COLUMN (xfit, ID_fit,         "IPP_IDET",      int);
+  GET_COLUMN (xfit, MODEL_TYPE_str, "MODEL_TYPE",    char);  int NcharModel = Ncol;
+  GET_COLUMN (xfit, EXT_WIDTH_MAJ,  "EXT_WIDTH_MAJ", float);
+  GET_COLUMN (xfit, EXT_WIDTH_MIN,  "EXT_WIDTH_MIN", float);
+  GET_COLUMN (xfit, EXT_THETA,      "EXT_THETA",     float);
+  GET_COLUMN (xfit, EXT_THETA_ERR,  "EXT_THETA_ERR", float);
+  GET_COLUMN (xfit, INDEX,          "EXT_PAR_07",    float);
+  int Nfit = Nrow;
+
+  myAssert (NcharModel < 256, "max model type name is very long: %d", NcharModel);
+
+  // free the memory associated with the FITS files
+  gfits_free_header (&header_xfit);
+  gfits_free_table (&ftable_xfit);
+
+  char string[256];
+
+  // convert MODEL_TYPE_str to MODEL_TYPE_fit (transforming strings to values)
+  int *MODEL_TYPE_fit;
+  ALLOCATE (MODEL_TYPE_fit, int, Nfit);
+  for (i = 0; i < Nfit; i++) {
+    memset (string, 0, 256);
+    memcpy (string, &MODEL_TYPE_str[i*NcharModel], NcharModel); string[NcharModel] = 0;
+    stripwhite (string);
+    int myHash = strhash (string, 0xff);
+    int found = FALSE;
+    for (j = 0; !found && (j < 3); j++) {
+      int n = namehash[myHash][j];
+      if (strcmp(ModelTypeName[n], string)) continue;
+      MODEL_TYPE_fit[i] = ModelTypeNum[n];
+      found = TRUE;
+    }
+    myAssert (found, "unknown model name? %s", string);
+  }
+
+  Header header_xgal;
+  FTable ftable_xgal;
+  if (!gfits_find_Xheader (f, &header_xgal, "SkyChip.xgal")) {
+    if (VERBOSE) fprintf (stderr, "can't read galaxy photometry header\n");
+    gfits_free_header (&header_xgal);
+    gfits_free_header (&PHU);
+    fclose (f);
+    return NULL;
+  }
+
+  ftable_xgal.header = &header_xgal;
+
+  if (!gfits_fread_ftable_data (f, &ftable_xgal, FALSE)) {
+    if (VERBOSE) fprintf (stderr, "can't read galaxy photometry data\n");
+    gfits_free_header (&header_xgal);
+    gfits_free_header (&PHU);
+    fclose (f);
+    return (NULL);
+  }
+
+  firstCol = TRUE;
+  GET_COLUMN (xgal, ID_gal,        "IPP_IDET",     int);
+  GET_COLUMN (xgal, MODEL_TYPE_gal,"MODEL_TYPE",   int);
+  GET_COLUMN (xgal, NPIX,          "NPIX",  	   float);
+  GET_COLUMN (xgal, X_FIT,         "X_FIT", 	   float);
+  GET_COLUMN (xgal, Y_FIT,         "Y_FIT", 	   float);
+  GET_COLUMN (xgal, GAL_FLUX,      "GAL_FLUX",     float); Nsample = Ncol;
+  GET_COLUMN (xgal, GAL_FLUX_ERR,  "GAL_FLUX_ERR", float); myAssert (Ncol == Nsample, "invalid table");
+  GET_COLUMN (xgal, GAL_CHISQ,     "GAL_CHISQ",    float); myAssert (Ncol == Nsample, "invalid table");
+  GET_COLUMN (xgal, FR_MAJOR_MIN,  "FR_MAJOR_MIN", float);
+  GET_COLUMN (xgal, FR_MAJOR_MAX,  "FR_MAJOR_MAX", float);
+  GET_COLUMN (xgal, FR_MAJOR_DEL,  "FR_MAJOR_DEL", float);
+  GET_COLUMN (xgal, FR_MINOR_MIN,  "FR_MINOR_MIN", float);
+  GET_COLUMN (xgal, FR_MINOR_MAX,  "FR_MINOR_MAX", float);
+  GET_COLUMN (xgal, FR_MINOR_DEL,  "FR_MINOR_DEL", float);
+  int Ngal = Nrow;
+
+  // i need to match the two lists based on (ID_gal == ID_fit), (MODEL_TYPE_gal == MODEL_TYPE_fit)
+  GalPhotIDset fitSet, galSet;
+  fitSet.ID   = ID_fit;
+  fitSet.type = MODEL_TYPE_fit;
+  fitSet.N    = Nfit;
+  galSet.ID   = ID_gal;
+  galSet.type = MODEL_TYPE_gal;
+  galSet.N    = Ngal;
+  int *idx_gal = join_IDs (&galSet, &fitSet);
+
+  // free the memory associated with the FITS files
+  gfits_free_header (&header_xgal);
+  gfits_free_table (&ftable_xgal);
+
+  GalPhot_Stars *stars = NULL;
+  ALLOCATE (stars, GalPhot_Stars, Nrow);
+
+  Coords coords;
+  GetCoords (&coords, &PHU);
+
+  // we reuse these arrays : allocate just once:
+  ALLOCATE (Xpt, float, Nsample);
+  ALLOCATE (Ypt, float, Nsample);
+  ALLOCATE (Rpt, float, Nsample);
+  ALLOCATE (Rsr, float, Nsample);
+  ALLOCATE (mask, char, Nsample);
+  ALLOCATE (chisqFit, float, Nsample);
+
+  Fit2D *fit = fit2d_init (2);
+  fit->ClipNiter = 3;
+  fit->ClipNsigma = 5.0;
+
+  int Nbad = 0;
+  for (i = 0; i < Nrow; i++) {
+
+    int ifit = idx_gal[i];
+
+    double R, D;
+    XY_to_RD (&R, &D, X_FIT[i], Y_FIT[i], &coords);
+
+    stars[i].R = R;
+    stars[i].D = D;
+    stars[i].flag  = FALSE;
+    stars[i].found = FALSE;
+
+    // stars[i].galphot.R = R;
+    // stars[i].galphot.D = D;
+    stars[i].galphot.Xfit = X_FIT[i];
+    stars[i].galphot.Yfit = Y_FIT[i];
+
+    // I need to match up with the entries in xfit to get:
+    // theta, theta_err, index, 
+    // note that FR_MAJOR, etc are the fractions of the stack fit value
+    stars[i].galphot.theta     = EXT_THETA[ifit];
+    stars[i].galphot.thetaErr  = EXT_THETA_ERR[ifit];
+    stars[i].galphot.index     = INDEX[ifit];
+    stars[i].galphot.Npix      = NPIX[i];
+    stars[i].galphot.modelType = MODEL_TYPE_gal[i];
+    stars[i].galphot.detID     = ID_gal[i];
+
+    // I have a grid of measurements with (Flux, dFlux, Chisq) at each point
+    // I need to find the minimum position (interpolated) in this 2D space
+
+    if (!FitChisqMinimum (fit, &stars[i].galphot, &GAL_CHISQ[Nsample*i], &GAL_FLUX[Nsample*i], &GAL_FLUX_ERR[Nsample*i], Nsample, FR_MAJOR_MIN[i], FR_MAJOR_MAX[i], FR_MAJOR_DEL[i], FR_MINOR_MIN[i], FR_MINOR_MAX[i], FR_MINOR_DEL[i])) {
+      Nbad ++;
+    }
+
+    // I could either multiply FR_MAJOR_MIN, etc above or the fitted values below
+    stars[i].galphot.majorAxis    *= EXT_WIDTH_MAJ[ifit];
+    stars[i].galphot.majorAxisErr *= EXT_WIDTH_MAJ[ifit];
+    stars[i].galphot.minorAxis    *= EXT_WIDTH_MIN[ifit];
+    stars[i].galphot.minorAxisErr *= EXT_WIDTH_MIN[ifit];
+  }
+
+  free (Xpt);
+  free (Ypt);
+  free (Rpt);
+  free (Rsr);
+  free (mask);
+  free (chisqFit);
+
+  fit2d_free (fit);
+
+  fprintf (stderr, "Nbad: %d of %d\n", Nbad, (int) Nrow);
+
+  *nstars = Nrow;
+  return (stars);
+}
+
+int loadgalphot_sortStars (GalPhot_Stars *stars, int Nstars) {
+
+# define SWAPFUNC(A,B){ GalPhot_Stars temp = stars[A]; stars[A] = stars[B]; stars[B] = temp; }
+# define COMPARE(A,B)(stars[A].R < stars[B].R)
+
+  OHANA_SORT (Nstars, COMPARE, SWAPFUNC);
+
+# undef SWAPFUNC
+# undef COMPARE
+  
+  return TRUE;
+}
+
+// for some reason, gcc does not (always?) pick up a declaration of this function 
+long lrint (double value);
+
+int FitChisqMinimum (Fit2D *fit, GalPhot *galphot, 
+		     float *chisq, float *flux, float *fluxErr, int Npts, 
+		     float MajorMin, float MajorMax, float MajorDel, 
+		     float MinorMin, float MinorMax, float MinorDel) {
+
+  int i;
+
+  // validate the square dimensions??
+
+  // int Nx = nearbyint((MajorMax - MajorMin) / MajorDel) + 1;
+  // int Ny = nearbyint((MinorMax - MinorMin) / MinorDel) + 1;
+
+  int Nx = lrint((MajorMax - MajorMin) / MajorDel) + 1;
+  int Ny = lrint((MinorMax - MinorMin) / MinorDel) + 1;
+
+  myAssert (Nx*Ny == Npts, "inconsistent grid");
+  
+  // here are the steps:
+  // find the minimum chisq grid point (set X,Y values)
+  // choose the nearest 9 points
+  // fit 2D parabola (6 free parameters)
+  // use this to outlier-clip remaining points
+  // fit 2D parabola to the rest
+
+  memset (mask, 0, Npts*sizeof(char));
+
+  float chisqMin = FLT_MAX;
+  int iMin = -1;
+  int Nvalid = 0;
+  for (i = 0; i < Npts; i++) {
+    if (!isfinite(chisq[i])) {
+      mask[i] = TRUE;
+      continue;
+    }
+    int iY = i / Nx;
+    int iX = i % Nx;
+    Xpt[i] = MajorMin + MajorDel*iX;
+    Ypt[i] = MinorMin + MinorDel*iY;
+    Nvalid ++;
+    if (chisq[i] < chisqMin) {
+      chisqMin = chisq[i];
+      iMin = i;
+    }
+  }
+  if (!Nvalid) {
+    fprintf (stderr, "no good points\n");
+    return FALSE; // we cannot do anything if there is no finite chisq
+  }
+  
+  if (Nvalid < 6) {
+    galphot->majorAxis = Xpt[iMin];
+    galphot->minorAxis = Ypt[iMin];
+    galphot->majorAxisErr = MajorDel;
+    galphot->minorAxisErr = MinorDel;
+    fprintf (stderr, "too few good points: %d\n", Nvalid);
+    return FALSE;
+  }
+
+  // re-fit all except the most extreme set
+  if (!fit2d (fit, Xpt, Ypt, chisq, chisqFit, mask, Npts)) {
+    // raise a flag?
+    galphot->majorAxis = Xpt[iMin];
+    galphot->minorAxis = Ypt[iMin];
+    galphot->majorAxisErr = MajorDel;
+    galphot->minorAxisErr = MinorDel;
+    fprintf (stderr, "failed fit\n");
+    return FALSE;
+  }
+
+  // get X,Y for the chisq min from the fit:
+  float Det = 1.0 / (4*fit->c20*fit->c02 - SQ(fit->c11));
+  float Xmin = (fit->c01*fit->c11 - 2.0*fit->c02*fit->c10) * Det;
+  float Ymin = (fit->c10*fit->c11 - 2.0*fit->c20*fit->c01) * Det;
+
+  // chisqMin @ (Xmin,Ymin)
+  chisqMin = 
+    fit->c00 + 
+    fit->c10*Xmin + fit->c20*Xmin*Xmin +
+    fit->c01*Ymin + fit->c02*Ymin*Ymin +
+    fit->c11*Xmin*Ymin;
+
+  float chisqOff = chisqMin + 1.0;
+
+  float A, B, C, Xoff, Yoff;
+
+  // Xoff @ chisqMin + 1.0
+  A = fit->c20;
+  B = fit->c10 + fit->c11*Ymin;
+  C = fit->c00 + fit->c01*Ymin + fit->c02*Ymin*Ymin - chisqOff;
+  Xoff = (-B + sqrt(B*B - 4*A*C)) / (2.0 * A);
+
+  // Xoff @ chisqMin + 1.0
+  A = fit->c02;
+  B = fit->c01 + fit->c11*Xmin;
+  C = fit->c00 + fit->c10*Xmin + fit->c20*Xmin*Xmin - chisqOff;
+  Yoff = (-B + sqrt(B*B - 4*A*C)) / (2.0 * A);
+
+  galphot->majorAxis = Xmin;
+  galphot->minorAxis = Ymin;
+  galphot->majorAxisErr = fabs(Xoff - Xmin);
+  galphot->minorAxisErr = fabs(Yoff - Ymin);
+
+  // use bilinear interpolation to choose Flux @ (Xmin,Ymin)?
+  galphot->mag    = -2.5*log10(flux[iMin]); // correct for exptime?
+  galphot->magErr = sqrt(fluxErr[iMin]) / flux[iMin];
+  galphot->chisq  = chisqMin;
+  
+  return TRUE;
+}
+
Index: trunk/Ohana/src/addstar/src/loadgalphot_table.c
===================================================================
--- trunk/Ohana/src/addstar/src/loadgalphot_table.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/loadgalphot_table.c	(revision 38553)
@@ -0,0 +1,49 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+int loadgalphot_table (SkyList *skylistInput, HostTable *hosts, char *filename, AddstarClientOptions *options) {
+  
+  int i, Nstars;
+
+  GalPhot_Stars *stars = loadgalphot_readstars (filename, &Nstars);
+
+  // sort the stars by RA
+  loadgalphot_sortStars (stars, Nstars);
+
+  // scan through the stars, loading the containing catalogs
+  // skip through table for unsaved stars
+  for (i = 0; i < Nstars; i++) {
+    if (stars[i].flag) continue;
+
+    // scan forward until we read the UserPatch
+    if (stars[i].R < UserPatch.Rmin) continue;
+    if (stars[i].R > UserPatch.Rmax) break;
+    if (stars[i].D < UserPatch.Dmin) continue;
+    if (stars[i].D > UserPatch.Dmax) continue;
+
+    // identify the relevant catalog
+    SkyList *skylist = SkyRegionByPoint_List (skylistInput, -1, stars[i].R, stars[i].D);
+    if (skylist[0].Nregions == 0) {
+      SkyListFree (skylist);
+      continue;
+    }
+    SkyRegion *region = skylist[0].regions[0];
+
+    // select stars matching this region
+    int Nsubset;
+    GalPhot_Stars *subset = loadgalphot_make_subset (stars, Nstars, i, region, &Nsubset);
+
+    // In parallel mode, write out the subset to a disk file.  Block until a remote host
+    // is available.  In serial mode, just match against the appropriate region and save
+    // NOTE: disable parallel mode for now: 
+    // loadgalphot_save_remote (subset, Nsubset, hosts, region, skylist[0].filename[0], options);
+    loadgalphot_catalog (subset, Nsubset, region, skylist[0].filename[0], options);
+  }
+
+  // wait for last remote clients to finish
+  // NOTE: disable parallel mode for now: 
+  // harvest_all ();
+
+  return TRUE;
+}
+
Index: trunk/Ohana/src/addstar/src/sortIDs.c
===================================================================
--- trunk/Ohana/src/addstar/src/sortIDs.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/sortIDs.c	(revision 38553)
@@ -0,0 +1,18 @@
+# include "addstar.h"
+# include "loadgalphot.h"
+
+/* sort a coordinate pair (X,Y) and the associated index (S) */
+void sort_IDs_seqonly (int *X, int *S, int N) {
+  
+# define SWAPFUNC(A,B){ off_t itmp; \
+  itmp = S[A]; S[A] = S[B]; S[B] = itmp; \
+}
+# define COMPARE(A,B)(X[S[A]] < X[S[B]])
+
+  OHANA_SORT (N, COMPARE, SWAPFUNC);
+
+# undef SWAPFUNC
+# undef COMPARE
+
+}
+
Index: trunk/Ohana/src/addstar/src/strhash.c
===================================================================
--- trunk/Ohana/src/addstar/src/strhash.c	(revision 38553)
+++ trunk/Ohana/src/addstar/src/strhash.c	(revision 38553)
@@ -0,0 +1,16 @@
+# include "addstar.h"
+
+int strhash (char *string, int modulus) {
+
+  myAssert (modulus < 0x100, "for the moment, (modulus) is limited to 255");
+
+  int Nchar = strlen (string);
+
+  int i;
+  int Nsum = 0;
+  for (i = 0; i < Nchar; i++) {
+    Nsum += (string[i] % modulus);
+  }
+  int value = Nsum % modulus;
+  return (value);
+}
Index: trunk/Ohana/src/addstar/test/compress.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/compress.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/compress.dvo	(revision 38553)
@@ -2,4 +2,9 @@
 
 input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
+
 $CATDIR = catdir.test.v0
 
@@ -38,5 +43,5 @@
   mkinput
   tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC -type $1 $NO_NOISE
-  tapEXEC addstar -D CATCOMPRESS $3 -D CATDIR $CATDIR -D CAMERA simtest test.cmf -D CATFORMAT $2 -quick-airmass
+  tapEXEC addstar -D CATCOMPRESS $3 -D CATDIR $CATDIR -D CAMERA gpc1 test.cmf -D CATFORMAT $2 -quick-airmass
 
   list testfields -copy testfields_$1
Index: trunk/Ohana/src/addstar/test/dvomerge.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/dvomerge.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/dvomerge.dvo	(revision 38553)
@@ -2,4 +2,13 @@
 
 input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
+
+macro test.all
+  $TAP_VERBOSE = 1
+  test.dvomerge.update.new
+end
 
 # create 2 populated catdirs, each with a couple of cmf files
@@ -8,7 +17,7 @@
   tapPLAN 51
 
-  exec rm -rf catdir.test1
-  exec rm -rf catdir.test2
-  exec rm -rf catdir.test3
+  tapEXEC rm -rf catdir.test1
+  tapEXEC rm -rf catdir.test2
+  tapEXEC rm -rf catdir.test3
 
   $RA = 10.0
@@ -16,34 +25,34 @@
 
   mkinput
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec 10.0 20.0
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec 10.0 20.0
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec 9.9 20.0
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec 9.9 20.0
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 05:00:00 -radec 10.0 19.9
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 06:00:00 -radec 10.0 19.9
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 07:00:00 -radec 9.9 19.9
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 08:00:00 -radec 9.9 19.9
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec 10.0 20.0
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec 10.0 20.0
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec 9.9 20.0
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec 9.9 20.0
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 05:00:00 -radec 10.0 19.9
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 06:00:00 -radec 10.0 19.9
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 07:00:00 -radec 9.9 19.9
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 08:00:00 -radec 9.9 19.9
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
 
   break
 
-  exec rsync -auc catdir.test2/ catdir.test3/
+  tapEXEC rsync -auc catdir.test2/ catdir.test3/
 
   date -var t1 -seconds -reftime 1276000000
-  exec dvomerge catdir.test1 into catdir.test3
+  tapEXEC dvomerge catdir.test1 into catdir.test3
   date -var t2 -seconds -reftime 1276000000
   echo "merge time: {$t2 - $t1}"
@@ -114,8 +123,8 @@
   end
 
-  # exec rm test.in.txt test.cmf
-  # exec rm -rf catdir.test1
-  # exec rm -rf catdir.test2
-  # exec rm -rf catdir.test3
+  # tapEXEC rm test.in.txt test.cmf
+  # tapEXEC rm -rf catdir.test1
+  # tapEXEC rm -rf catdir.test2
+  # tapEXEC rm -rf catdir.test3
 
   tapDONE
@@ -127,7 +136,7 @@
   tapPLAN 51
 
-  exec rm -rf catdir.test1
-  exec rm -rf catdir.test2
-  exec rm -rf catdir.test3
+  tapEXEC rm -rf catdir.test1
+  tapEXEC rm -rf catdir.test2
+  tapEXEC rm -rf catdir.test3
 
   $RA = 10.0
@@ -135,22 +144,20 @@
 
   mkinput
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  break
-
-  exec rsync -auc catdir.test2/ catdir.test3/
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC rsync -auc catdir.test2/ catdir.test3/
 
   date -var t1 -seconds -reftime 1276000000
-  exec dvomerge catdir.test1 into catdir.test3
+  tapEXEC dvomerge catdir.test1 into catdir.test3
   date -var t2 -seconds -reftime 1276000000
   echo "merge time: {$t2 - $t1}"
@@ -221,8 +228,8 @@
   end
 
-  # exec rm test.in.txt test.cmf
-  # exec rm -rf catdir.test1
-  # exec rm -rf catdir.test2
-  # exec rm -rf catdir.test3
+  # tapEXEC rm test.in.txt test.cmf
+  # tapEXEC rm -rf catdir.test1
+  # tapEXEC rm -rf catdir.test2
+  # tapEXEC rm -rf catdir.test3
 
   tapDONE
@@ -234,6 +241,6 @@
   tapPLAN 51
 
-  exec rm -rf catdir.test1
-  exec rm -rf catdir.test2
+  tapEXEC rm -rf catdir.test1
+  tapEXEC rm -rf catdir.test2
 
   $RA = 10.0
@@ -241,12 +248,12 @@
 
   mkinput
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
 
   date -var t1 -seconds -reftime 1276000000
-  exec dvomerge catdir.test1 into catdir.test2
+  tapEXEC dvomerge catdir.test1 into catdir.test2
   date -var t2 -seconds -reftime 1276000000
   echo "merge time: {$t2 - $t1}"
@@ -297,8 +304,8 @@
   end
 
-  # exec rm test.in.txt test.cmf
-  # exec rm -rf catdir.test1
-  # exec rm -rf catdir.test2
-  # exec rm -rf catdir.test3
+  # tapEXEC rm test.in.txt test.cmf
+  # tapEXEC rm -rf catdir.test1
+  # tapEXEC rm -rf catdir.test2
+  # tapEXEC rm -rf catdir.test3
 
   tapDONE
@@ -310,7 +317,7 @@
   tapPLAN 51
 
-  exec rm -rf catdir.test1
-  exec rm -rf catdir.test2
-  exec rm -rf catdir.test3
+  tapEXEC rm -rf catdir.test1
+  tapEXEC rm -rf catdir.test2
+  tapEXEC rm -rf catdir.test3
 
   $RA = 10.0
@@ -318,21 +325,21 @@
 
   mkinput
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
 
   # generate a few extra unmatched sources 
   mkinput.extras
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec rsync -auc catdir.test2/ catdir.test3/
-
-  exec dvomerge catdir.test1 into catdir.test3
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC rsync -auc catdir.test2/ catdir.test3/
+
+  tapEXEC dvomerge catdir.test1 into catdir.test3
 
   catdir catdir.test3
@@ -401,8 +408,8 @@
   end
 
-  # exec rm test.in.txt test.cmf
-  # exec rm -rf catdir.test1
-  # exec rm -rf catdir.test2
-  # exec rm -rf catdir.test3
+  # tapEXEC rm test.in.txt test.cmf
+  # tapEXEC rm -rf catdir.test1
+  # tapEXEC rm -rf catdir.test2
+  # tapEXEC rm -rf catdir.test3
 
   tapDONE
@@ -414,7 +421,7 @@
   tapPLAN 21
 
-  exec rm -rf catdir.test1
-  exec rm -rf catdir.test2
-  exec rm -rf catdir.test3
+  tapEXEC rm -rf catdir.test1
+  tapEXEC rm -rf catdir.test2
+  tapEXEC rm -rf catdir.test3
 
   $RA = 10.0
@@ -422,17 +429,17 @@
 
   mkinput
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test1 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec $RA $DEC
-  exec addstar -D CATDIR catdir.test2 -D CAMERA simtest test.cmf
-
-  exec dvomerge catdir.test1 and catdir.test2 to catdir.test3
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 02:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test1 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 03:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 04:00:00 -radec $RA $DEC
+  tapEXEC addstar -D CATDIR catdir.test2 -D CAMERA gpc1 test.cmf -quick-airmass
+
+  tapEXEC dvomerge catdir.test1 and catdir.test2 to catdir.test3
 
   catdir catdir.test3
@@ -501,8 +508,8 @@
   end
 
-  # exec rm test.in.txt test.cmf
-  # exec rm -rf catdir.test1
-  # exec rm -rf catdir.test2
-  # exec rm -rf catdir.test3
+  # tapEXEC rm test.in.txt test.cmf
+  # tapEXEC rm -rf catdir.test1
+  # tapEXEC rm -rf catdir.test2
+  # tapEXEC rm -rf catdir.test3
 
   tapDONE
@@ -511,5 +518,5 @@
 # make a simple input file for mkcmf
 macro mkinput.alt
-  exec rm -f test.in.txt
+  tapEXEC rm -f test.in.txt
 
   output test.in.txt
@@ -524,5 +531,5 @@
 # make a simple input file for mkcmf
 macro mkinput
-  exec rm -f test.in.txt
+  tapEXEC rm -f test.in.txt
 
   output test.in.txt
@@ -537,5 +544,5 @@
 # make a simple input file for mkcmf
 macro mkinput.extras
-  exec rm -f test.in.txt
+  tapEXEC rm -f test.in.txt
 
   output test.in.txt
Index: trunk/Ohana/src/addstar/test/groups.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/groups.dvo	(revision 38553)
+++ trunk/Ohana/src/addstar/test/groups.dvo	(revision 38553)
@@ -0,0 +1,479 @@
+# -*-sh-*-
+
+input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
+
+macro test.one
+  test.fields PS1_V5 PS1_V5
+end
+
+macro test.all
+  # test.fields (DVO schema) (CMF format)
+  test.fields PS1_DEV_0 PS1_V1
+  test.fields PS1_DEV_1 PS1_V1
+  test.fields PS1_V1    PS1_V1
+  test.fields PS1_V2    PS1_V1
+  test.fields PS1_V3    PS1_V1
+  test.fields PS1_V5    PS1_V1
+
+  test.fields PS1_DEV_0 PS1_V2
+  test.fields PS1_DEV_1 PS1_V2
+  test.fields PS1_V1    PS1_V2
+  test.fields PS1_V2    PS1_V2
+  test.fields PS1_V3    PS1_V2
+  test.fields PS1_V5    PS1_V2
+
+  test.fields PS1_DEV_0 PS1_V3
+  test.fields PS1_DEV_1 PS1_V3
+  test.fields PS1_V1    PS1_V3
+  test.fields PS1_V2    PS1_V3
+  test.fields PS1_V3    PS1_V3
+  test.fields PS1_V5    PS1_V3
+
+  test.fields PS1_DEV_0 PS1_V4
+  test.fields PS1_DEV_1 PS1_V4
+  test.fields PS1_V1    PS1_V4
+  test.fields PS1_V2    PS1_V4
+  test.fields PS1_V3    PS1_V4
+  test.fields PS1_V5    PS1_V4
+end  
+
+if (not($?NO_NOISE)) 
+  $NO_NOISE = ""
+end
+
+# create a populated catdir with a single cmf -- test each field
+macro test.fields
+  if ($0 != 3)
+    echo "USAGE: test.fields (cmftype) (dvotype?)"
+    break
+  end
+
+  echo ""
+  echo "testing --- CMF = $1, DVO = $2 ---"
+
+  exec rm -rf catdir.test
+
+  $RA = 10.0
+  $DEC = 20.0
+
+  mkinput
+  # tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC -type $1 $NO_NOISE
+
+  $options = 
+  $options = $options -type $1
+  $options = $options -radec $RA $DEC
+  $options = $options -mjd 54466.041667
+  $options = $options -date 2008/1/1 -time 01:00:00
+  $options = $options -photcode GPC1.g.XY00
+  $options = $options $NO_NOISE
+
+  # $options = $options -flags
+  # $options = $options -bad-psfqf-frac $DEFECT_FRAC
+  # $options = $options -size $CHIP_DX $CHIP_DY 
+  # $options = $options -crpix {0.5*$CHIP_DX} {0.5*$CHIP_DY} 
+  # $options = $options -airmass $AIRMASS
+  # $options = $options -exptime $EXPTIME
+  # $options = $options -coords 
+
+  for i 0 10
+    tapEXEC mkcmf test.in.txt test.$i.cmf $options
+  end
+  tapEXEC addstar -D CATDIR catdir.test -D CAMERA gpc1 test.?.cmf -D CATFORMAT $2 -quick-airmass
+
+  list testfields -copy testfields_$1
+
+  # set the number of tests based on the testfields list
+  tapPLAN {3 + 3*($testfields:n - 1)}
+
+  catdir catdir.test
+  skyregion {$RA-1.0} {$RA+1.0} {$DEC-1.0} {$DEC+1.0} 
+
+  data test.cmf
+
+  for i 0 $testfields:n
+    if ($TAP_VERBOSE) echo $testfields:$i
+    list name -split $testfields:$i
+    if ("$name:0" == "SKIP") continue
+    if ("$name:2" == "SKIP") continue
+ 
+    read -fits Chip.psf $name:0
+    mextract $name:2
+  end
+
+  # how is the detection ID?
+  list name -split $testfields:0
+  set ID1 = $name:0
+  set ID2 = $name:2
+  tapOK {ID1[] == ID2[]} "lengths for $name:0 vs $name:2"
+  if (not($TAP_LAST)) return
+
+  set d = $name:0 - $name:2
+  vstat -q d
+  tapOK {abs($MEAN)  < 0.001} "$name:0 vs $name:2 (MEAN = $MEAN)"
+  tapOK {abs($SIGMA) < 0.001} "$name:0 vs $name:2 (SIGMA = $SIGMA)"
+
+  # detection ID must be first for this to work:
+  for i 1 $testfields:n
+    list name -split $testfields:$i
+    if ("$name:0" == "SKIP") 
+      tapSKIP 3
+      continue
+    end
+    if ("$name:2" == "SKIP") 
+      tapSKIP 3
+      continue
+    end
+    # must be the same length
+    set v1 = $name:0
+    set v2 = $name:2
+    tapOK {v1[] == v2[]} "lengths for $name:0 vs $name:2"
+    if (not($TAP_LAST)) continue
+
+    set id1 = ID1
+    set id2 = ID2
+    sort id1 v1
+    sort id2 v2
+
+    # some fields require arithmetic manipulations
+    ## if ("$name:0" == "KRON_FLUX") 
+    ##  set v1 = -2.5*log(v1)
+    ## end
+    ## if ("$name:0" == "KRON_FLUX_ERR") 
+    ##  set v1 = KRON_FLUX_ERR / KRON_FLUX
+    ## end
+    if (("$name:0" == "X_PSF_SIG") || ("$name:0" == "Y_PSF_SIG"))
+     set v1 = int(100*(v1))
+     set v2 = int(100*(v2 + 0.0001))
+    end
+    if ("$name:0" == "POSANGLE")
+     set v1 = int((0xffff/360.0)*(v1))
+     set v2 = int((0xffff/360.0)*(v2 + 0.0028))
+    end
+
+    set d = v1 - v2
+    vstat -q d
+    
+    #echo tapOK fabs($MEAN)  < 0.001 "$name:0 vs $name:2 (MEAN)"
+    #echo tapOK fabs($SIGMA) < 0.001 "$name:0 vs $name:2 (SIGMA)"
+
+    # THETA is stored to only (360/65536) deg accuracy
+    if ("$name:0" == "PSF_THETA")
+      # echo $MEAN
+      tapOK {abs($MEAN)  < 0.006} "$name:0 vs $name:2 (MEAN = $MEAN)"
+      tapOK {abs($SIGMA) < 0.001} "$name:0 vs $name:2 (SIGMA = $SIGMA)"
+      continue
+    end
+
+    tapOK {abs($MEAN)  < 0.001} "$name:0 vs $name:2 (MEAN = $MEAN)"
+    tapOK {abs($SIGMA) < 0.001} "$name:0 vs $name:2 (SIGMA = $MEAN)"
+  end    
+
+  # exec rm test.cmf test.in.txt
+  # exec rm -r catdir.test
+
+  tapDONE
+end
+
+# make a simple input file for mkcmf
+macro mkinput
+  exec rm -f test.in.txt
+
+  output test.in.txt
+  for i 10 1024 100
+    for j 10 1024 100
+      fprintf " %4d %4d  %6.2f" $i $j {-15.0 + 2.5*($i + $j)/1000.0}
+    end
+  end
+  output stdout
+end
+
+# the following lists define fields in the cmf files which can be compared to their equivalents in DVO
+# the left column is the cmf field name, the right column is the dvo field name
+
+# list of cmf fields to test matched to mextract fields
+# this list is good for PS1_DEV_0
+list testfields_PS1_DEV_0
+  IPP_IDET          : detid
+  X_PSF             : xccd
+  Y_PSF             : yccd
+  X_PSF_SIG         : xccd:err
+  Y_PSF_SIG         : yccd:err
+  PSF_INST_MAG      : mag:inst
+  PSF_INST_MAG_SIG  : mag:err
+  PEAK_FLUX_AS_MAG  : SKIP # not ingested into DVO
+  SKY               : sky
+  SKY_SIG           : sky_err
+  PSF_CHISQ         : psf_chisq
+  PSF_WIDTH_X       : FWHM_MAJ
+  PSF_WIDTH_Y       : FWHM_MIN
+  PSF_THETA         : THETA
+  PSF_QF            : PSF_QF
+  N_FRAMES          : SKIP # not ingested into DVO
+end
+
+# list of cmf fields to test matched to mextract fields
+# this list is good for PS1_DEV_1
+list testfields_PS1_DEV_1
+  IPP_IDET          : detid
+  X_PSF             : xccd
+  Y_PSF             : yccd
+  X_PSF_SIG         : xccd:err
+  Y_PSF_SIG         : yccd:err
+  PSF_INST_MAG      : mag:inst
+  PSF_INST_MAG_SIG  : mag:err
+  PEAK_FLUX_AS_MAG  : SKIP # not ingested into DVO
+  SKY               : sky
+  SKY_SIG           : sky_err
+  PSF_CHISQ         : psf_chisq
+  CR_NSIGMA         : cr_nsigma
+  EXT_NSIGMA        : ext_nsigma
+  PSF_WIDTH_X       : FWHM_MAJ
+  PSF_WIDTH_Y       : FWHM_MIN
+  PSF_THETA         : THETA
+  PSF_QF            : PSF_QF
+  N_FRAMES          : SKIP # not ingested into DVO
+  FLAGS             : phot_flags
+end
+
+# this list is good for PS1_V1
+list testfields_PS1_V1
+  IPP_IDET          : detid     
+  X_PSF             : xccd      
+  Y_PSF             : yccd      
+  X_PSF_SIG         : xccd:err #  FAIL
+  Y_PSF_SIG         : yccd:err # FAIL
+  RA_PSF            : SKIP # astrometry is not calibrated in the cmf
+  DEC_PSF           : SKIP # astrometry is not calibrated in the cmf
+  POSANGLE          : SKIP # astrometry is not calibrated in the cmf
+  PLTSCALE          : SKIP # astrometry is not calibrated in the cmf
+  PSF_INST_MAG      : mag:inst  
+  PSF_INST_MAG_SIG  : mag:err   
+# AP_MAG_STANDARD   : mag:ap # FAIL
+  AP_MAG_RADIUS     : SKIP # no accessor
+  PEAK_FLUX_AS_MAG  : SKIP # no accessor
+  CAL_PSF_MAG       : SKIP # photometry is not calibrated in the cmf
+  CAL_PSF_MAG_SIG   : SKIP # photometry is not calibrated in the cmf
+  SKY               : sky       
+  SKY_SIGMA         : sky_err   
+  PSF_CHISQ         : psf_chisq 
+  CR_NSIGMA         : cr_nsigma 
+  EXT_NSIGMA        : ext_nsigma
+  PSF_MAJOR         : FWHM_MAJ  
+  PSF_MINOR         : FWHM_MIN  
+  PSF_THETA         : THETA # FAIL
+  PSF_QF            : PSF_QF    
+  PSF_NDOF          : SKIP # no accessor
+  PSF_NPIX          : SKIP # no accessor
+  MOMENTS_XX        : SKIP # no accessor
+  MOMENTS_XY        : SKIP # no accessor
+  MOMENTS_YY        : SKIP # no accessor
+  FLAGS             : phot_flags
+  N_FRAMES          : SKIP # no accessor        
+end
+
+# this list is good for PS1_V2
+list testfields_PS1_V2
+  IPP_IDET          : detid     
+  X_PSF             : xccd      
+  Y_PSF             : yccd      
+  X_PSF_SIG         : xccd:err # FAIL
+  Y_PSF_SIG         : yccd:err # FAIL
+  RA_PSF            : SKIP # astrometry is not calibrated in the cmf
+  DEC_PSF           : SKIP # astrometry is not calibrated in the cmf
+  POSANGLE          : SKIP # astrometry is not calibrated in the cmf
+  PLTSCALE          : SKIP # astrometry is not calibrated in the cmf
+  PSF_INST_MAG      : mag:inst  
+  PSF_INST_MAG_SIG  : mag:err   
+# AP_MAG_STANDARD   : mag:ap # FAIL
+  AP_MAG_RADIUS     : SKIP # no accessor
+  PEAK_FLUX_AS_MAG  : SKIP # no accessor
+  CAL_PSF_MAG       : SKIP # photometry is not calibrated in the cmf
+  CAL_PSF_MAG_SIG   : SKIP # photometry is not calibrated in the cmf
+  SKY               : sky       
+  SKY_SIGMA         : sky_err   
+  PSF_CHISQ         : psf_chisq 
+  CR_NSIGMA         : cr_nsigma 
+  EXT_NSIGMA        : ext_nsigma
+  PSF_MAJOR         : FWHM_MAJ  
+  PSF_MINOR         : FWHM_MIN  
+  PSF_THETA         : THETA # FAIL
+  PSF_QF            : PSF_QF    
+  PSF_NDOF          : SKIP # no accessor
+  PSF_NPIX          : SKIP # no accessor
+  MOMENTS_XX        : SKIP # no accessor
+  MOMENTS_XY        : SKIP # no accessor
+  MOMENTS_YY        : SKIP # no accessor
+  FLAGS             : phot_flags
+  N_FRAMES          : SKIP # no accessor        
+end
+
+# this list is good for PS1_V3
+list testfields_PS1_V3
+  IPP_IDET          : detid     
+  X_PSF             : xccd      
+  Y_PSF             : yccd      
+  X_PSF_SIG         : xccd:err # FAIL
+  Y_PSF_SIG         : yccd:err # FAIL
+  POSANGLE          : SKIP # astrometry is not calibrated in the cmf
+  PLTSCALE          : SKIP # astrometry is not calibrated in the cmf
+  PSF_INST_MAG      : mag:inst  
+  PSF_INST_MAG_SIG  : mag:err   
+  PSF_INST_FLUX     : SKIP # not ingested into DVO
+  PSF_INST_FLUX_SIG : SKIP # not ingested into DVO
+# AP_MAG_STANDARD   : mag:aperinst # FAIL
+  AP_MAG_RAW        : SKIP # not ingested into DVO
+  AP_MAG_RADIUS     : SKIP # not ingested into DVO
+  CAL_PSF_MAG       : SKIP # photometry is not calibrated in the cmf
+  CAL_PSF_MAG_SIG   : SKIP # photometry is not calibrated in the cmf
+  RA_PSF            : SKIP # astrometry is not calibrated in the cmf
+  DEC_PSF           : SKIP # astrometry is not calibrated in the cmf
+  PEAK_FLUX_AS_MAG  : SKIP # not ingested into DVO
+  SKY               : sky       
+  SKY_SIGMA         : sky_err   
+  PSF_CHISQ         : psf_chisq 
+  CR_NSIGMA         : cr_nsigma 
+  EXT_NSIGMA        : ext_nsigma
+  PSF_MAJOR         : FWHM_MAJ  
+  PSF_MINOR         : FWHM_MIN  
+  PSF_THETA         : THETA # FAIL
+  PSF_QF            : PSF_QF    
+  PSF_QF_PERFECT    : SKIP # not ingested into DVO
+  PSF_NDOF          : PSF_NDOF
+  PSF_NPIX          : PSF_NPIX
+  MOMENTS_XX        : MXX
+  MOMENTS_XY        : MXY
+  MOMENTS_YY        : MYY
+  MOMENTS_M3C       : SKIP # not ingested into DVO
+  MOMENTS_M3S       : SKIP # not ingested into DVO
+  MOMENTS_M4C       : SKIP # not ingested into DVO
+  MOMENTS_M4S       : SKIP # not ingested into DVO
+  MOMENTS_R1        : SKIP # not ingested into DVO
+  MOMENTS_RH        : SKIP # not ingested into DVO
+  KRON_FLUX         : mag:kron:inst
+  KRON_FLUX_ERR     : mag:kron:err
+  KRON_FLUX_INNER   : SKIP # not ingested into DVO
+  KRON_FLUX_OUTER   : SKIP # not ingested into DVO
+  FLAGS             : phot_flags
+  N_FRAMES          : SKIP # not ingested into DVO
+end
+
+# this list is good for PS1_V5
+list testfields_PS1_V5
+  IPP_IDET          : detid     
+  X_PSF             : xccd      
+  Y_PSF             : yccd      
+  X_PSF_SIG         : xccd:err
+  Y_PSF_SIG         : yccd:err
+  POSANGLE          : posangle
+  PLTSCALE          : platescale
+  PSF_INST_MAG      : mag:inst  
+  PSF_INST_MAG_SIG  : mag:err   
+  PSF_INST_FLUX     : flux:inst
+  PSF_INST_FLUX_SIG : flux:inst:err
+  AP_MAG            : mag:aper:inst
+  AP_MAG_RAW        : SKIP # not ingested into DVO
+  AP_MAG_RADIUS     : SKIP # not ingested into DVO
+  AP_FLUX           : flux:aper:inst  
+  AP_FLUX_SIG       : flux:aper:inst:err
+  CAL_PSF_MAG       : mag:cal
+  CAL_PSF_MAG_SIG   : mag:cal:err
+  RA_PSF            : ra
+  DEC_PSF           : dec
+  AP_NPIX           : SKIP # not ingested into DVO		      
+  PEAK_FLUX_AS_MAG  : SKIP # not ingested into DVO		      
+  SKY               : sky       				      
+  SKY_SIGMA         : sky_err   				      
+  PSF_CHISQ         : psf_chisq 				      
+  CR_NSIGMA         : cr_nsigma 				      
+  EXT_NSIGMA        : ext_nsigma				      
+  PSF_MAJOR         : fwhm_maj # XXX technically, this is not FWHM but Sigma
+  PSF_MINOR         : fwhm_min # XXX technically, this is not FWHM but Sigma
+  PSF_THETA         : theta # FAIL				      
+  PSF_CORE          : SKIP # not ingested into DVO 
+  PSF_FWHM_MAJ      : SKIP # not ingested into DVO 
+  PSF_FWHM_MIN      : SKIP # not ingested into DVO 
+  PSF_QF            : psf_qf    				      
+  PSF_QF_PERFECT    : SKIP # not ingested into DVO		      
+  PSF_NDOF          : psf_ndof				      
+  PSF_NPIX          : psf_npix				      
+  MOMENTS_XX        : Mxx					      
+  MOMENTS_XY        : Mxy					      
+  MOMENTS_YY        : Myy					      
+  MOMENTS_M3C       : SKIP # not ingested into DVO		      
+  MOMENTS_M3S       : SKIP # not ingested into DVO		      
+  MOMENTS_M4C       : SKIP # not ingested into DVO		      
+  MOMENTS_M4S       : SKIP # not ingested into DVO		      
+  MOMENTS_R1        : SKIP # not ingested into DVO		      
+  MOMENTS_RH        : SKIP # not ingested into DVO		      
+  KRON_FLUX         : flux:kron:inst				      
+  KRON_FLUX_ERR     : flux:kron:inst:err				      
+  KRON_FLUX_INNER   : SKIP # not ingested into DVO		          
+  KRON_FLUX_OUTER   : SKIP # not ingested into DVO		      
+  SKY_LIMIT_RAD     : SKIP # not ingested into DVO		          
+  SKY_LIMIT_FLUX    : SKIP # not ingested into DVO		          
+  SKY_LIMIT_SLOPE   : SKIP # not ingested into DVO		          
+  FLAGS             : phot_flags				      
+  FLAGS2            : SKIP # not ingested into DVO		          
+  N_FRAMES          : SKIP # not ingested into DVO		      
+end								      
+
+# this list is good for PS1_SV3
+list testfields_PS1_SV3
+  IPP_IDET          : detid     
+  X_PSF             : xccd      
+  Y_PSF             : yccd      
+  X_PSF_SIG         : xccd:err
+  Y_PSF_SIG         : yccd:err
+  POSANGLE          : posangle
+  PLTSCALE          : platescale
+  PSF_INST_MAG      : mag:inst  
+  PSF_INST_MAG_SIG  : mag:err   
+  PSF_INST_FLUX     : flux:inst
+  PSF_INST_FLUX_SIG : flux:inst:err
+  AP_MAG            : mag:aper:inst
+  AP_MAG_RAW        : SKIP # not ingested into DVO
+  AP_MAG_RADIUS     : SKIP # not ingested into DVO
+  AP_FLUX           : flux:aper:inst  
+  AP_FLUX_SIG       : flux:aper:inst:err
+  CAL_PSF_MAG       : mag:cal
+  CAL_PSF_MAG_SIG   : mag:cal:err
+  RA_PSF            : ra
+  DEC_PSF           : dec
+  AP_NPIX           : SKIP # not ingested into DVO		      
+  PEAK_FLUX_AS_MAG  : SKIP # not ingested into DVO		      
+  SKY               : sky       				      
+  SKY_SIGMA         : sky_err   				      
+  PSF_CHISQ         : psf_chisq 				      
+  CR_NSIGMA         : cr_nsigma 				      
+  EXT_NSIGMA        : ext_nsigma				      
+  PSF_MAJOR         : fwhm_maj # XXX technically, this is not FWHM but Sigma
+  PSF_MINOR         : fwhm_min # XXX technically, this is not FWHM but Sigma
+  PSF_THETA         : theta # FAIL				      
+  PSF_CORE          : SKIP # not ingested into DVO 
+  PSF_FWHM_MAJ      : SKIP # not ingested into DVO 
+  PSF_FWHM_MIN      : SKIP # not ingested into DVO 
+  PSF_QF            : psf_qf    				      
+  PSF_QF_PERFECT    : SKIP # not ingested into DVO		      
+  PSF_NDOF          : psf_ndof				      
+  PSF_NPIX          : psf_npix				      
+  MOMENTS_XX        : Mxx					      
+  MOMENTS_XY        : Mxy					      
+  MOMENTS_YY        : Myy					      
+  MOMENTS_M3C       : SKIP # not ingested into DVO		      
+  MOMENTS_M3S       : SKIP # not ingested into DVO		      
+  MOMENTS_M4C       : SKIP # not ingested into DVO		      
+  MOMENTS_M4S       : SKIP # not ingested into DVO		      
+  MOMENTS_R1        : SKIP # not ingested into DVO		      
+  MOMENTS_RH        : SKIP # not ingested into DVO		      
+  KRON_FLUX         : flux:kron:inst				      
+  KRON_FLUX_ERR     : flux:kron:inst:err				      
+  KRON_FLUX_INNER   : SKIP # not ingested into DVO		          
+  KRON_FLUX_OUTER   : SKIP # not ingested into DVO		      
+  FLAGS             : phot_flags				      
+  FLAGS2            : SKIP # not ingested into DVO		          
+  N_FRAMES          : SKIP # not ingested into DVO		      
+end								      
Index: trunk/Ohana/src/addstar/test/ptolemy.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/ptolemy.dvo	(revision 38553)
+++ trunk/Ohana/src/addstar/test/ptolemy.dvo	(revision 38553)
@@ -0,0 +1,46 @@
+
+macro mkptolemy.rc
+  # generate a fake ptolemy.rc (to make this a contained test)
+  exec rm -f ptolemy.rc
+  output ptolemy.rc
+    echo "\#"
+    echo PHOTCODE_FILE dvo.photcodes
+    echo GSCFILE GSCregions.tbl
+    echo ZERO_PT 25.0
+    echo ADDSTAR_RADIUS 1.0
+    echo CATMODE                 SPLIT
+    echo CATFORMAT               PS1_V5
+    # echo CATFORMAT               PS1_V2 -- must be at least PS1_V3 for ubercaldist to work
+    echo SKY_DEPTH               4
+    echo CAMERA                  gpc1
+    echo CAMERA_CONFIG           dvo.layout
+    echo "input dvo.config"
+  output stdout
+
+  # we need to define a photcode table consistent with the fake construction
+  $zpt_nominal:g = 24.0
+  $zpt_nominal:r = 24.5
+
+  # klam is negative, so klam*(airmass - 1) increases the zero point
+  $klam_nominal:g = -0.15
+  $klam_nominal:r = -0.10
+
+  # generate a fake dvo.photcode
+  exec rm -f dvo.photcodes
+  output dvo.photcodes
+    echo "\# code  name                type    zero  slope offset c1    c2   slope   zero  equiv  sys scale   scale  sys     poor   bad     poor   bad"
+    echo "1     g                    sec   0.000  0.000 0.000     1     3 0.0000     0  1051   0.000 0.000 0.000  0.000   0x0000 0x0000  0x0000 0x0000"
+    echo "2     r                    sec   0.000  0.000 0.000     2     3 0.0000     0  1052   0.000 0.000 0.000  0.000   0x0000 0x0000  0x0000 0x0000"
+    echo "10000 GPC1.g.XY00          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "10001 GPC1.g.XY01          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "10010 GPC1.g.XY10          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "10011 GPC1.g.XY11          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "10100 GPC1.r.XY00          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "10101 GPC1.r.XY01          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "10110 GPC1.r.XY10          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "10111 GPC1.r.XY11          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
+    echo "2011  2MASS_J              ref   0.000  0.000 0.000     -     - 0.0000     0     6   0.080 0.000 2.000  0.000   0x0000 0x0000  0x0000 0x0000"
+    echo "3001  SYNTH.g              ref   0.000  0.000 0.000     -     - 0.0000     0     1     nan 0.000 2.000  0.600   0x0000 0x0000  0x0000 0x0000"
+    echo "2020  TYCHO_B              ref   0.000  0.000 0.000     -     - 0.0000     0     -   0.000 0.000 0.000  0.000   0x0000 0x0000  0x0000 0x0000"
+  output stdout      
+end
Index: trunk/Ohana/src/addstar/test/relastro.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/relastro.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/relastro.dvo	(revision 38553)
@@ -2,4 +2,8 @@
 
 input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
 
 macro test.all
@@ -60,5 +64,5 @@
     mkinput $offset:$i
     exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time $i\:00:00 -radec $RA $DEC -type $1
-    exec addstar -D CATDIR catdir.test -D CAMERA simtest test.cmf -D CATFORMAT $2
+    exec addstar -D CATDIR catdir.test -D CAMERA gpc1 test.cmf -D CATFORMAT $2
   end
 
Index: trunk/Ohana/src/addstar/test/relphot.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/relphot.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/relphot.dvo	(revision 38553)
@@ -3,4 +3,8 @@
 
 input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
 
 macro test.all
@@ -39,5 +43,5 @@
     mkinput $offset:$i
     exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time $i\:00:00 -radec $RA $DEC -type $1
-    exec addstar -D CATDIR catdir.test -D CAMERA simtest test.cmf -D CATFORMAT $2 -quick-airmass
+    exec addstar -D CATDIR catdir.test -D CAMERA gpc1 test.cmf -D CATFORMAT $2 -quick-airmass
   end
 
Index: trunk/Ohana/src/addstar/test/relphot.flatcorr.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/relphot.flatcorr.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/relphot.flatcorr.dvo	(revision 38553)
@@ -17,4 +17,5 @@
 $TAP_VERBOSE = 1
 input tap.dvo
+input ptolemy.dvo
 
 # set globals
@@ -31,47 +32,7 @@
 # set various global variables
 macro init
-  # generate a fake ptolemy.rc (to make this a contained test)
-  exec rm -f ptolemy.rc
-  output ptolemy.rc
-    echo "\#"
-    echo PHOTCODE_FILE dvo.photcodes
-    echo GSCFILE GSCregions.tbl
-    echo ZERO_PT 25.0
-    echo ADDSTAR_RADIUS 1.0
-    echo CATMODE                 SPLIT
-    echo CATFORMAT               PS1_V5
-    # echo CATFORMAT               PS1_V2 -- must be at least PS1_V3 for ubercaldist to work
-    echo SKY_DEPTH               4
-    echo CAMERA                  gpc1
-    echo CAMERA_CONFIG           dvo.layout
-    echo "input dvo.config"
-  output stdout
-
-  # we need to define a photcode table consistent with the fake construction
-  $zpt_nominal:g = 24.0
-  $zpt_nominal:r = 24.5
-
-  # klam is negative, so klam*(airmass - 1) increases the zero point
-  $klam_nominal:g = -0.15
-  $klam_nominal:r = -0.10
-
-  # generate a fake dvo.photcode
-  exec rm -f dvo.photcodes
-  output dvo.photcodes
-    echo "\# code  name                type    zero  slope offset c1    c2   slope   zero  equiv  sys scale   scale  sys     poor   bad     poor   bad"
-    echo "1     g                    sec   0.000  0.000 0.000     1     3 0.0000     0  1051   0.000 0.000 0.000  0.000   0x0000 0x0000  0x0000 0x0000"
-    echo "2     r                    sec   0.000  0.000 0.000     2     3 0.0000     0  1052   0.000 0.000 0.000  0.000   0x0000 0x0000  0x0000 0x0000"
-    echo "10000 GPC1.g.XY00          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "10001 GPC1.g.XY01          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "10010 GPC1.g.XY10          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "10011 GPC1.g.XY11          dep  $zpt_nominal:g $klam_nominal:g 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "10100 GPC1.r.XY00          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "10101 GPC1.r.XY01          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "10110 GPC1.r.XY10          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "10111 GPC1.r.XY11          dep  $zpt_nominal:r $klam_nominal:r 0.000     -     - 0.0000     0     1   0.015 0.000 1.000  0.000   0x0000 0x0000  0xe0440130 0x1003bc88"
-    echo "2011  2MASS_J              ref   0.000  0.000 0.000     -     - 0.0000     0     6   0.080 0.000 2.000  0.000   0x0000 0x0000  0x0000 0x0000"
-    echo "3001  SYNTH.g              ref   0.000  0.000 0.000     -     - 0.0000     0     1     nan 0.000 2.000  0.600   0x0000 0x0000  0x0000 0x0000"
-    echo "2020  TYCHO_B              ref   0.000  0.000 0.000     -     - 0.0000     0     -   0.000 0.000 0.000  0.000   0x0000 0x0000  0x0000 0x0000"
-  output stdout      
+
+  # generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+  mkptolemy.rc
 
   $RA_CENTER = 10.0
@@ -897,5 +858,5 @@
     mkinput test.in.txt $offset:$i
     exec mkcmf test.in.txt test.cmf -date 2008/1/1 -time $i\:00:00 -radec $RA $DEC -type $1
-    exec addstar -D CATDIR catdir.test -D CAMERA simtest test.cmf -D CATFORMAT $2
+    exec addstar -D CATDIR catdir.test -D CAMERA gpc1 test.cmf -D CATFORMAT $2
   end
 
Index: trunk/Ohana/src/addstar/test/relphot.parallel.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/relphot.parallel.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/relphot.parallel.dvo	(revision 38553)
@@ -5,4 +5,8 @@
 
 input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
 
 # set globals
Index: trunk/Ohana/src/addstar/test/relphot.reject.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/relphot.reject.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/relphot.reject.dvo	(revision 38553)
@@ -15,4 +15,8 @@
 
 input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
 
 # set globals
Index: trunk/Ohana/src/addstar/test/simple.dvo
===================================================================
--- trunk/Ohana/src/addstar/test/simple.dvo	(revision 38543)
+++ trunk/Ohana/src/addstar/test/simple.dvo	(revision 38553)
@@ -2,4 +2,12 @@
 
 input tap.dvo
+input ptolemy.dvo
+
+# generates ptolemy.rc, dvo.photcodes, $zpt_nominal:g,r $klam_nominal:g,r
+mkptolemy.rc
+
+macro test.one
+  test.fields PS1_V5 PS1_V5
+end
 
 macro test.all
@@ -54,6 +62,24 @@
 
   mkinput
-  tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC -type $1 $NO_NOISE
-  tapEXEC addstar -D CATDIR catdir.test -D CAMERA simtest test.cmf -D CATFORMAT $2 -quick-airmass
+  # tapEXEC mkcmf test.in.txt test.cmf -date 2008/1/1 -time 01:00:00 -radec $RA $DEC -type $1 $NO_NOISE
+
+  $options = 
+  $options = $options -type $1
+  $options = $options -radec $RA $DEC
+  $options = $options -mjd 54466.041667
+  $options = $options -date 2008/1/1 -time 01:00:00
+  $options = $options -photcode GPC1.g.XY00
+  $options = $options $NO_NOISE
+
+  # $options = $options -flags
+  # $options = $options -bad-psfqf-frac $DEFECT_FRAC
+  # $options = $options -size $CHIP_DX $CHIP_DY 
+  # $options = $options -crpix {0.5*$CHIP_DX} {0.5*$CHIP_DY} 
+  # $options = $options -airmass $AIRMASS
+  # $options = $options -exptime $EXPTIME
+  # $options = $options -coords 
+
+  tapEXEC mkcmf test.in.txt test.cmf $options
+  tapEXEC addstar -D CATDIR catdir.test -D CAMERA gpc1 test.cmf -D CATFORMAT $2 -quick-airmass
 
   list testfields -copy testfields_$1
Index: trunk/Ohana/src/dvomerge/include/dvomerge.h
===================================================================
--- trunk/Ohana/src/dvomerge/include/dvomerge.h	(revision 38543)
+++ trunk/Ohana/src/dvomerge/include/dvomerge.h	(revision 38553)
@@ -30,17 +30,17 @@
 int    VERIFY_CATALOG_ONLY;
 int    IMAGES_ONLY;
-char   CATDIR[256];
-char   GSCFILE[256];
-char   CATMODE[16];    /* raw, mef, split, mysql */
-char   CATFORMAT[16];  /* internal, elixir, loneos, panstarrs */
-char   ImageCat[256];
+char   CATDIR[DVO_MAX_PATH];
+char   GSCFILE[DVO_MAX_PATH];
+char   ImageCat[DVO_MAX_PATH];
+char   CATMODE[256];    /* raw, mef, split, mysql */
+char   CATFORMAT[256];  /* internal, elixir, loneos, panstarrs */
 float  RADIUS;
 int    SKY_DEPTH;
 int    NTHREADS;
-char  *ALTERNATE_PHOTCODE_FILE;
 int    REPLACE_BY_PHOTCODE;
 int    REPLACE_TYCHO;
 int    FORCE_MERGE;
 int    MAX_CLIENTS;
+char  *ALTERNATE_PHOTCODE_FILE;
 char  *UPDATE_CATFORMAT;
 char  *UPDATE_CATCOMPRESS;
@@ -116,4 +116,5 @@
 void 	   dvomerge_help          PROTO((int argc, char **argv));
 int  	   dvomerge_args 	  PROTO((int *argc, char **argv));
+void       dvomerge_args_free     PROTO((void));
 
 void       dvomerge_client_usage  PROTO((void));
@@ -174,4 +175,6 @@
 off_t 	   dvo_map_image_ID       PROTO((IDmapType *IDmap, off_t oldID));
 int   	   dvo_update_image_IDs   PROTO((IDmapType *IDmap, Catalog *catalog));
+void       dvo_image_map_free     PROTO((IDmapType *IDmap));
+void       dvo_image_map_init     PROTO((IDmapType *IDmap));
 
 // dvorepair prototypes
@@ -212,4 +215,6 @@
 int dmhObjectCheck (dmhObject *history, dmhObjectStats *inStats);
 dmhObject *dmhObjectRead (char *filename);
+dmhObject *dmhObjectAlloc (void);
+void dmhObjectFree (dmhObject *history);
 
 void dmhObjectStatsFree (dmhObjectStats *stats);
@@ -217,6 +222,7 @@
 
 int dmhImageAdd (FITS_DB *db, dmhImage *history, char *dbID);
-dmhImage *dmhImageRead (FITS_DB *db) ;
+dmhImage *dmhImageRead (FITS_DB *db);
 int dmhImageCheck (dmhImage *history, char *dbID);
+void dmhImageFree(dmhImage *history);
 
 char *dmhImageReadID (FITS_DB *db);
Index: trunk/Ohana/src/dvomerge/include/dvoverify.h
===================================================================
--- trunk/Ohana/src/dvomerge/include/dvoverify.h	(revision 38543)
+++ trunk/Ohana/src/dvomerge/include/dvoverify.h	(revision 38553)
@@ -53,4 +53,5 @@
 void AddFailures (char *filename);
 char **GetFailures (int *N);
+void FreeFailures (void);
 
 int LoadImageIDs (char *catdir);
@@ -59,2 +60,4 @@
 int SaveImageIDsSmall(char *filename);
 int LoadImageIDsSmall (char *filename);
+
+void FreeImageIDs (void);
Index: trunk/Ohana/src/dvomerge/src/ConfigInit.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/ConfigInit.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/ConfigInit.c	(revision 38553)
@@ -47,4 +47,5 @@
   VERBOSE = TRUE;
 
+  FreeConfigFile();
   free (config);
   free (file);
Index: trunk/Ohana/src/dvomerge/src/args.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/args.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/args.c	(revision 38553)
@@ -6,4 +6,7 @@
   int N;
 
+  HOSTDIR = NULL;
+  SINGLE_CPT = NULL;
+
   /* extra error messages */
   VERBOSE = FALSE;
@@ -53,4 +56,5 @@
 
   /* use a different photcode file to define mean values */
+  ALTERNATE_PHOTCODE_FILE = NULL;
   if ((N = get_argument (*argc, argv, "-photcode-file"))) {
     remove_argument (N, argc, argv);
@@ -156,4 +160,12 @@
 }
 
+void dvomerge_args_free (void) {
+  FREE (HOSTDIR);
+  FREE (ALTERNATE_PHOTCODE_FILE);
+  FREE (UPDATE_CATFORMAT);
+  FREE (UPDATE_CATCOMPRESS);
+  FREE (SINGLE_CPT);
+}
+
 /*** check for command line options ***/
 int dvomerge_client_args (int *argc, char **argv) {
Index: trunk/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 38553)
@@ -5,4 +5,19 @@
 void SortTgtByTimes (e_time *S, off_t *I, short *C, off_t N);
 off_t getTgtIndex (e_time start, e_time stop, short photcode, off_t *TgtIndex, e_time *TgtTimes, short *TgtCodes, off_t NimagesTgt);
+
+void dvo_image_map_init (IDmapType *IDmap) {
+  // we don't own the IDmap, just the elements
+  IDmap->old = NULL;
+  IDmap->new = NULL;
+  IDmap->notFound = NULL;
+  IDmap->Nmap = 0;
+}
+
+void dvo_image_map_free (IDmapType *IDmap) {
+  // we don't own the IDmap, just the elements
+  FREE (IDmap->old);
+  FREE (IDmap->new);
+  FREE (IDmap->notFound);
+}
 
 // we have two tables; 'tgt' contains some exposures from 'src' : find them and match a map
Index: trunk/Ohana/src/dvomerge/src/dvomerge.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvomerge.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvomerge.c	(revision 38553)
@@ -7,4 +7,6 @@
   ConfigInit (&argc, argv);
   dvomerge_args (&argc, argv);
+
+  if ((argc < 4) || (argc > 6)) dvomerge_usage();
 
   if (argc == 6) {
@@ -38,6 +40,8 @@
     }
   }
-  dvomerge_usage();
-  exit (2); // cannot reach here.
+  dvomerge_args_free ();
+  ohana_memcheck (TRUE);
+  ohana_memdump (TRUE);
+  exit (0);
 }
 
Index: trunk/Ohana/src/dvomerge/src/dvomergeHistory.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvomergeHistory.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvomergeHistory.c	(revision 38553)
@@ -28,4 +28,15 @@
   char *ID = strcreate (dbID);
   return ID;
+}
+
+void dmhImageFree(dmhImage *history) {
+  if (!history) return;
+  
+  int i;
+  for (i = 0; i < history->Nmerge; i++) {
+    FREE (history->IDs[i]);
+  }
+  FREE (history->IDs);
+  FREE (history);
 }
 
@@ -125,4 +136,34 @@
 }
 
+dmhObject *dmhObjectAlloc (void) {
+
+  dmhObject *history = NULL;
+  ALLOCATE (history, dmhObject, 1);
+  history->Nmerge = 0;
+  
+  // ALLOCATE full list
+  ALLOCATE (history->size, off_t,  history->Nmerge);
+  ALLOCATE (history->time, time_t, history->Nmerge);
+  ALLOCATE (history->date, char *, history->Nmerge);
+  return history;
+}
+
+void dmhObjectFree (dmhObject *history) {
+  if (!history) return;
+
+  FREE (history->size);
+  FREE (history->time);
+
+  if (history->date) {
+    int i;
+    for (i = 0; i < history->Nmerge; i++) {
+      FREE (history->date[i]);
+    }
+  }
+  FREE (history->date);
+  FREE (history);
+  return;
+}
+
 // read the array of merged history information from this file's header
 dmhObject *dmhObjectRead (char *filename) {
@@ -133,12 +174,5 @@
   if (stat_result) {
     if (errno == ENOENT) {
-      dmhObject *history = NULL;
-      ALLOCATE (history, dmhObject, 1);
-      history->Nmerge = 0;
-    
-      // ALLOCATE full list
-      ALLOCATE (history->size, off_t,  history->Nmerge);
-      ALLOCATE (history->time, time_t, history->Nmerge);
-      ALLOCATE (history->date, char *, history->Nmerge);
+      dmhObject *history = dmhObjectAlloc();
       return history;
     }
@@ -162,6 +196,5 @@
   fclose (fout);
 
-  dmhObject *history = NULL;
-  ALLOCATE (history, dmhObject, 1);
+  dmhObject *history = dmhObjectAlloc();
 
   int status = gfits_scan (&outheader, "NMERGE", "%d", 1, &history->Nmerge);      
@@ -171,7 +204,7 @@
 
   // ALLOCATE full list
-  ALLOCATE (history->size, off_t,  history->Nmerge);
-  ALLOCATE (history->time, time_t, history->Nmerge);
-  ALLOCATE (history->date, char *, history->Nmerge);
+  REALLOCATE (history->size, off_t,  history->Nmerge);
+  REALLOCATE (history->time, time_t, history->Nmerge);
+  REALLOCATE (history->date, char *, history->Nmerge);
 
   int i;
@@ -199,4 +232,5 @@
     history->time[i] = ohana_date_to_sec (date);
   }
+  gfits_free_header (&outheader);
   return history;
 }
@@ -239,5 +273,5 @@
   history->size[last] = inStats->size;
   history->time[last] = inStats->time;
-  history->date[last] = inStats->date;
+  history->date[last] = strcreate (inStats->date);
 
   char name[16];
@@ -280,5 +314,5 @@
   int i;
   for (i = 0; i < N; i++) {
-    if (outstat[i].history)  { free (outstat[i].history); }
+    if (outstat[i].history)  { dmhObjectFree (outstat[i].history); }
     if (outstat[i].filename) { free (outstat[i].filename); }
   }
Index: trunk/Ohana/src/dvomerge/src/dvomergeImageIDs.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvomergeImageIDs.c	(revision 38553)
@@ -64,4 +64,9 @@
     dvo_image_match_dbs(IDmap, &outDB, &inDB);
     dvo_image_unlock (&outDB); // unlock output
+
+    gfits_db_free (&inDB);
+    gfits_db_free (&outDB);
+    dmhImageFree (history);
+    FREE (indbID);
     return TRUE;
   }
@@ -80,4 +85,10 @@
   SetProtect (FALSE);
   dvo_image_unlock (&outDB); // unlock output
+
+  gfits_db_free (&inDB);
+  gfits_db_free (&outDB);
+
+  dmhImageFree (history);
+  FREE (indbID);
 
   return TRUE;
@@ -136,4 +147,7 @@
   dvo_image_match_dbs(IDmap, &outDB, &inDB);
 
+  gfits_db_free (&inDB);
+  gfits_db_free (&outDB);
+
   return TRUE;
 }
Index: trunk/Ohana/src/dvomerge/src/dvomergeUpdate.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 38553)
@@ -8,10 +8,10 @@
   char filename[256], *input, *output;
   IDmapType IDmap;
-  PhotCodeData *inputPhotcodes;
-  PhotCodeData *outputPhotcodes;
   int *secfiltMap = NULL;
   int NsecfiltInput, NsecfiltOutput;
 
   INITTIME;
+
+  dvo_image_map_init (&IDmap);
 
   CONTINUE = FALSE;
@@ -34,4 +34,7 @@
     exit (1);
   }
+
+  PhotCodeData *inputPhotcodes  = NULL;
+  PhotCodeData *outputPhotcodes = NULL;
 
   SetPhotcodeTable(NULL);
@@ -120,4 +123,15 @@
     exit (1);
   }
+  FREE (skyfile);
+
+  SkyTableFree (insky);
+  SkyTableFree (outsky);
+  SkyListFree (inlist);
+
+  FREE (secfiltMap);
+  dvo_image_map_free (&IDmap);
+  if (outputPhotcodes != inputPhotcodes) { FreePhotcodeData (outputPhotcodes); }
+  FreePhotcodeData (inputPhotcodes);
+  FreePhotcodeTable ();
 
   if (!status) {
@@ -127,4 +141,4 @@
 
   MARKTIME ("SUCCESS: elapsed time %9.4f sec\n", dtime);
-  exit (0);
+  return TRUE;
 }
Index: trunk/Ohana/src/dvomerge/src/dvoverify.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvoverify.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvoverify.c	(revision 38553)
@@ -24,5 +24,5 @@
 
     // check the photcode table
-    sprintf (filename, "%s/Photcodes.dat", CATDIR);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/Photcodes.dat", CATDIR) < DVO_MAX_PATH, "overflow");
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -34,7 +34,8 @@
       Nbad ++;
     }
+    free (skyfile);
 
     // check the image table
-    sprintf (filename, "%s/Images.dat", CATDIR);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/Images.dat", CATDIR) < DVO_MAX_PATH, "overflow");
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -71,4 +72,12 @@
     fprintf (stderr, "NOTE: %d files are not sorted\n", NNotSorted);
   }
+
+  FreeImageIDs ();
+  FreeFailures ();
+  SkyTableFree (sky);
+  SkyListFree (skylist);
+
+  ohana_memcheck (TRUE);
+  ohana_memdump (TRUE);
   exit (0);
 }
Index: trunk/Ohana/src/dvomerge/src/dvoverify_args.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvoverify_args.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvoverify_args.c	(revision 38553)
@@ -45,5 +45,12 @@
     }
 
+    CHECK_IMAGE_ID = FALSE;
+
     int isGood = dvoverify_single (filename);
+    free (filename);
+
+    ohana_memcheck (TRUE);
+    ohana_memdump (TRUE);
+
     if (!isGood) exit (1);
     exit (0);
Index: trunk/Ohana/src/dvomerge/src/dvoverify_catalogs.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvoverify_catalogs.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvoverify_catalogs.c	(revision 38553)
@@ -27,5 +27,5 @@
     if (!HostTableTestHost(skylist[0].regions[i], HOST_ID)) continue;
 
-    sprintf (filename, "%s/%s.cpt", mycatdir, skylist[0].regions[i][0].name);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/%s.cpt", mycatdir, skylist[0].regions[i][0].name) < DVO_MAX_PATH, "overflow");
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -34,5 +34,5 @@
     }
 
-    sprintf (filename, "%s/%s.cps", mycatdir, skylist[0].regions[i][0].name);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/%s.cps", mycatdir, skylist[0].regions[i][0].name) < DVO_MAX_PATH, "overflow");
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -40,5 +40,5 @@
     }
 
-    sprintf (filename, "%s/%s.cpm", mycatdir, skylist[0].regions[i][0].name);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/%s.cpm", mycatdir, skylist[0].regions[i][0].name) < DVO_MAX_PATH, "overflow");
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -47,5 +47,5 @@
     }
 
-    sprintf (filename, "%s/%s.cpx", mycatdir, skylist[0].regions[i][0].name);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/%s.cpx", mycatdir, skylist[0].regions[i][0].name) < DVO_MAX_PATH, "overflow");
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -54,5 +54,5 @@
     }
 
-    sprintf (filename, "%s/%s.cpy", mycatdir, skylist[0].regions[i][0].name);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/%s.cpy", mycatdir, skylist[0].regions[i][0].name) < DVO_MAX_PATH, "overflow");
     if (!VerifyTableFile (filename)) {
       Nbad ++;
@@ -61,5 +61,5 @@
     }
 
-    sprintf (filename, "%s/%s.cpt", mycatdir, skylist[0].regions[i][0].name);
+    myAssert (snprintf (filename, DVO_MAX_PATH, "%s/%s.cpt", mycatdir, skylist[0].regions[i][0].name) < DVO_MAX_PATH, "overflow");
     if (!skipIndexCheck) {
       if (!CheckCatalogIndexes(filename, skylist[0].regions[i])){
Index: trunk/Ohana/src/dvomerge/src/dvoverify_utils.c
===================================================================
--- trunk/Ohana/src/dvomerge/src/dvoverify_utils.c	(revision 38543)
+++ trunk/Ohana/src/dvomerge/src/dvoverify_utils.c	(revision 38553)
@@ -5,6 +5,16 @@
 static char **failures = NULL;
 
-void InitFailures () {
-  ALLOCATE (failures, char *, NFAILURES);
+void InitFailures (void) {
+  ALLOCATE_ZERO (failures, char *, NFAILURES);
+}
+
+void FreeFailures (void) {
+  int i;
+
+  if (!failures) return;
+  for (i = 0; i < NFAILURES; i++) {
+    FREE (failures[i]);
+  }
+  FREE (failures);
 }
 
@@ -128,5 +138,6 @@
 	fprintf (stderr, "unable to read header for %s, extension %d (or file has excess bytes)\n", filename, Next);
       }
-      fclose(file);
+      fclose (file);
+      gfits_free_header (&header);
       return (FALSE);
     }
@@ -175,5 +186,5 @@
 
   // set the parameters which guide catalog open/load/create
-    dvo_catalog_init (&catalog, TRUE);
+  dvo_catalog_init (&catalog, TRUE);
   catalog.filename  = filename;
   catalog.catflags  = DVO_LOAD_AVERAGE | DVO_LOAD_MEASURE | DVO_LOAD_LENSING | DVO_LOAD_LENSOBJ;
@@ -183,4 +194,5 @@
   if (!dvo_catalog_open (&catalog, region, VERBOSE, "r")) {
     fprintf (stderr, "ERROR: failure to open catalog file %s\n", catalog.filename);
+    dvo_catalog_free (&catalog);
     return FALSE;
   }
@@ -463,5 +475,5 @@
 
   char ImageCat[DVO_MAX_PATH];
-  snprintf (ImageCat, DVO_MAX_PATH, "%s/Images.dat", catdir);
+  myAssert (snprintf (ImageCat, DVO_MAX_PATH, "%s/Images.dat", catdir) < DVO_MAX_PATH, "overflow");
 
   // load the iage database table
@@ -506,11 +518,15 @@
     IDlist[id] = i;
   }
-
-  // free image table here?
+  
   // (in the future, I'll have to do the image table read in segments
   // it is just getting to be too large...)
   dvo_image_unlock (&inDB); // unlock input
+  gfits_db_free (&inDB);
 
   return TRUE;
+}
+
+void FreeImageIDs (void) {
+  FREE (IDlist);
 }
 
Index: trunk/Ohana/src/imregister/photreg/output.c
===================================================================
--- trunk/Ohana/src/imregister/photreg/output.c	(revision 38543)
+++ trunk/Ohana/src/imregister/photreg/output.c	(revision 38553)
@@ -96,4 +96,5 @@
     extname = strcreate ("SUMMARY_ZPTS");
   }
+
   gfits_create_table_header (&theader, "TABLE", extname);
     
Index: trunk/Ohana/src/kapa2/src/bDrawIt.c
===================================================================
--- trunk/Ohana/src/kapa2/src/bDrawIt.c	(revision 38543)
+++ trunk/Ohana/src/kapa2/src/bDrawIt.c	(revision 38553)
@@ -3,5 +3,5 @@
 bDrawBuffer *bDrawIt (png_color *palette, int Npalette, int Nbyte) {
 
-  int i, Nsection;
+  int i, j, Nsection;
   bDrawBuffer *buffer;
   bDrawColor black;
@@ -23,6 +23,6 @@
       section = GetSectionByNumber (i);
       bDrawImage (buffer, section->image, graphic);
-      for (i = 0; section->image && (i < NOVERLAYS); i++) {
-	if (section->image->overlay[i].active) bDrawOverlay (buffer, section->image, i);
+      for (j = 0; section->image && (j < NOVERLAYS); j++) {
+	if (section->image->overlay[j].active) bDrawOverlay (buffer, section->image, j);
       }
       bDrawGraph (buffer, section->graph);
Index: trunk/Ohana/src/libautocode/Makefile.Targets
===================================================================
--- trunk/Ohana/src/libautocode/Makefile.Targets	(revision 38543)
+++ trunk/Ohana/src/libautocode/Makefile.Targets	(revision 38553)
@@ -55,6 +55,6 @@
 $(ASRC)/starpar-ps1-v5.$(ARCH).o \
 $(ASRC)/starpar-ps1-sim.$(ARCH).o \
-$(ASRC)/galshape.$(ARCH).o \
-$(ASRC)/galshape-ps1-v5.$(ARCH).o \
+$(ASRC)/galphot.$(ARCH).o \
+$(ASRC)/galphot-ps1-v5.$(ARCH).o \
 $(ASRC)/missing.$(ARCH).o \
 $(ASRC)/photcode.$(ARCH).o \
@@ -167,6 +167,6 @@
 $(AINC)/starpar-ps1-v5.h \
 $(AINC)/starpar-ps1-sim.h \
-$(AINC)/galshape.h \
-$(AINC)/galshape-ps1-v5.h \
+$(AINC)/galphot.h \
+$(AINC)/galphot-ps1-v5.h \
 $(AINC)/missing.h \
 $(AINC)/photcode.h \
Index: trunk/Ohana/src/libautocode/def/galphot-ps1-v5.d
===================================================================
--- trunk/Ohana/src/libautocode/def/galphot-ps1-v5.d	(revision 38553)
+++ trunk/Ohana/src/libautocode/def/galphot-ps1-v5.d	(revision 38553)
@@ -0,0 +1,31 @@
+STRUCT       GalPhot_PS1_V5
+EXTNAME      DVO_GALPHOT_PS1_V5
+TYPE         BINTABLE
+SIZE         80
+DESCRIPTION  DVO Galaxy Shape Table 
+
+FIELD Xfit,         XFIT,    	    float,          centroid for fit
+FIELD Yfit,         YFIT,    	    float,          centroid for fit
+FIELD mag,          MAG,    	    float,          galaxy magnitude
+FIELD magErr,       MAG_ERR,	    float,          galaxy magnitude error
+FIELD majorAxis,    MAJOR_AXIS,     float,          major axis size
+FIELD minorAxis,    MINOR_AXIS,     float,          minor axis size
+FIELD majorAxisErr, MAJOR_AXIS_ERR, float,          major axis size error
+FIELD minorAxisErr, MINOR_AXIS_ERR, float,          minor axis size error
+FIELD theta,        THETA,          float,          angle
+FIELD thetaErr,     THETA_ERR,      float,          angle error
+FIELD index,        INDEX,          float,          sersic index (if relevant)
+FIELD chisq,        CHISQ,   	    float,          fit chisq
+		    
+FIELD Npix,         NPIX,           float,          fitted pixels
+
+FIELD objID,        OBJ_ID,         unsigned int,   unique ID for object in table
+FIELD catID,        CAT_ID,         unsigned int,   unique ID for table in which object was first realized
+FIELD detID,        DET_ID,         unsigned int,   detection ID
+FIELD imageID,      IMAGE_ID,       unsigned int,   reference to DVO image ID
+
+FIELD averef,       AVEREF,         unsigned int,   reference to average table
+FIELD dummy,        DUMMY,          unsigned int,   filler
+
+FIELD photcode,     PHOTCODE,       short
+FIELD modelType,    MODEL_TYPE,     short,          mean lensing smear object E2
Index: trunk/Ohana/src/libautocode/def/galphot.d
===================================================================
--- trunk/Ohana/src/libautocode/def/galphot.d	(revision 38553)
+++ trunk/Ohana/src/libautocode/def/galphot.d	(revision 38553)
@@ -0,0 +1,31 @@
+STRUCT       GalPhot
+EXTNAME      DVO_GALPHOT
+TYPE         BINTABLE
+SIZE         80
+DESCRIPTION  DVO Galaxy Shape Table 
+
+FIELD Xfit,         XFIT,    	    float,          centroid for fit
+FIELD Yfit,         YFIT,    	    float,          centroid for fit
+FIELD mag,          MAG,    	    float,          galaxy magnitude
+FIELD magErr,       MAG_ERR,	    float,          galaxy magnitude error
+FIELD majorAxis,    MAJOR_AXIS,     float,          major axis size
+FIELD minorAxis,    MINOR_AXIS,     float,          minor axis size
+FIELD majorAxisErr, MAJOR_AXIS_ERR, float,          major axis size error
+FIELD minorAxisErr, MINOR_AXIS_ERR, float,          minor axis size error
+FIELD theta,        THETA,          float,          angle
+FIELD thetaErr,     THETA_ERR,      float,          angle error
+FIELD index,        INDEX,          float,          sersic index (if relevant)
+FIELD chisq,        CHISQ,   	    float,          fit chisq
+		    
+FIELD Npix,         NPIX,           float,          fitted pixels
+
+FIELD objID,        OBJ_ID,         unsigned int,   unique ID for object in table
+FIELD catID,        CAT_ID,         unsigned int,   unique ID for table in which object was first realized
+FIELD detID,        DET_ID,         unsigned int,   detection ID
+FIELD imageID,      IMAGE_ID,       unsigned int,   reference to DVO image ID
+
+FIELD averef,       AVEREF,         unsigned int,   reference to average table
+FIELD dummy,        DUMMY,          unsigned int,   filler
+
+FIELD photcode,     PHOTCODE,       short
+FIELD modelType,    MODEL_TYPE,     short,          mean lensing smear object E2
Index: trunk/Ohana/src/libautocode/def/galshape-ps1-v5.d
===================================================================
--- trunk/Ohana/src/libautocode/def/galshape-ps1-v5.d	(revision 38543)
+++ 	(revision )
@@ -1,33 +1,0 @@
-STRUCT       GalPhot_PS1_V5
-EXTNAME      DVO_GALPHOT_PS1_V5
-TYPE         BINTABLE
-SIZE         72
-DESCRIPTION  DVO Galaxy Shape Table 
-
-FIELD Xfit,         XFIT,    	    float,          centroid for fit
-FIELD Yfit,         YFIT,    	    float,          centroid for fit
-
-FIELD mag,          MAG,    	    float,          galaxy magnitude
-FIELD magErr,       MAG_ERR,	    float,          galaxy magnitude error
-
-FIELD majorAxis,    MAJOR_AXIS,     float,          major axis size
-FIELD minorAxis,    MINOR_AXIS,     float,          minor axis size
-
-FIELD majorAxisErr, MAJOR_AXIS_ERR, float,          major axis size error
-FIELD minorAxisErr, MINOR_AXIS_ERR, float,          minor axis size error
-
-FIELD theta,        THETA,          float,          angle
-FIELD theta_err,    THETA_ERR,      float,          angle error
-
-FIELD index,        INDEX,          float,          sersic index (if relevant)
-FIELD chisq,        CHISQ,   	    float,          fit chisq
-		    
-FIELD Npix,         NPIX,           float,          fitted pixels
-
-FIELD objID,        OBJ_ID,         unsigned int,   unique ID for object in table
-FIELD catID,        CAT_ID,         unsigned int,   unique ID for table in which object was first realized
-FIELD detID,        DET_ID,         unsigned int,   detection ID
-FIELD imageID,      IMAGE_ID,       unsigned int,   reference to DVO image ID
-
-FIELD photcode,     PHOTCODE,       short
-FIELD modelType,    MODEL_TYPE,     short,          mean lensing smear object E2
Index: trunk/Ohana/src/libautocode/def/galshape.d
===================================================================
--- trunk/Ohana/src/libautocode/def/galshape.d	(revision 38543)
+++ 	(revision )
@@ -1,28 +1,0 @@
-STRUCT       GalPhot
-EXTNAME      DVO_GALPHOT
-TYPE         BINTABLE
-SIZE         72
-DESCRIPTION  DVO Galaxy Shape Table 
-
-FIELD Xfit,         XFIT,    	    float,          centroid for fit
-FIELD Yfit,         YFIT,    	    float,          centroid for fit
-FIELD mag,          MAG,    	    float,          galaxy magnitude
-FIELD magErr,       MAG_ERR,	    float,          galaxy magnitude error
-FIELD majorAxis,    MAJOR_AXIS,     float,          major axis size
-FIELD minorAxis,    MINOR_AXIS,     float,          minor axis size
-FIELD majorAxisErr, MAJOR_AXIS_ERR, float,          major axis size error
-FIELD minorAxisErr, MINOR_AXIS_ERR, float,          minor axis size error
-FIELD theta,        THETA,          float,          angle
-FIELD theta_err,    THETA_ERR,      float,          angle error
-FIELD index,        INDEX,          float,          sersic index (if relevant)
-FIELD chisq,        CHISQ,   	    float,          fit chisq
-		    
-FIELD Npix,         NPIX,           float,          fitted pixels
-
-FIELD objID,        OBJ_ID,         unsigned int,   unique ID for object in table
-FIELD catID,        CAT_ID,         unsigned int,   unique ID for table in which object was first realized
-FIELD detID,        DET_ID,         unsigned int,   detection ID
-FIELD imageID,      IMAGE_ID,       unsigned int,   reference to DVO image ID
-
-FIELD photcode,     PHOTCODE,       short
-FIELD modelType,    MODEL_TYPE,     short,          mean lensing smear object E2
Index: trunk/Ohana/src/libdvo/include/cmf-ps1-v5-r2-lensing.h
===================================================================
--- trunk/Ohana/src/libdvo/include/cmf-ps1-v5-r2-lensing.h	(revision 38543)
+++ trunk/Ohana/src/libdvo/include/cmf-ps1-v5-r2-lensing.h	(revision 38553)
@@ -95,4 +95,6 @@
 
 CMF_PS1_V5_R2_Lensing *gfits_table_get_CMF_PS1_V5_R2_Lensing (FTable *table, off_t *Ndata, char *swapped);
+CMF_PS1_V5_R2_Lensing *gfits_table_get_CMF_PS1_V5_R2x_Lensing (FTable *ftable, off_t *Ndata, char *swapped);
+
 int      gfits_table_set_CMF_PS1_V5_R2_Lensing (FTable *ftable, CMF_PS1_V5_R2_Lensing *data, off_t Ndata);
 int      gfits_table_mkheader_CMF_PS1_V5_R2_Lensing (Header *header);
Index: trunk/Ohana/src/libdvo/include/convert.h
===================================================================
--- trunk/Ohana/src/libdvo/include/convert.h	(revision 38543)
+++ trunk/Ohana/src/libdvo/include/convert.h	(revision 38553)
@@ -13,6 +13,6 @@
 int           hh_hms                PROTO((double hh, int *hr, int *mn, double *sc));
 int           dd_dms                PROTO((double dd, int *dg, int *mn, double *sc));
-int           hms_format            PROTO((char *line, double value));
-int           dms_format            PROTO((char *line, double value));
+int           hms_format            PROTO((char *line, int length, double value));
+int           dms_format            PROTO((char *line, int length, double value));
 int           hh_hm                 PROTO((double hh, int *hr, double *mn));
 int           day_to_sec            PROTO((char *string, time_t *second));
Index: trunk/Ohana/src/libdvo/include/dvo.h
===================================================================
--- trunk/Ohana/src/libdvo/include/dvo.h	(revision 38543)
+++ trunk/Ohana/src/libdvo/include/dvo.h	(revision 38553)
@@ -259,4 +259,5 @@
 typedef struct {
   off_t Nregions;
+  off_t Nalloc;
   char **filename;
   SkyRegion *regions;
@@ -920,4 +921,6 @@
 PhotCodeData *GetPhotcodeTable (void);
 void SetPhotcodeTable (PhotCodeData *);
+void FreePhotcodeData (PhotCodeData *myPhotcodes);
+void FreePhotcodeTable (void);
 
 int *GetSecFiltMap(PhotCodeData *ouput, PhotCodeData* input);
Index: trunk/Ohana/src/libdvo/src/HostTable.c
===================================================================
--- trunk/Ohana/src/libdvo/src/HostTable.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/HostTable.c	(revision 38553)
@@ -62,6 +62,7 @@
   char *filename = NULL;
 
-  ALLOCATE (filename, char, strlen(catdir) + strlen(rootname) + 2); // one slash and one EOL
-  sprintf (filename, "%s/%s", catdir, rootname);
+  int Nchar = strlen(catdir) + strlen(rootname) + 16;
+  ALLOCATE (filename, char, Nchar); // one slash and one EOL
+  snprintf (filename, Nchar, "%s/%s", catdir, rootname);
 
   FILE *f = fopen (filename, "r");
Index: trunk/Ohana/src/libdvo/src/LoadImages.c
===================================================================
--- trunk/Ohana/src/libdvo/src/LoadImages.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/LoadImages.c	(revision 38553)
@@ -23,5 +23,5 @@
 
   catdir = dvo_get_catdir ();
-  sprintf (filename, "%s/Images.dat", catdir);
+  snprintf (filename, 256, "%s/Images.dat", catdir);
 
   if (lastFilename) {
Index: trunk/Ohana/src/libdvo/src/LoadPhotcodesFITS.c
===================================================================
--- trunk/Ohana/src/libdvo/src/LoadPhotcodesFITS.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/LoadPhotcodesFITS.c	(revision 38553)
@@ -51,5 +51,4 @@
     }									\
     photcode = PhotCode_##FORMAT##_To_Internal (photcode_input, Ncode); \
-    free (photcode_input);						\
   }
 
@@ -65,4 +64,6 @@
   CONVERT_FORMAT("DVO_PHOTCODE_PS1_V4",    PS1_V4);
   CONVERT_FORMAT("DVO_PHOTCODE_PS1_V5",    PS1_V5);
+
+  gfits_db_free (&db);
 
   table = GetPhotcodeTable ();
Index: trunk/Ohana/src/libdvo/src/RegionHostTable.c
===================================================================
--- trunk/Ohana/src/libdvo/src/RegionHostTable.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/RegionHostTable.c	(revision 38553)
@@ -64,6 +64,8 @@
   char *filename = NULL;
 
-  ALLOCATE (filename, char, strlen(catdir) + strlen(rootname) + 2); // one slash and one EOL
-  sprintf (filename, "%s/%s", catdir, rootname);
+  int Nchar = strlen(catdir) + strlen(rootname) + 16;
+
+  ALLOCATE (filename, char, Nchar); // one slash and one EOL
+  snprintf (filename, Nchar, "%s/%s", catdir, rootname);
 
   FILE *f = fopen (filename, "r");
Index: trunk/Ohana/src/libdvo/src/SavePhotcodesFITS.c
===================================================================
--- trunk/Ohana/src/libdvo/src/SavePhotcodesFITS.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/SavePhotcodesFITS.c	(revision 38553)
@@ -37,4 +37,5 @@
   if (!gfits_db_save (&db)) return (FALSE);
   if (!gfits_db_close (&db)) return (FALSE);
+  if (!gfits_db_free (&db)) return (FALSE);
 
   free (photcode_output);
Index: trunk/Ohana/src/libdvo/src/cmf-ps1-v5-r2-lensing.c
===================================================================
--- trunk/Ohana/src/libdvo/src/cmf-ps1-v5-r2-lensing.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/cmf-ps1-v5-r2-lensing.c	(revision 38553)
@@ -480,2 +480,54 @@
 }
 
+/** ****/
+int fix_lensing (char *data, int Nrows) {
+
+  off_t i;
+
+  int Nbytes = sizeof (CMF_PS1_V5_R2_Lensing);
+
+  char buffer[64];
+
+  char *ptr = data;
+  for (i = 0; i < Nrows; i++, ptr += Nbytes) {
+    // bytes 184 - 224 (exclusive) are now at 288 - 328 (exclusive)
+    memcpy (buffer, &ptr[288], 40);
+    memmove (&ptr[224], &ptr[184], 104);
+    memcpy (&ptr[184], buffer, 40);
+  }
+  return TRUE;
+}
+
+/**************************************/
+CMF_PS1_V5_R2_Lensing *gfits_table_get_CMF_PS1_V5_R2x_Lensing (FTable *ftable, off_t *Ndata, char *swapped) {
+
+  int Ncols;
+  CMF_PS1_V5_R2_Lensing *data;
+
+  Ncols = ftable[0].header[0].Naxis[0];
+  if (Ncols != ST_SIZE) {
+    fprintf (stderr, "ERROR: mis-match in table size: width is %d but should be %d bytes\n", Ncols, ST_SIZE);
+    return NULL;
+  }
+
+  *Ndata = ftable[0].header[0].Naxis[1];
+
+  fix_lensing (ftable[0].buffer, *Ndata);
+  data = (CMF_PS1_V5_R2_Lensing *) ftable[0].buffer;
+  if ((swapped == NULL) || (*swapped == FALSE)) {
+    if (!gfits_convert_CMF_PS1_V5_R2_Lensing ((unsigned char *) data, sizeof (CMF_PS1_V5_R2_Lensing), *Ndata, TRUE)) {
+      return NULL;
+    }
+    off_t i;
+    for (i = 0; i < *Ndata; i++) {
+      data[i].detID   += 0x80000000;
+      data[i].flags   += 0x80000000;
+      data[i].flags2  += 0x80000000;
+      data[i].nFrames += 0x8000;
+    }
+    // gfits_table_scale_data (ftable);
+    if (swapped != NULL) *swapped = TRUE;
+  }
+  return (data);
+}
+
Index: trunk/Ohana/src/libdvo/src/convert.c
===================================================================
--- trunk/Ohana/src/libdvo/src/convert.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/convert.c	(revision 38553)
@@ -46,5 +46,5 @@
 }
  
-int hms_format (char *line, double value) {
+int hms_format (char *line, int length, double value) {
 
   int hr, mn;
@@ -54,10 +54,10 @@
   hr = (int) value;
   if (isnan (value))
-    sprintf (line, "xx:xx:xx.xx");
+    snprintf (line, length, "xx:xx:xx.xx");
   else {
     if (value < 0) {
-      sprintf (line, "-%02d:%02d:%05.2f", abs(hr), mn, sc);
+      snprintf (line, length, "-%02d:%02d:%05.2f", abs(hr), mn, sc);
     } else {
-      sprintf (line, "+%02d:%02d:%05.2f", hr, mn, sc);
+      snprintf (line, length, "+%02d:%02d:%05.2f", hr, mn, sc);
     }
   }      
@@ -65,5 +65,5 @@
 }
 
-int dms_format (char *line, double value) {
+int dms_format (char *line, int length, double value) {
 
   int dg, mn;
@@ -72,7 +72,7 @@
   dd_dms (value, &dg, &mn, &sc);
   if (value < 0) {
-    sprintf (line, "-%02d:%02d:%05.2f", abs(dg), mn, sc);
+    snprintf (line, length, "-%02d:%02d:%05.2f", abs(dg), mn, sc);
   } else {
-    sprintf (line, "+%02d:%02d:%05.2f", dg, mn, sc);
+    snprintf (line, length, "+%02d:%02d:%05.2f", dg, mn, sc);
   }
   return (TRUE);
@@ -134,5 +134,5 @@
   ALLOCATE (line, char, 64);
   gmt   = gmtime (&second);
-  sprintf (line, "%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+  snprintf (line, 64, "%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
   return (line);
 }
@@ -148,23 +148,23 @@
   switch (gmt[0].tm_wday) {
     case 0:
-      sprintf (line, "Sun@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      snprintf (line, 64, "Sun@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
       break;
     case 1:
-      sprintf (line, "Mon@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      snprintf (line, 64, "Mon@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
       break;
     case 2:
-      sprintf (line, "Tue@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      snprintf (line, 64, "Tue@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
       break;
     case 3:
-      sprintf (line, "Wed@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      snprintf (line, 64, "Wed@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
       break;
     case 4:
-      sprintf (line, "Thu@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      snprintf (line, 64, "Thu@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
       break;
     case 5:
-      sprintf (line, "Fri@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      snprintf (line, 64, "Fri@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
       break;
     case 6:
-      sprintf (line, "Sat@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+      snprintf (line, 64, "Sat@%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
       break;
   }
@@ -195,5 +195,5 @@
   hh_hm (deg, &hr, &mn);
 
-  sprintf (line, "%03d:%04.1f", abs(hr), mn);
+  snprintf (line, 16, "%03d:%04.1f", abs(hr), mn);
   return (line);
 }
@@ -209,5 +209,5 @@
   hh_hm (deg/15.0, &hr, &mn);
 
-  sprintf (line, "%02d:%04.1f", abs(hr), mn);
+  snprintf (line, 16, "%02d:%04.1f", abs(hr), mn);
   return (line);
 }
@@ -224,7 +224,7 @@
 
   if (deg < 0) {
-    sprintf (line, "-%02d:%04.1f", abs(hr), mn);
+    snprintf (line, 16, "-%02d:%04.1f", abs(hr), mn);
   } else {
-    sprintf (line, "+%02d:%04.1f", hr, mn);
+    snprintf (line, 16, "+%02d:%04.1f", hr, mn);
   }      
   return (line);
Index: trunk/Ohana/src/libdvo/src/coordops.c
===================================================================
--- trunk/Ohana/src/libdvo/src/coordops.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/coordops.c	(revision 38553)
@@ -740,5 +740,5 @@
 	for (i = 0; i < 14; i++) {
 	  char name[64];
-	  sprintf (name, "PV2_%d", i);
+	  snprintf (name, 64, "PV2_%d", i);
 	  if (i < 7) {
 	    found = gfits_scan (header, name, "%f", 1, &coords[0].polyterms[0][i]);
@@ -834,5 +834,5 @@
     if (!strncmp (coords[0].ctype, "SLAT", 4)) strcpy (csys, "SLON");
     if (!strcmp (csys, "NONE")) return (FALSE);
-    sprintf (ctype, "%s-%s", csys, &coords[0].ctype[5]);
+    snprintf (ctype, 16, "%s-%s", csys, &coords[0].ctype[5]);
     gfits_modify (header, "CTYPE1",   "%s",  1, ctype);
   }    
Index: trunk/Ohana/src/libdvo/src/dvo_catalog.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_catalog.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_catalog.c	(revision 38553)
@@ -85,28 +85,27 @@
 
 // we can return a static string here unless we run multiple outputs threads at once
-static char compress_string[16];
 char *dvo_catalog_compress_string (DVOCatCompress catcompress) {
-
+  char *compress_string = NULL;
   switch (catcompress) {
     case DVO_COMPRESS_NONE:
-      strcpy (compress_string, "NONE");
+      compress_string = strcreate("NONE");
       break;
     case DVO_COMPRESS_AUTO:
-      strcpy (compress_string, "AUTO");
+      compress_string = strcreate("AUTO");
       break;
     case DVO_COMPRESS_GZIP_1:
-      strcpy (compress_string, "GZIP_1");
+      compress_string = strcreate("GZIP_1");
       break;
     case DVO_COMPRESS_GZIP_2:
-      strcpy (compress_string, "GZIP_2");
+      compress_string = strcreate("GZIP_2");
       break;
     case DVO_COMPRESS_NONE_1:
-      strcpy (compress_string, "NONE_1");
+      compress_string = strcreate("NONE_1");
       break;
     case DVO_COMPRESS_NONE_2:
-      strcpy (compress_string, "NONE_2");
+      compress_string = strcreate("NONE_2");
       break;
     case DVO_COMPRESS_RICE_1:
-      strcpy (compress_string, "RICE_1");
+      compress_string = strcreate("RICE_1");
       break;
     default:
@@ -532,5 +531,5 @@
   galphot->minorAxisErr = NAN;
   galphot->theta        = NAN;
-  galphot->theta_err    = NAN;
+  galphot->thetaErr     = NAN;
   galphot->index        = NAN;
   galphot->chisq        = NAN;
@@ -541,4 +540,5 @@
   galphot->catID   = -1;
   galphot->imageID = -1;
+  galphot->averef  = 0;
 
   galphot->photcode = 0;
@@ -1157,9 +1157,11 @@
     return FALSE;
   }
-      
+  
+  int outStatus = TRUE;
   status = unlink (tmpfilename);
   if (status) {
+    perror ("unlink: ");
     fprintf (stderr, "failed to unlink catalog %s~\n", catalog->filename);
-    return FALSE;
+    outStatus = FALSE;
   }
       
@@ -1167,40 +1169,40 @@
     if (catalog[0].measure_catalog != NULL) {
       if (!dvo_catalog_unlink_backup (catalog[0].measure_catalog, FALSE)) {
-	return FALSE;
+	outStatus = FALSE;
       }
     }
     if (catalog[0].missing_catalog != NULL) {
       if (!dvo_catalog_unlink_backup (catalog[0].missing_catalog, FALSE)) {
-	return FALSE;
+	outStatus = FALSE;
       }
     }
     if (catalog[0].secfilt_catalog != NULL) {
       if (!dvo_catalog_unlink_backup (catalog[0].secfilt_catalog, FALSE)) {
-	return FALSE;
+	outStatus = FALSE;
       }
     }
     if ((catalog[0].lensing_catalog != NULL) && (catalog[0].Nlensing_disk > 0)) {
       if (!dvo_catalog_unlink_backup (catalog[0].lensing_catalog, FALSE)) {
-	return FALSE;
+	outStatus = FALSE;
       }
     }
     if ((catalog[0].lensobj_catalog != NULL) && (catalog[0].Nlensobj_disk > 0)) {
       if (!dvo_catalog_unlink_backup (catalog[0].lensobj_catalog, FALSE)) {
-	return FALSE;
+	outStatus = FALSE;
       }
     }
     if ((catalog[0].starpar_catalog != NULL) && (catalog[0].Nstarpar_disk > 0)) {
       if (!dvo_catalog_unlink_backup (catalog[0].starpar_catalog, FALSE)) {
-	return FALSE;
+	outStatus = FALSE;
       }
     }
     if ((catalog[0].galphot_catalog != NULL) && (catalog[0].Ngalphot_disk > 0)) {
       if (!dvo_catalog_unlink_backup (catalog[0].galphot_catalog, FALSE)) {
-	return FALSE;
-      }
-    }
-  }
-  return TRUE;
-}
-
-
+	outStatus = FALSE;
+      }
+    }
+  }
+  return outStatus;
+}
+
+
Index: trunk/Ohana/src/libdvo/src/dvo_catalog_create.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_catalog_create.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_catalog_create.c	(revision 38553)
@@ -105,5 +105,6 @@
   char *path = pathname (catalog[0].filename);
   char *root = filerootname (catalog[0].filename);
-  int length = strlen(path) + strlen(root) + 6;
+
+  int length = strlen(path) + strlen(root) + 16;
     
   Catalog *subcat;
@@ -120,5 +121,5 @@
   ALLOCATE (subcat->filename, char, length);
 
-  sprintf (subcat->filename, "%s/%s.%s", path, root, ext);
+  snprintf (subcat->filename, length, "%s/%s.%s", path, root, ext);
 
   char *file = filebasename (subcat->filename);
Index: trunk/Ohana/src/libdvo/src/dvo_catalog_split.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 38553)
@@ -90,7 +90,5 @@
 int dvo_catalog_save_subcat (Catalog *catalog, FTable *ftable, off_t start, off_t Nrows, off_t Ndisk, off_t Ntotal) {
 
-  Matrix matrix;
-  
-  if (OHANA_MEMCHECK) ohana_memcheck_func (TRUE);
+  if (OHANA_MEMCHECK) ohana_memcheck (TRUE);
   
   /* rewind file pointers and truncate (file is still open) */
@@ -108,5 +106,7 @@
   off_t fullsize = catalog->header.datasize;
 
+# if (1)
   // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+  Matrix matrix;
   gfits_create_matrix (&catalog->header, &matrix);
   if (!gfits_fwrite_matrix  (catalog->f, &matrix)) {
@@ -117,4 +117,5 @@
   fullsize += matrix.datasize;
   gfits_free_matrix (&matrix);
+# endif
 
   FTable *outtable = ftable;
@@ -128,5 +129,5 @@
   int isCompressed = output_is_compressed (start, Nrows, Ntotal, catalog->catcompress);
 
-  if (OHANA_MEMCHECK) ohana_memcheck_func (TRUE);
+  if (OHANA_MEMCHECK) ohana_memcheck (TRUE);
 
   if (isCompressed) {
@@ -136,18 +137,22 @@
     if (!gfits_compress_table (ftable, &cmptable, 1000, compressMode)) {
       fprintf (stderr, "compression failure\n");
+      free (compressMode);
       return (FALSE);
     }
     if (!byteswap_varlength_ftable (&cmpheader, &cmptable)) {
       fprintf (stderr, "failed to swap varlength column\n");
+      free (compressMode);
       return FALSE;
     }
     if (!gfits_modify (cmptable.header, "DVO_CMP", "%s", 1, compressMode)) {
       fprintf (stderr, "can't save compression mode\n");
-      return (FALSE);
-    }
+      free (compressMode);
+      return (FALSE);
+    }
+    free (compressMode);
     outtable = &cmptable;
   }
 
-  if (OHANA_MEMCHECK) ohana_memcheck_func (TRUE);
+  if (OHANA_MEMCHECK) ohana_memcheck (TRUE);
 
   // write the table data
@@ -169,5 +174,31 @@
   fullsize += outtable->datasize + outtable->header->datasize;
 
-  if (OHANA_MEMCHECK) ohana_memcheck_func (TRUE);
+  // XXX test of repeated failure
+  if (0) {
+    Matrix myMatrix;
+
+    // write the PHU matrix; this is probably a NOP, do I have to keep it in?
+    gfits_create_matrix (&catalog->header, &myMatrix);
+
+    int niter;
+    for (niter = 0; niter < 5; niter ++) {
+      char name[1024];
+      snprintf (name, 1024, "%s.v.%d", catalog->filename, niter);
+      FILE *f = fopen (name, "w");
+
+      myAssert (gfits_fwrite_header  (f, &catalog->header), "failed to write header");
+      myAssert (gfits_fwrite_matrix  (f, &myMatrix), "failed to write matrix");
+      myAssert (gfits_fwrite_Theader (f, outtable->header), "can't write table header");
+      myAssert (gfits_fwrite_table (f, outtable), "can't write table data");
+      myAssert (!fflush (f), "failed to flush");
+      myAssert (!fclose (f), "failed to close");
+      int fd = fileno(f);
+      myAssert (fsync(fd), "failed to sync");
+      fprintf (stderr, "wrote to %s\n", name);
+    }
+    gfits_free_matrix (&myMatrix);
+  }
+
+  if (OHANA_MEMCHECK) ohana_memcheck (TRUE);
 
   // since we init'ed the structures above, these operations are safe whether or not we compressed the table
@@ -191,5 +222,5 @@
   off_t Nskip;
   int status;
-  char *path, string[80];
+  char *path, string[256];
   Catalog *subcat;
 
@@ -215,6 +246,7 @@
     return (DVO_CAT_OPEN_FAIL);
   }
-  ALLOCATE (subcat[0].filename, char, strlen(path) + strlen(string) + 2);
-  sprintf (subcat[0].filename, "%s/%s", path, string);
+  int Nchar = strlen(path) + strlen(string) + 10;
+  ALLOCATE (subcat[0].filename, char, Nchar);
+  snprintf (subcat[0].filename, Nchar, "%s/%s", path, string);
   free (path);
 
@@ -282,5 +314,5 @@
     }
 
-    char compressMode[80];
+    char compressMode[256];
     if (!gfits_scan (ftable->header, "DVO_CMP", "%s", 1, compressMode)) {
       strcpy (compressMode, "AUTO");
@@ -759,4 +791,21 @@
 }
 
+# if (0)
+void compare_file_ptr (FILE *copy_ptr, FILE *real_ptr, char *name) {
+  return;
+
+  int i;
+  
+  char *real = (char *) real_ptr;
+  char *copy = (char *) copy_ptr;
+
+  for (i = 0; i < sizeof(FILE); i++, real++, copy++) {
+    if (*real != *copy) {
+      fprintf (stderr, "file pointers %s differ @ %d\n", name, (int) ((char *) real - (char *) real_ptr));
+    }
+  }
+}
+# endif
+
 /* save_catalog_split writes all data currently in memory to disk */
 int dvo_catalog_save_split (Catalog *catalog, char VERBOSE) {
@@ -845,4 +894,5 @@
       goto failure;
     }
+
     gfits_free_header (&header);
     gfits_free_table (&ftable);
@@ -887,4 +937,5 @@
       goto failure;
     }
+
     gfits_free_header (&header);
     gfits_free_table (&ftable);
Index: trunk/Ohana/src/libdvo/src/dvo_convert.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_convert.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_convert.c	(revision 38553)
@@ -1035,12 +1035,13 @@
   Nimage = theader[0].Naxis[1];
 
-# define FORMAT_CASE(FORMAT, TYPE) \
-    case DVO_FORMAT_##FORMAT: { \
-      Image_##TYPE *tmpImage; \
+# define FORMAT_CASE(FORMAT, TYPE)		\
+  case DVO_FORMAT_##FORMAT: {			\
+    Image_##TYPE *tmpImage;						\
       tmpImage = ImageInternalTo_##TYPE ((Image *) ftable[0].buffer, Nimage); \
-      free (ftable[0].buffer); \
-      gfits_table_set_Image_##TYPE (ftable, tmpImage, Nimage, TRUE); \
-      free (tmpImage); \
-      break; }
+	free (ftable[0].buffer);					\
+	gfits_free_header (ftable->header);				\
+	gfits_table_set_Image_##TYPE (ftable, tmpImage, Nimage, TRUE);	\
+	  free (tmpImage);						\
+	  break; }
 
   /* convert from the internal format */
Index: trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V5.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V5.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_convert_PS1_V5.c	(revision 38553)
@@ -990,22 +990,23 @@
 
     out[i].Xfit       	 = in[i].Xfit;
-    out[i]. Yfit      	 = in[i]. Yfit;
-    out[i]. mag       	 = in[i]. mag;
-    out[i]. magErr    	 = in[i]. magErr;
-    out[i]. majorAxis 	 = in[i]. majorAxis;
-    out[i]. minorAxis 	 = in[i]. minorAxis;
-    out[i]. majorAxisErr = in[i]. majorAxisErr;
-    out[i]. minorAxisErr = in[i]. minorAxisErr;
-    out[i]. theta        = in[i]. theta;
-    out[i]. theta_err    = in[i]. theta_err;
-    out[i]. index        = in[i]. index;
-    out[i]. chisq	 = in[i]. chisq;
-    out[i]. Npix 	 = in[i]. Npix;
-    out[i]. objID	 = in[i]. objID;
-    out[i]. catID        = in[i]. catID;
-    out[i]. detID	 = in[i]. detID;
-    out[i]. imageID	 = in[i]. imageID;
-    out[i]. photcode	 = in[i]. photcode;
-    out[i]. modelType	 = in[i]. modelType;
+    out[i].Yfit      	 = in[i].Yfit;
+    out[i].mag       	 = in[i].mag;
+    out[i].magErr    	 = in[i].magErr;
+    out[i].majorAxis 	 = in[i].majorAxis;
+    out[i].minorAxis 	 = in[i].minorAxis;
+    out[i].majorAxisErr  = in[i].majorAxisErr;
+    out[i].minorAxisErr  = in[i].minorAxisErr;
+    out[i].theta         = in[i].theta;
+    out[i].thetaErr      = in[i].thetaErr;
+    out[i].index         = in[i].index;
+    out[i].chisq	 = in[i].chisq;
+    out[i].Npix 	 = in[i].Npix;
+    out[i].objID	 = in[i].objID;
+    out[i].catID         = in[i].catID;
+    out[i].detID	 = in[i].detID;
+    out[i].imageID	 = in[i].imageID;
+    out[i].averef	 = in[i].averef;
+    out[i].photcode	 = in[i].photcode;
+    out[i].modelType	 = in[i].modelType;
   }
   return (out);
@@ -1029,5 +1030,5 @@
     out[i].minorAxisErr  = in[i].minorAxisErr;
     out[i].theta         = in[i].theta;
-    out[i].theta_err     = in[i].theta_err;
+    out[i].thetaErr      = in[i].thetaErr;
     out[i].index         = in[i].index;
     out[i].chisq	 = in[i].chisq;
@@ -1037,4 +1038,5 @@
     out[i].detID	 = in[i].detID;
     out[i].imageID	 = in[i].imageID;
+    out[i].averef	 = in[i].averef;
     out[i].photcode	 = in[i].photcode;
     out[i].modelType	 = in[i].modelType;
Index: trunk/Ohana/src/libdvo/src/dvo_image.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_image.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_image.c	(revision 38553)
@@ -231,5 +231,5 @@
 int dvo_image_createID (Header *header) {
   
-  char dbID[33];
+  char dbID[64];
 
   if (!header->buffer) return FALSE;
@@ -259,5 +259,5 @@
   int i;
   for (i = 0; i < 32; i++) {
-    sprintf (&dbID[i], "%1x", (int)(16.0*drand48()));
+    myAssert (snprintf (&dbID[i], 2, "%1x", (int)(16.0*drand48())) < 2, "overflow");
   }
 
Index: trunk/Ohana/src/libdvo/src/dvo_photcode_ops.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_photcode_ops.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_photcode_ops.c	(revision 38553)
@@ -43,5 +43,19 @@
 }
 
-// set the photcode table. This is used to switch between serveral previously
+// free a specified photcode set
+void FreePhotcodeData (PhotCodeData *myPhotcodes) {
+  if (!myPhotcodes) return;
+  FREE(myPhotcodes->code);
+  FREE(myPhotcodes);
+}
+
+// free the internal table
+void FreePhotcodeTable (void) {
+  FreePhotcodeData (photcodes);
+  FREE(genericCodeMag);
+  FREE(genericCodeFlux);
+}
+
+// set the photcode table. This is used to switch between several previously
 // allocated tables
 void SetPhotcodeTable (PhotCodeData *new) {
Index: trunk/Ohana/src/libdvo/src/dvo_util.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_util.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/dvo_util.c	(revision 38553)
@@ -63,5 +63,5 @@
     }
 
-    sprintf (dvoConfig->photcodeFile, "%s/Photcodes.dat", dvoConfig->catdir);
+    snprintf (dvoConfig->photcodeFile, 256, "%s/Photcodes.dat", dvoConfig->catdir);
     if (!LoadPhotcodes (dvoConfig->photcodeFile, MasterPhotcodeFile, FALSE)) {
         fprintf (stderr, "error loading photcode table %s or master file %s\n",
@@ -101,5 +101,5 @@
     char filename[256];
   
-    sprintf (filename, "%s/Images.dat", dvoConfig->catdir);
+    snprintf (filename, 256, "%s/Images.dat", dvoConfig->catdir);
 
     gfits_db_init (&dvoConfig->imageDB);
Index: trunk/Ohana/src/libdvo/src/skydb.c
===================================================================
--- trunk/Ohana/src/libdvo/src/skydb.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/skydb.c	(revision 38553)
@@ -224,5 +224,5 @@
   /* north dec bands */
   for (dec = 0; dec < 90; dec += 7.5) {
-    sprintf (db[N].name, "n%04d.cpt", (int) 100*dec);
+    myAssert (snprintf (db[N].name, 18, "n%04d.cpt", (int) 100*dec) < 18, "overflow");
     db[N].Rmin =   0; db[N].Rmax = 360;
     db[N].Dmin = dec; db[N].Dmax = dec + 7.5;
@@ -233,5 +233,5 @@
   /* south dec bands */
   for (dec = 0; dec > -90; dec -= 7.5) {
-    sprintf (db[N].name, "s%04d.cpt", (int) 100*dec);
+    myAssert (snprintf (db[N].name, 18, "s%04d.cpt", (int) 100*dec) < 18, "overflow");
     db[N].Rmin =   0;       db[N].Rmax = 360;
     db[N].Dmin = dec - 7.5; db[N].Dmax = dec;
@@ -276,5 +276,5 @@
       new[Nnew].child = FALSE;
       strncpy (root, db[i].name, 5); root[5] = 0;
-      sprintf (new[Nnew].name, "%s/r%04d.cpt", root, Rnumber);
+      myAssert (snprintf (new[Nnew].name, 18, "%s/r%04d.cpt", root, Rnumber) < 18, "overflow");
       Rnumber ++;      
       Nnew ++;
@@ -365,5 +365,5 @@
 	db[N].child = FALSE;
 	strncpy (root, db[i].name, 10); root[10] = 0;
-	sprintf (db[N].name, "%s.%02d.cpt", root, Rnumber);
+	myAssert (snprintf (db[N].name, 18, "%s.%02d.cpt", root, Rnumber) < 18, "overflow");
 	Rnumber ++;
 	N ++;
Index: trunk/Ohana/src/libdvo/src/skyregion_gsc.c
===================================================================
--- trunk/Ohana/src/libdvo/src/skyregion_gsc.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/skyregion_gsc.c	(revision 38553)
@@ -46,5 +46,4 @@
   FTable ftable;
   SkyTable *skytable;
-  SkyTable *band;
   SkyTable L0, L1, L2, L3, L4;
   SkyRegionZone *zones;
@@ -79,5 +78,6 @@
 /* L0 : full sky */
   L0.Nregions = 1;
-  ALLOCATE (L0.regions, SkyRegion, L0.Nregions);
+  L0.Nalloc = 1;
+  ALLOCATE (L0.regions, SkyRegion, L0.Nalloc);
   L0.regions[0].Rmin 	=   0;
   L0.regions[0].Rmax 	= 360;
@@ -99,8 +99,8 @@
   /* allocate space for all levels */
   L1.Nregions = L2.Nregions = L3.Nregions = L4.Nregions = 0;
-  ALLOCATE (L1.regions, SkyRegion, 1);
-  ALLOCATE (L2.regions, SkyRegion, 1);
-  ALLOCATE (L3.regions, SkyRegion, 1);
-  ALLOCATE (L4.regions, SkyRegion, 1);
+  L1.Nalloc = NDECBANDS;         ALLOCATE (L1.regions, SkyRegion, L1.Nalloc);
+  L2.Nalloc = NDECBANDS*0x10;    ALLOCATE (L2.regions, SkyRegion, L2.Nalloc);
+  L3.Nalloc = NDECBANDS*0x100;   ALLOCATE (L3.regions, SkyRegion, L3.Nalloc);
+  L4.Nalloc = NDECBANDS*0x1000;  ALLOCATE (L4.regions, SkyRegion, L4.Nalloc);
 
   // skipLines = 0;
@@ -130,5 +130,5 @@
 
     /* load all GSC Regions in this band */
-    band = SkyRegionForDecBand (&ftable.buffer[skipLines*48], DecLines[i], DecNames[i], L1.regions[i].Dmin, L1.regions[i].Dmax);
+    SkyTable *band = SkyRegionForDecBand (&ftable.buffer[skipLines*48], DecLines[i], DecNames[i], L1.regions[i].Dmin, L1.regions[i].Dmax);
     skipLines += DecLines[i];
 
@@ -151,5 +151,5 @@
 
     L1.Nregions ++;
-    REALLOCATE (L1.regions, SkyRegion, L1.Nregions + 1);
+    myAssert (L1.Nregions <= NDECBANDS, "too many L1 regions");
   }
 
@@ -225,5 +225,5 @@
 
     temp[5] = 0;
-    sprintf (name, "%s/%s", DecName, &temp[1]);
+    snprintf (name, 80, "%s/%s", DecName, &temp[1]);
     strcpy (regions[i].name, name);
   }
@@ -231,4 +231,5 @@
   band[0].regions = regions;
   band[0].Nregions = Nregions;
+  band[0].Nalloc   = Nregions;
   return (band);
 }
@@ -277,5 +278,5 @@
   Nregions = band[0].Nregions;
 
-  NZ = 10;
+  NZ = 100;
   ALLOCATE (zones, SkyRegionZone, NZ);
  
@@ -312,5 +313,5 @@
       /* go to the next zone */
       Nz++;
-      CHECK_REALLOCATE (zones, SkyRegionZone, NZ, Nz, 10);
+      CHECK_REALLOCATE (zones, SkyRegionZone, NZ, Nz, 100);
 
       /* start info for the new zone */
@@ -365,5 +366,5 @@
 	band[0].regions[Nregions + i].Dmax = -86.250;
       }
-      sprintf (band[0].regions[Nregions + i].name, "%s.%d", basename, i);
+      myAssert (snprintf (band[0].regions[Nregions + i].name, 18, "%s.%d", basename, i) < 18, "overflow");
     }
     band[0].regions[Nregions + i].Rmin = 0.0;
@@ -376,5 +377,5 @@
       band[0].regions[Nregions + i].Dmax = -88.125;
     }
-    sprintf (band[0].regions[Nregions + i].name, "%s.%d", basename, i);
+    myAssert (snprintf (band[0].regions[Nregions + i].name, 18, "%s.%d", basename, i) < 18, "overflow");
 
     zones[0].Nset = 6;
@@ -401,9 +402,9 @@
 void SkyTableL2fromZone (SkyTable *L2, SkyTable *L3, SkyTable *L4, SkyTable *band, SkyRegionZone *zone, int parent) {
 
-  int i, Nr, Ns, Ne;
+  int i, Ns, Ne;
   char *p, name[80];
 
-  Nr = L2[0].Nregions;
-  REALLOCATE (L2[0].regions, SkyRegion, Nr + 1);
+  int Nr = L2[0].Nregions;
+  CHECK_REALLOCATE (L2[0].regions, SkyRegion, L2[0].Nalloc, L2[0].Nregions, 100);
   
   /* divide this zone into L2 regions with Nset L3 regions each (fewer on ends) */
@@ -435,5 +436,5 @@
     }
     *p = 0;
-    sprintf (name, "%s/z%03d", band[0].regions[Ns].name, Nr);
+    myAssert (snprintf (name, 80, "%s/z%03d", band[0].regions[Ns].name, Nr) < 80, "overflow");
     *p = '/';
     strcpy (L2[0].regions[Nr].name, name);
@@ -444,5 +445,5 @@
 
     Nr++;
-    REALLOCATE (L2[0].regions, SkyRegion, Nr + 1);
+    CHECK_REALLOCATE (L2[0].regions, SkyRegion, L2[0].Nalloc, Nr, 100);
   }
   L2[0].Nregions = Nr;
@@ -456,5 +457,5 @@
   Nr = L3[0].Nregions;
   L3[0].Nregions += Ne - Ns;
-  REALLOCATE (L3[0].regions, SkyRegion, L3[0].Nregions);
+  CHECK_REALLOCATE (L3[0].regions, SkyRegion, L3[0].Nalloc, L3[0].Nregions, 0.5*L3[0].Nalloc);
 
   L2[0].child  = TRUE;
@@ -498,5 +499,5 @@
   Nr = L4[0].Nregions;
   L4[0].Nregions += NDIV*NDIV;
-  REALLOCATE (L4[0].regions, SkyRegion, L4[0].Nregions);
+  CHECK_REALLOCATE (L4[0].regions, SkyRegion, L4[0].Nalloc, L4[0].Nregions, 0.5*L4[0].Nalloc);
 
   L3[0].child  = TRUE;
@@ -531,5 +532,5 @@
       L4[0].regions[Nr].backupID  = 0;
 
-      sprintf (name, "%s.%02d", L3[0].name, Nbox);
+      myAssert (snprintf (name, 80, "%s.%02d", L3[0].name, Nbox) < 80, "overflow");
       strcpy (L4[0].regions[Nr].name, name);
       if (DEBUG >= 4) SkyRegionPrint (&L4[0].regions[Nr]);
Index: trunk/Ohana/src/libdvo/src/skyregion_io.c
===================================================================
--- trunk/Ohana/src/libdvo/src/skyregion_io.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/skyregion_io.c	(revision 38553)
@@ -113,4 +113,9 @@
   fclose (f);
 
+  gfits_free_header  (&header);
+  gfits_free_matrix  (&matrix);
+  gfits_free_header  (&theader);
+  gfits_free_table   (&ftable);
+
   return (TRUE);
 }
@@ -131,4 +136,5 @@
     exit (1);
   }
+  free (filename);
   return (sky);
 
@@ -195,5 +201,5 @@
   // this generates the names, be sure to free when not needed
   for (i = 0; i < list[0].Nregions; i++) {
-    sprintf (line, "%s/%s.%s", path, list[0].regions[i][0].name, ext);
+    snprintf (line, 256, "%s/%s.%s", path, list[0].regions[i][0].name, ext);
     list[0].filename[i] = strcreate (line);
   }
@@ -209,5 +215,5 @@
   // this generates the names, be sure to free when not needed
   for (i = 0; i < sky[0].Nregions; i++) {
-    sprintf (line, "%s/%s.%s", path, sky[0].regions[i].name, ext);
+    snprintf (line, 256, "%s/%s.%s", path, sky[0].regions[i].name, ext);
     sky[0].filename[i] = strcreate (line);
   }
@@ -222,6 +228,8 @@
   
   char *skyfile;
-  ALLOCATE (skyfile, char, strlen(catdir) + strlen("/SkyTable.fits") + 1);
-  sprintf (skyfile, "%s/SkyTable.fits", catdir);
+
+  int Nchar = strlen(catdir) + strlen("/SkyTable.fits") + 16;
+  ALLOCATE (skyfile, char, Nchar);
+  snprintf (skyfile, Nchar, "%s/SkyTable.fits", catdir);
 
   return skyfile;
Index: trunk/Ohana/src/libdvo/src/skyregion_ops.c
===================================================================
--- trunk/Ohana/src/libdvo/src/skyregion_ops.c	(revision 38543)
+++ trunk/Ohana/src/libdvo/src/skyregion_ops.c	(revision 38553)
@@ -550,4 +550,5 @@
     }
     free (list[0].regions);
+    free (list[0].filename);
   }
   free (list);
Index: trunk/Ohana/src/libfits/header/F_write_H.c
===================================================================
--- trunk/Ohana/src/libfits/header/F_write_H.c	(revision 38543)
+++ trunk/Ohana/src/libfits/header/F_write_H.c	(revision 38553)
@@ -5,19 +5,8 @@
 int gfits_write_header (char *filename, Header *header) {
 
-  FILE *f;
-  off_t Nbytes;
-  int status;
-  
-  status = TRUE;
+  FILE *f = fopen (filename, "w");
+  if (!f) return (FALSE);
 
-  f = fopen (filename, "w");
-  if (f == (FILE *) NULL) return (FALSE);
-
-  Nbytes = fwrite (header[0].buffer, sizeof(char), header[0].datasize, f);
-
-  if (Nbytes != header[0].datasize) {
-    status = FALSE;
-  }
-
+  int status = gfits_fwrite_header (f, header);
   fclose (f);
 
@@ -29,22 +18,26 @@
 
   off_t Nbytes; 
-  int status;
-  
-  status = TRUE;
+
+# ifdef OHANA_MEMORY  
+  { // check memory before writing:
+    // memblock of supplied pointer
+    OhanaMemblock *myBlock = (OhanaMemblock *) header[0].buffer - 1;
+    myAssert (myBlock->startblock == OHANA_MEMMAGIC, "bad memory");
+    myAssert (myBlock->endblock == OHANA_MEMMAGIC, "bad memory");
+    myAssert (myBlock->size >= header[0].datasize, "overflow");
+  }
+# endif
 
   Nbytes = fwrite (header[0].buffer, sizeof(char), header[0].datasize, f);
-
-  if (Nbytes != header[0].datasize) {
-    status = FALSE;
+  if (Nbytes != header[0].datasize) { 
+    perror ("fwrite: "); 
+    return FALSE; 
   }
-
-  return (status);
+  return TRUE;
 }	
 
 
 int gfits_fwrite_header (FILE *f, Header *header) {
-
-  int status;
-  status = gfits_save_header (f, header);
+  int status = gfits_save_header (f, header);
   return (status);
 }
Index: trunk/Ohana/src/libfits/include/gfitsio.h
===================================================================
--- trunk/Ohana/src/libfits/include/gfitsio.h	(revision 38543)
+++ trunk/Ohana/src/libfits/include/gfitsio.h	(revision 38553)
@@ -99,14 +99,14 @@
 
 typedef struct {
-  char ttype[16]; 	      // TTYPE field of original table
-  char ttype_cmt[80];	      // comment associated with TTYPE
-  char tunit[16];	      // TUNIT field of original table
-  char tunit_cmt[80];	      // comment associated with TUNIT
-  char tformat[16];	      // TFORM field of original table
-  char tformat_cmt[80];	      // comment associated with TFORM
-  char zctype[80];	      // compression type for this field
+  char ttype[256]; 	      // TTYPE field of original table
+  char ttype_cmt[256];	      // comment associated with TTYPE
+  char tunit[256];	      // TUNIT field of original table
+  char tunit_cmt[256];	      // comment associated with TUNIT
+  char tformat[256];	      // TFORM field of original table
+  char tformat_cmt[256];      // comment associated with TFORM
+  char zctype[256];	      // compression type for this field
   VarLengthColumn zdef;	      // description of the output variable length column
 
-  char datatype[80];	      // named data type associated with ttype (eg, 18J -> int, 18D -> double)
+  char datatype[256];	      // named data type associated with ttype (eg, 18J -> int, 18D -> double)
   int Nvalues;		      // number of values per row (eg 18J -> 18 int values)
   int pixsize;		      // number of bytes per value of this row (eg, 18J -> 4 bytes)
Index: trunk/Ohana/src/libfits/matrix/F_write_M.c
===================================================================
--- trunk/Ohana/src/libfits/matrix/F_write_M.c	(revision 38543)
+++ trunk/Ohana/src/libfits/matrix/F_write_M.c	(revision 38553)
@@ -35,4 +35,7 @@
   else 
     nbytes = FT_RECORD_SIZE * ((off_t) (matrix[0].datasize / FT_RECORD_SIZE));
+
+  // fprintf (stderr, "write matrix: %d bytes (%d datasize)\n", (int) nbytes, (int) matrix[0].datasize);
+  if (nbytes == 0) return TRUE;
 
 # define DOSWAP(A,B) { char tmp = A; A = B; B = tmp; }
Index: trunk/Ohana/src/libfits/table/F_compress_T.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_compress_T.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_compress_T.c	(revision 38553)
@@ -57,4 +57,5 @@
   char *raw = NULL;
   char *zdata = NULL;
+  TableField *fields = NULL;
 
   Header *srcheader = srctable->header;
@@ -100,5 +101,4 @@
   gettimeofday (&startTimer, (void *) NULL);
 
-  TableField *fields = NULL;
   ALLOCATE_ZERO (fields, TableField, Nfields);
   for (i = 0; i < Nfields; i++) {
@@ -351,6 +351,7 @@
   gfits_dump_cmp_table (tgttable, "cmp");
 
-  free (raw);
-  free (zdata);
+  FREE (raw);
+  FREE (zdata);
+  FREE (fields);
   return (TRUE);
 
@@ -358,4 +359,5 @@
   FREE (raw);
   FREE (zdata);
+  FREE (fields);
   return FALSE;
 }
Index: trunk/Ohana/src/libfits/table/F_create_TH.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_create_TH.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_create_TH.c	(revision 38553)
@@ -11,8 +11,9 @@
   
   int i;
-  char axis[10];
+  char axis[128];
   
   header[0].datasize = NBYTES;
 
+  myAssert (!header->buffer, "failed to init header or free buffer?");
   ALLOCATE (header[0].buffer, char, NBYTES);
   
@@ -26,5 +27,5 @@
   
   for (i = 0; i < header[0].Naxes; i++) {
-    sprintf (axis, "NAXIS%d", i + 1);
+    snprintf (axis, 64, "NAXIS%d", i + 1);
     gfits_modify (header,  axis, OFF_T_FMT, 1,  header[0].Naxis[i]);
   }
Index: trunk/Ohana/src/libfits/table/F_define_column.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_define_column.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_define_column.c	(revision 38553)
@@ -11,5 +11,5 @@
   off_t Naxis1;
   int Nfields, Nbytes, Nval;
-  char type[16], field[16];
+  char type[64], field[64];
   
   if (!gfits_bintable_format (format, type, &Nval, &Nbytes)) return (FALSE);
@@ -21,17 +21,17 @@
   Naxis1 += Nbytes*Nval;
 
-  sprintf (field, "TTYPE%d", Nfields);
+  snprintf (field, 64, "TTYPE%d", Nfields);
   gfits_modify (header, field, "%s", 1, label);
   gfits_modify_alt (header, field, "%C", 1, comment);
-  sprintf (field, "TUNIT%d", Nfields);
+  snprintf (field, 64, "TUNIT%d", Nfields);
   gfits_modify (header, field, "%s", 1, unit);
-  sprintf (field, "TFORM%d", Nfields);
+  snprintf (field, 64, "TFORM%d", Nfields);
   gfits_modify (header, field, "%s", 1, format);
 
   // add scaling parameters unless they amount to a noop
   if ((bscale != 1.0) || (bzero != 0.0)) {
-      sprintf (field, "TSCAL%d", Nfields);
+      snprintf (field, 64, "TSCAL%d", Nfields);
       gfits_modify (header, field, "%lf", 1, bscale);
-      sprintf (field, "TZERO%d", Nfields);
+      snprintf (field, 64, "TZERO%d", Nfields);
       gfits_modify (header, field, "%lf", 1, bzero);
   }
@@ -54,5 +54,5 @@
   off_t Naxis1;
   int Nfields, Nbytes, Nval;
-  char type[16], field[16];
+  char type[64], field[64];
   
   if (!gfits_bintable_format (format, type, &Nval, &Nbytes)) return (FALSE);
@@ -64,5 +64,5 @@
   Naxis1 += Nbytes*Nval;
 
-  sprintf (field, "TTYPE%d", Nfields);
+  snprintf (field, 64, "TTYPE%d", Nfields);
   gfits_modify (header, field, "%s", 1, label);
   if (comment) {
@@ -70,15 +70,15 @@
   }
   if (unit) {
-    sprintf (field, "TUNIT%d", Nfields);
+    snprintf (field, 64, "TUNIT%d", Nfields);
     gfits_modify (header, field, "%s", 1, unit);
   }
-  sprintf (field, "TFORM%d", Nfields);
+  snprintf (field, 64, "TFORM%d", Nfields);
   gfits_modify (header, field, "%s", 1, format);
 
   // add scaling parameters unless they amount to a noop
   if ((bscale != 1.0) || (bzero != 0.0)) {
-      sprintf (field, "TSCAL%d", Nfields);
+      snprintf (field, 64, "TSCAL%d", Nfields);
       gfits_modify (header, field, "%lf", 1, bscale);
-      sprintf (field, "TZERO%d", Nfields);
+      snprintf (field, 64, "TZERO%d", Nfields);
       gfits_modify (header, field, "%lf", 1, bzero);
   }
@@ -97,5 +97,5 @@
   off_t Naxis1;
   int Nstart, Nfields, Nbytes, Nval;
-  char type[16], field[16], cformat[16];
+  char type[64], field[64], cformat[64];
 
   strcpy (cformat, format);
@@ -109,13 +109,13 @@
   Naxis1 += Nbytes*Nval;
 
-  sprintf (field, "TTYPE%d", Nfields);
+  snprintf (field, 64, "TTYPE%d", Nfields);
   gfits_modify (header, field, "%s", 1, label);
   gfits_modify_alt (header, field, "%C", 1, comment);
-  sprintf (field, "TUNIT%d", Nfields);
+  snprintf (field, 64, "TUNIT%d", Nfields);
   gfits_modify (header, field, "%s", 1, unit);
-  sprintf (field, "TFORM%d", Nfields);
+  snprintf (field, 64, "TFORM%d", Nfields);
   gfits_modify (header, field, "%s", 1, format);
 
-  sprintf (field, "TBCOL%d", Nfields);
+  snprintf (field, 64, "TBCOL%d", Nfields);
   gfits_modify (header, field, "%d", 1, Nstart);
 
Index: trunk/Ohana/src/libfits/table/F_get_T_column.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_get_T_column.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_get_T_column.c	(revision 38553)
@@ -9,5 +9,5 @@
 {
   
-  char Tform[100], field[100], tmp[100];
+  char Tform[256], field[256], tmp[256];
   int  start, Nchar, i, N;
   
@@ -22,8 +22,8 @@
   /* should I count fields from 0 or from 1? */
   
-  sprintf (field, "TBCOL%d\0", X);
+  snprintf (field, 256, "TBCOL%d\0", X);
   gfits_scan (&table[0].header, field, "%d", &start, 1);
   start --;
-  sprintf (field, "TFORM%d\0", X);
+  snprintf (field, 256, "TFORM%d\0", X);
   gfits_scan (&table[0].header, field, "%s", Tform, 1);
   Nchar = atof (&Tform[1]);
Index: trunk/Ohana/src/libfits/table/F_get_T_value.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_get_T_value.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_get_T_value.c	(revision 38553)
@@ -10,5 +10,5 @@
 {
   
-  char Tform[100], field[100];
+  char Tform[256], field[256];
   int  start, Nchar, byte;
   char tmp[1000];
@@ -16,11 +16,12 @@
   /* no error checking, all sorts of problems! */
   
-  sprintf (field, "TBCOL%d\0", X);
+  snprintf (field, 256, "TBCOL%d\0", X);
   gfits_scan (&table[0].header, field, "%d", &start, 1);
   start --;
   
-  sprintf (field, "TFORM%d\0", X);
+  snprintf (field, 256, "TFORM%d\0", X);
   gfits_scan (&table[0].header, field, "%s", Tform, 1);
   Nchar = atof (&Tform[1]);
+  myAssert (Nchar < 999, "overflow");
   
   byte = Y*table[0].Naxis[0] + start;
Index: trunk/Ohana/src/libfits/table/F_get_column.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_get_column.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_get_column.c	(revision 38553)
@@ -25,5 +25,5 @@
   off_t Nx, Ny;
   int i, N, Nfields, Nval, Nbytes, Nstart, Nv, Nb;
-  char tlabel[80], field[80], format[80], tmpline[16];
+  char tlabel[256], field[256], format[256], tmpline[64];
   char *Pin, *Pout, *array;
   double Bscale, Bzero;
@@ -36,5 +36,5 @@
   if (!gfits_scan (header, "TFIELDS", "%d", 1, &Nfields)) return (NULL);
   for (i = 1; strcasecmp (label, tlabel) && (i < Nfields + 1); i++) {
-    sprintf (field, "TTYPE%d", i);
+    snprintf (field, 256, "TTYPE%d", i);
     gfits_scan (header, field, "%s", 1, tlabel);
   }
@@ -46,9 +46,9 @@
 
   /* interpret format */
-  sprintf (field, "TSCAL%d", N);
+  snprintf (field, 256, "TSCAL%d", N);
   gfits_scan (header, field, "%lf", 1, &Bscale);
-  sprintf (field, "TZERO%d", N);
+  snprintf (field, 256, "TZERO%d", N);
   gfits_scan (header, field, "%lf", 1, &Bzero);
-  sprintf (field, "TFORM%d", N);
+  snprintf (field, 256, "TFORM%d", N);
   gfits_scan (header, field, "%s", 1, format);
 
@@ -62,5 +62,5 @@
   Nstart = 0;
   for (i = 1; i < N; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 256, "TFORM%d", i);
     gfits_scan (header, field, "%s", 1, format);
     gfits_bintable_format (format, tmpline, &Nv, &Nb);
@@ -145,9 +145,9 @@
 
   int Nbytes;
-  char field[80], format[80];
+  char field[256], format[256];
 
   assert (N > 0);
 
-  sprintf (field, "TFORM%d", N);
+  snprintf (field, 256, "TFORM%d", N);
   if (!gfits_scan (header, field, "%s", 1, format)) return FALSE;
   if (!gfits_bintable_format (format, type, Nval, &Nbytes)) return (FALSE);
@@ -159,5 +159,5 @@
 
   int i, N, Nfields;
-  char tlabel[80], field[80];
+  char tlabel[256], field[256];
 
   if (label == (char *) NULL) return (FALSE);
@@ -168,5 +168,5 @@
   gfits_scan (header, "TFIELDS", "%d", 1, &Nfields);
   for (i = 1; strcasecmp (label, tlabel) && (i < Nfields + 1); i++) {
-    sprintf (field, "TTYPE%d", i);
+    snprintf (field, 256, "TTYPE%d", i);
     gfits_scan (header, field, "%s", 1, tlabel);
   }
@@ -181,5 +181,5 @@
 int gfits_get_bintable_column_raw (Header *header, FTable *table, char *label, void **data, char nativeOrder) {
 
-  char type[16];
+  char type[64];
   off_t Nrow;
   int Ncol;
@@ -195,5 +195,5 @@
 int gfits_get_bintable_column (Header *header, FTable *table, char *label, void **data) {
 
-  char type[16];
+  char type[64];
   off_t Nrow;
   int Ncol;
@@ -229,5 +229,5 @@
 
   int i, N, Nfields, Nval, Nbytes;
-  char tlabel[80], field[80], format[80];
+  char tlabel[256], field[256], format[256];
 
   if (label == (char *) NULL) return (FALSE);
@@ -238,5 +238,5 @@
   gfits_scan (header, "TFIELDS", "%d", 1, &Nfields);
   for (i = 1; strcasecmp (label, tlabel) && (i < Nfields + 1); i++) {
-    sprintf (field, "TTYPE%d", i);
+    snprintf (field, 256, "TTYPE%d", i);
     gfits_scan (header, field, "%s", 1, tlabel);
   }
@@ -245,5 +245,5 @@
 
   /* interpret format */
-  sprintf (field, "TFORM%d", N);
+  snprintf (field, 256, "TFORM%d", N);
   gfits_scan (header, field, "%s", 1, format);
 
@@ -257,5 +257,5 @@
   off_t Nx, Ny;
   int i, N, Nfields, Nval, Nbytes, Nstart, Nv, Nb;
-  char tlabel[80], field[80], format[80], cformat[80], type[16], tmp[16];
+  char tlabel[256], field[256], format[256], cformat[256], type[64], tmp[64];
   char *array, *Pin, *Pout, *line;
 
@@ -268,5 +268,5 @@
   gfits_scan (header, "TFIELDS", "%d", 1, &Nfields);
   for (i = 1; strcasecmp (label, tlabel) && (i < Nfields + 1); i++) {
-    sprintf (field, "TTYPE%d", i);
+    snprintf (field, 256, "TTYPE%d", i);
     gfits_scan (header, field, "%s", 1, tlabel);
   }
@@ -275,5 +275,5 @@
 
   /* interpret format */
-  sprintf (field, "TFORM%d", N);
+  snprintf (field, 256, "TFORM%d", N);
   gfits_scan (header, field, "%s", 1, format);
 
@@ -288,5 +288,5 @@
   Nstart = 0;
   for (i = 1; i < N; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 256, "TFORM%d", i);
     gfits_scan (header, field, "%s", 1, format);
     gfits_table_format (format, tmp, &Nv, &Nb);
Index: trunk/Ohana/src/libfits/table/F_set_column.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_set_column.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_set_column.c	(revision 38553)
@@ -30,5 +30,5 @@
   int i, N, Nfields;
   int Nval, Nbytes, Nstart, Nv, Nb;
-  char tlabel[80], field[80], format[80], type[16], tmpline[16];
+  char tlabel[256], field[256], format[256], type[64], tmpline[64];
   char *Pin, *Pout, *array;
   double Bscale, Bzero;
@@ -41,5 +41,5 @@
   gfits_scan (header, "TFIELDS", "%d", 1, &Nfields);
   for (i = 1; strcasecmp (label, tlabel) && (i < Nfields + 1); i++) {
-    sprintf (field, "TTYPE%d", i);
+    snprintf (field, 256, "TTYPE%d", i);
     gfits_scan (header, field, "%s", 1, tlabel);
   }
@@ -48,13 +48,13 @@
 
   /* interpret format */
-  sprintf (field, "TSCAL%d", N);
+  snprintf (field, 256, "TSCAL%d", N);
   if (!gfits_scan (header, field, "%lf", 1, &Bscale)) {
     Bscale = 1.0;
   }
-  sprintf (field, "TZERO%d", N);
+  snprintf (field, 256, "TZERO%d", N);
   if (!gfits_scan (header, field, "%lf", 1, &Bzero)) {
     Bzero = 0.0;
   }
-  sprintf (field, "TFORM%d", N);
+  snprintf (field, 256, "TFORM%d", N);
   gfits_scan (header, field, "%s", 1, format);
 
@@ -75,5 +75,5 @@
   Nstart = 0;
   for (i = 1; i < N; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 256, "TFORM%d", i);
     gfits_scan (header, field, "%s", 1, format);
     gfits_bintable_format (format, tmpline, &Nv, &Nb);
@@ -190,5 +190,5 @@
   int i, N, Nfields;
   int Nval, NbytesOut, Nstart, Nv, Nb;
-  char tlabel[80], field[80], format[80], outtype[16], tmpline[16];
+  char tlabel[256], field[256], format[256], outtype[64], tmpline[64];
   char *Pin, *Pout, *array;
   double Bscale, Bzero;
@@ -201,5 +201,5 @@
   gfits_scan (header, "TFIELDS", "%d", 1, &Nfields);
   for (i = 1; strcasecmp (label, tlabel) && (i < Nfields + 1); i++) {
-    sprintf (field, "TTYPE%d", i);
+    snprintf (field, 256, "TTYPE%d", i);
     gfits_scan (header, field, "%s", 1, tlabel);
   }
@@ -208,13 +208,13 @@
 
   /* interpret format */
-  sprintf (field, "TSCAL%d", N);
+  snprintf (field, 256, "TSCAL%d", N);
   if (!gfits_scan (header, field, "%lf", 1, &Bscale)) {
     Bscale = 1.0;
   }
-  sprintf (field, "TZERO%d", N);
+  snprintf (field, 256, "TZERO%d", N);
   if (!gfits_scan (header, field, "%lf", 1, &Bzero)) {
     Bzero = 0.0;
   }
-  sprintf (field, "TFORM%d", N);
+  snprintf (field, 256, "TFORM%d", N);
   gfits_scan (header, field, "%s", 1, format);
 
@@ -233,5 +233,5 @@
   Nstart = 0;
   for (i = 1; i < N; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 256, "TFORM%d", i);
     gfits_scan (header, field, "%s", 1, format);
     gfits_bintable_format (format, tmpline, &Nv, &Nb);
@@ -780,5 +780,5 @@
   off_t Nx, Ny;
   int i, N, Nfields, Nval, Nbytes, Nstart, Nv, Nb;
-  char tlabel[80], field[80], format[80], cformat[80], type[16], tmp[16];
+  char tlabel[256], field[256], format[256], cformat[256], type[64], tmp[64];
   char *array, *Pin, *Pout, *line;
 
@@ -790,5 +790,5 @@
   gfits_scan (header, "TFIELDS", "%d", 1, &Nfields);
   for (i = 1; strcmp (label, tlabel) && (i < Nfields + 1); i++) {
-    sprintf (field, "TTYPE%d", i);
+    snprintf (field, 256, "TTYPE%d", i);
     gfits_scan (header, field, "%s", 1, tlabel);
   }
@@ -797,5 +797,5 @@
 
   /* interpret format */
-  sprintf (field, "TFORM%d", N);
+  snprintf (field, 256, "TFORM%d", N);
   gfits_scan (header, field, "%s", 1, format);
 
@@ -815,5 +815,5 @@
   Nstart = 0;
   for (i = 1; i < N; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 256, "TFORM%d", i);
     gfits_scan (header, field, "%s", 1, format);
     gfits_table_format (format, tmp, &Nv, &Nb);
Index: trunk/Ohana/src/libfits/table/F_table_column.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_table_column.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_table_column.c	(revision 38553)
@@ -6,5 +6,5 @@
 /* we expect one more field: the pointer to the array we read in */
 
-  char string[80], this_field[80], form[80], temp[80];
+  char string[256], this_field[256], form[256], temp[256];
   int i, j, N, start, end, width, M;
   va_list argp;
@@ -18,5 +18,5 @@
   /* find the correct field */
   for (i = 0; i < table[0].Nfields; i++) {
-    sprintf (string, "TTYPE%d\0", i+1);
+    snprintf (string, 256, "TTYPE%d\0", i+1);
     gfits_scan (&table[0].header, string, "%s", 1, this_field);
     if (!strcmp (field, this_field)) {
@@ -32,7 +32,7 @@
   N = i + 1;
 
-  sprintf (string, "TBCOL%d\0", N);
+  snprintf (string, 256, "TBCOL%d\0", N);
   gfits_scan (&table[0].header, string, "%d", 1, &start);
-  sprintf (string, "TFORM%d\0", N);
+  snprintf (string, 256, "TFORM%d\0", N);
   gfits_scan (&table[0].header, string, "%s", 1, form);
   /* we could use some error checking from the FITS table form, but
@@ -42,5 +42,5 @@
     end = table[0].Naxis[0];
   } else {
-    sprintf (string, "TBCOL%d\0", N+1);
+    snprintf (string, 256, "TBCOL%d\0", N+1);
     gfits_scan (&table[0].header, string, "%d", 1, &end);
   }
Index: trunk/Ohana/src/libfits/table/F_table_format.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_table_format.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_table_format.c	(revision 38553)
@@ -113,4 +113,6 @@
   if (!*Nbytes) { return (FALSE); }
   
+  // XXXX : check usage:
+  myAbort ("need to check length");
   sprintf (format, "%%-%s%c", Size, Type);
 
@@ -191,5 +193,5 @@
   off_t Nx, off;
   int i, Nchar, Nval, Nbytes, Nfields;
-  char *line, format[64], field[16], type[16];
+  char *line, format[64], field[64], type[64];
   va_list argp;
   
@@ -204,5 +206,5 @@
   for (i = 1; i <= Nfields; i++) {
 
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 64, "TFORM%d", i);
     gfits_scan (table[0].header, field, "%s", 1, format);       /* get field format */
     gfits_table_format (format, type, &Nval, &Nbytes); /* convert to c-style */
@@ -232,5 +234,5 @@
   int i, j, n, Nfields;
   int Nchar, Nval, Nbytes, status;
-  char format[64], field[16], type[16];
+  char format[64], field[64], type[64];
   double tzero, tscale;
   char *tmpChar;
@@ -246,10 +248,10 @@
 
   for (i = 1; i <= Nfields; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 64, "TFORM%d", i);
     gfits_scan (ftable[0].header, field, "%s", 1, format);       /* get field format */
     gfits_bintable_format (format, type, &Nval, &Nbytes); /* convert to c-style */
     Nchar = Nval * Nbytes;
 
-    sprintf (field, "TZERO%d", i);
+    snprintf (field, 64, "TZERO%d", i);
     status = gfits_scan (ftable[0].header, field, "%lf", 1, &tzero);       /* get field format */
     if (!status) {
@@ -258,5 +260,5 @@
     }
 
-    sprintf (field, "TSCAL%d", i);
+    snprintf (field, 64, "TSCAL%d", i);
     status = gfits_scan (ftable[0].header, field, "%lf", 1, &tscale);       /* get field format */
     if (!status) {
@@ -325,5 +327,5 @@
   int i, j, n, Nfields;
   int Nchar, Nval, Nbytes, status;
-  char format[64], field[16], type[16];
+  char format[64], field[64], type[64];
   double tzero, tscale;
   char *tmpChar;
@@ -339,10 +341,10 @@
 
   for (i = 1; i <= Nfields; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 64, "TFORM%d", i);
     gfits_scan (ftable[0].header, field, "%s", 1, format);       /* get field format */
     gfits_bintable_format (format, type, &Nval, &Nbytes); /* convert to c-style */
     Nchar = Nval * Nbytes;
 
-    sprintf (field, "TZERO%d", i);
+    snprintf (field, 64, "TZERO%d", i);
     status = gfits_scan (ftable[0].header, field, "%lf", 1, &tzero);       /* get field format */
     if (!status) {
@@ -351,5 +353,5 @@
     }
 
-    sprintf (field, "TSCAL%d", i);
+    snprintf (field, 64, "TSCAL%d", i);
     status = gfits_scan (ftable[0].header, field, "%lf", 1, &tscale);       /* get field format */
     if (!status) {
Index: trunk/Ohana/src/libfits/table/F_table_varlength.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_table_varlength.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_table_varlength.c	(revision 38553)
@@ -8,7 +8,7 @@
   int Nv, Nb;
   char *p1, *p2, *p3;
-  char field[81];
-  char format[81];
-  char tmpline[81];
+  char field[256];
+  char format[256];
+  char tmpline[256];
 
   // grab the value of TFORMn for this column
@@ -61,5 +61,5 @@
   def->offset = 0;
   for (i = 1; i < column; i++) {
-    sprintf (field, "TFORM%d", i);
+    snprintf (field, 256, "TFORM%d", i);
     gfits_scan (ftable->header, field, "%s", 1, format);
     gfits_bintable_format (format, tmpline, &Nv, &Nb);
Index: trunk/Ohana/src/libfits/table/F_uncompress_T.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_uncompress_T.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_uncompress_T.c	(revision 38553)
@@ -78,8 +78,9 @@
   int i;
 
-  char keyword[81];
+  char keyword[256];
 
   char *raw = NULL;
   char *zdata = NULL;
+  TableField *fields = NULL;
 
   Header *srcheader = srctable->header;
@@ -111,5 +112,4 @@
   int offset = 0;
 
-  TableField *fields = NULL;
   ALLOCATE (fields, TableField, Nfields);
   for (i = 0; i < Nfields; i++) {
@@ -336,4 +336,5 @@
   free (raw);
   free (zdata);
+  free (fields);
   return (TRUE);
 
@@ -341,4 +342,5 @@
   FREE (raw);
   FREE (zdata);
+  FREE (fields);
   return FALSE;
 }
Index: trunk/Ohana/src/libfits/table/F_write_T.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_write_T.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_write_T.c	(revision 38553)
@@ -5,13 +5,8 @@
 int gfits_write_table (char *filename, FTable *table) {
   
-  FILE *f;
-  int status;
-  
-  status = TRUE;
-  
-  f = fopen (filename, "a+");
+  FILE *f = fopen (filename, "a+");
   if (f == (FILE *) NULL) return (FALSE);
   
-  status = fseeko (f, 0LL, SEEK_END);  /* write table to end of file! */
+  int status = fseeko (f, 0LL, SEEK_END);  /* write table to end of file! */
   if (status) { perror ("fseeko: "); return (FALSE);  }
   status = gfits_fwrite_table (f, table);
@@ -25,7 +20,20 @@
   
   off_t Nbytes;
-  
+
+# ifdef OHANA_MEMORY  
+  { // check memory before writing:
+    // memblock of supplied pointer
+    OhanaMemblock *myBlock = (OhanaMemblock *) table[0].buffer - 1;
+    myAssert (myBlock->startblock == OHANA_MEMMAGIC, "bad memory");
+    myAssert (myBlock->endblock == OHANA_MEMMAGIC, "bad memory");
+    myAssert (myBlock->size >= table[0].datasize, "overflow");
+  }
+# endif
+
   Nbytes = fwrite (table[0].buffer, sizeof(char), table[0].datasize, f);
-  if (Nbytes != table[0].datasize) { perror ("fwrite: "); return (FALSE);  }
+  if (Nbytes != table[0].datasize) { 
+    perror ("fwrite: "); 
+    return (FALSE);  
+  }
   return (TRUE);
 }	
Index: trunk/Ohana/src/libfits/table/F_write_TH.c
===================================================================
--- trunk/Ohana/src/libfits/table/F_write_TH.c	(revision 38543)
+++ trunk/Ohana/src/libfits/table/F_write_TH.c	(revision 38553)
@@ -5,13 +5,8 @@
 int gfits_write_Theader (char *filename, Header *header) {
   
-  FILE *f;
-  int status;
+  FILE *f = fopen (filename, "a+");
+  if (!f) return (FALSE);
   
-  status = TRUE;
-  
-  f = fopen (filename, "a+");
-  if (f == (FILE *) NULL) return (FALSE);
-  
-  status = fseeko (f, 0LL, SEEK_END);  /* write header to end of file! */
+  int status = fseeko (f, 0LL, SEEK_END);  /* write header to end of file! */
   if (status) { perror ("fseeko: "); return (FALSE);  }
   status = gfits_fwrite_Theader (f, header);
@@ -26,6 +21,19 @@
   off_t Nbytes;
   
+# ifdef OHANA_MEMORY  
+  { 
+    // memblock of supplied pointer
+    OhanaMemblock *myBlock = (OhanaMemblock *) header[0].buffer - 1;
+    myAssert (myBlock->startblock == OHANA_MEMMAGIC, "bad memory");
+    myAssert (myBlock->endblock == OHANA_MEMMAGIC, "bad memory");
+    myAssert (myBlock->size >= header[0].datasize, "overflow");
+  }
+# endif
+
   Nbytes = fwrite (header[0].buffer, sizeof(char), header[0].datasize, f);
-  if (Nbytes != header[0].datasize) { perror ("fwrite: "); return (FALSE);  }
+  if (Nbytes != header[0].datasize) { 
+    perror ("fwrite: "); 
+    return (FALSE);  
+  }
 
   return (TRUE);
Index: trunk/Ohana/src/libfits/test/imagecomp.c
===================================================================
--- trunk/Ohana/src/libfits/test/imagecomp.c	(revision 38543)
+++ trunk/Ohana/src/libfits/test/imagecomp.c	(revision 38553)
@@ -11,6 +11,6 @@
 int bitpix[] = {8, 16, 32, -32, -64, 0};
 
-//char *cmptype[] = {"GZIP_1", NULL};
-//int bitpix[] = {16, 0};
+// char *cmptype[] = {"NONE", NULL};
+// int bitpix[] = {16, 0};
 
 static int NX = 10;
@@ -31,4 +31,5 @@
       test_compress_fulltile (bitpix[j], cmptype[i]);
       test_compress_fullrange (bitpix[j], cmptype[i]);
+      ok (ohana_memcheck (TRUE), "no memory corruption");
     }
   }
@@ -42,4 +43,5 @@
       test_compress_fulltile (bitpix[j], cmptype[i]);
       test_compress_fullrange (bitpix[j], cmptype[i]);
+      ok (ohana_memcheck (TRUE), "no memory corruption");
     }
   }
@@ -53,4 +55,5 @@
       test_compress_fulltile (bitpix[j], cmptype[i]);
       test_compress_fullrange (bitpix[j], cmptype[i]);
+      ok (ohana_memcheck (TRUE), "no memory corruption");
     }
   }
Index: trunk/Ohana/src/libfits/test/tablecomp.c
===================================================================
--- trunk/Ohana/src/libfits/test/tablecomp.c	(revision 38543)
+++ trunk/Ohana/src/libfits/test/tablecomp.c	(revision 38553)
@@ -27,5 +27,5 @@
     test_compress_fullrange (cmptype[i]);
     test_compress_empty (cmptype[i]);
-    ok (ohana_memcheck_func (TRUE), "no memory corruption");
+    ok (ohana_memcheck (TRUE), "no memory corruption");
   }
 
Index: trunk/Ohana/src/libfits/test/tcomptiming.c
===================================================================
--- trunk/Ohana/src/libfits/test/tcomptiming.c	(revision 38543)
+++ trunk/Ohana/src/libfits/test/tcomptiming.c	(revision 38553)
@@ -29,5 +29,5 @@
     gfits_uncompress_timing();
   }
-  ok (ohana_memcheck_func (TRUE), "no memory corruption");
+  ok (ohana_memcheck (TRUE), "no memory corruption");
 
   return exit_status();
Index: trunk/Ohana/src/libohana/include/ohana.h
===================================================================
--- trunk/Ohana/src/libohana/include/ohana.h	(revision 38543)
+++ trunk/Ohana/src/libohana/include/ohana.h	(revision 38553)
@@ -333,4 +333,5 @@
 char   *SelectConfigFile       PROTO((int *argc, char **argv, char *progname));
 char   *LoadConfigFile         PROTO((char *filename));
+void    FreeConfigFile         PROTO((void));
 char   *ScanConfig             PROTO((char *config, char *field, char *mode, int N,...)) OHANA_FORMAT(scanf, 3, 5);
 char   *expandline             PROTO((char *line, char *config));
Index: trunk/Ohana/src/libohana/include/ohana_allocate.h
===================================================================
--- trunk/Ohana/src/libohana/include/ohana_allocate.h	(revision 38543)
+++ trunk/Ohana/src/libohana/include/ohana_allocate.h	(revision 38553)
@@ -1,4 +1,19 @@
 # ifndef OHANA_ALLOCATE
 # define OHANA_ALLOCATE
+
+# define OHANA_MEMMAGIC (uint32_t) 0xdeadbeef
+
+typedef struct OhanaMemblock {
+  uint32_t startblock;	      // endpost marker
+  struct OhanaMemblock *prevBlock; // previously allocated memory
+  struct OhanaMemblock *nextBlock; // next allocated memory
+  size_t size;		      // size of memory
+  const char *file;	      // file (re)allocated 
+  const char *func;	      // func (re)allocated 
+  int line;		      // line (re)allocated
+  int freed;		      // memory has been freed
+  int dummy;		      // need to put endblock on the endpost
+  uint32_t endblock;	      // endpost marker
+} OhanaMemblock;
 
 typedef struct {
@@ -29,5 +44,5 @@
 void  real_free (void *in);
 
-# define ohana_memcheck(X) ohana_memcheck_func (X);
+# define ohana_memcheck(X) ohana_memcheck_func (X)
 # define ohana_memdump(X) ohana_memdump_func (X);
 
@@ -56,5 +71,7 @@
 # else  /* below: not OHANA_MEMORY */
 
-# define ohana_memcheck(X) TRUE
+int   ohana_memcheck_noop (int mode);
+
+# define ohana_memcheck(X) ohana_memcheck_noop (X)
 # define ohana_memdump(X) /* NOP */
 void  real_free (void *in);
Index: trunk/Ohana/src/libohana/src/config.c
===================================================================
--- trunk/Ohana/src/libohana/src/config.c	(revision 38543)
+++ trunk/Ohana/src/libohana/src/config.c	(revision 38553)
@@ -7,4 +7,15 @@
 static char **DefineVariable;
 static char **DefineValue;
+
+void FreeConfigFile (void) {
+  int i;
+  for (i = 0; i < NDefineVariable; i++) {
+    free (DefineVariable[i]);
+    free (DefineValue[i]);
+  }
+  free (DefineVariable);
+  free (DefineValue);
+  free (ConfigVariable);
+}
 
 char *SelectConfigFile (int *argc, char **argv, char *progname) {
@@ -80,8 +91,10 @@
   uid = getuid();
   gid = getgid();
-  ALLOCATE (find, char, strlen(progname) + 32);
+
+  int Nchar = strlen(progname) + 32;
+  ALLOCATE (find, char, Nchar);
 
   /* look for progname.rc */
-  sprintf (find, "%s.rc", progname);
+  snprintf (find, Nchar, "%s.rc", progname);
   status = stat (find, &filestat);
   if (status == 0) { 
@@ -114,5 +127,5 @@
   if (home == (char *) NULL) { return ((char *) NULL); }
   ALLOCATE (find, char, 1024);
-  sprintf (find, "%s/.%src", home, progname);
+  snprintf (find, 1024, "%s/.%src", home, progname);
   status = stat (find, &filestat);
   if (status == 0) { 
@@ -264,6 +277,7 @@
   va_start (argp, Nentry);
 
-  ALLOCATE (tfield, char, strlen (field) + 3);
-  sprintf (tfield, "\n%s", field);
+  int Nchar = strlen (field) + 16;
+  ALLOCATE (tfield, char, Nchar);
+  snprintf (tfield, Nchar, "\n%s", field);
 
   /* we search for Nentry matching fields,
Index: trunk/Ohana/src/libohana/src/findexec.c
===================================================================
--- trunk/Ohana/src/libohana/src/findexec.c	(revision 38543)
+++ trunk/Ohana/src/libohana/src/findexec.c	(revision 38553)
@@ -113,6 +113,7 @@
   /* check permission to write to backup file */
   if (BACKUP) {
-    ALLOCATE (filename, char, strlen(basefile) + 2);
-    sprintf (filename, "%s~", basefile);
+    int Nchar = strlen(basefile) + 16;
+    ALLOCATE (filename, char, Nchar);
+    snprintf (filename, Nchar, "%s~", basefile);
     status = stat (filename, &filestat);
     if (status == 0) { /* file exists, are permissions OK? */
@@ -289,5 +290,5 @@
 	e = strchr (c, ':');
       }
-      sprintf (name, "%s/%s", path, argv[0]);
+      snprintf (name, 1024, "%s/%s", path, argv[0]);
       status = check_file_exec (name);
 
@@ -374,9 +375,9 @@
   int status, cmode;
   struct stat filestat;
-  char line[256];
+  char line[1024];
 
   status = stat (filename, &filestat);
   if (status == 0) { /* file exists, make backup copy */
-    sprintf (line, "cp %s %s~", filename, filename);
+    snprintf (line, 1024, "cp %s %s~", filename, filename);
     status = system (line);
     if (status) {
@@ -385,5 +386,5 @@
     }
     cmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
-    sprintf (line, "%s~", filename);
+    snprintf (line, 1024, "%s~", filename);
     chmod (line, cmode);
   }
Index: trunk/Ohana/src/libohana/src/gaussj.c
===================================================================
--- trunk/Ohana/src/libohana/src/gaussj.c	(revision 38543)
+++ trunk/Ohana/src/libohana/src/gaussj.c	(revision 38553)
@@ -144,4 +144,14 @@
     if (fabs(growth) > MAX_RANGE) { 
       fprintf (stderr, "max range\n"); 
+# if (VERY_VERBOSE)
+      fprintf (stderr, "full A matrix:\n");
+      for (row = 0; row < N; row++) {
+	for (col = 0; col < N; col++) {
+	  fprintf (stderr, "%10.3e ", A[row][col]);
+	}
+	fprintf (stderr, "\n");
+      }
+      fprintf (stderr, "\n");
+# endif
       goto escape;
     }
Index: trunk/Ohana/src/libohana/src/glockfile.c
===================================================================
--- trunk/Ohana/src/libohana/src/glockfile.c	(revision 38543)
+++ trunk/Ohana/src/libohana/src/glockfile.c	(revision 38553)
@@ -152,6 +152,7 @@
     path = pathname (filename);
     file = filebasename (filename);
-    ALLOCATE (lockname, char, strlen (path) + strlen (file) + 10);
-    sprintf (lockname, "%s/.%s.lck", path, file);
+    int Nchar = strlen (path) + strlen (file) + 16;
+    ALLOCATE (lockname, char, Nchar);
+    snprintf (lockname, Nchar, "%s/.%s.lck", path, file);
 
     status = stat (lockname, &filestat);
@@ -261,6 +262,7 @@
     path = pathname (filename);
     file = filebasename (filename);
-    ALLOCATE (lockname, char, strlen (path) + strlen (file) + 10);
-    sprintf (lockname, "%s/.%s.lck", path, file);
+    int Nchar = strlen (path) + strlen (file) + 16;
+    ALLOCATE (lockname, char, Nchar);
+    snprintf (lockname, Nchar, "%s/.%s.lck", path, file);
     
     /* check for lockfile existance */
Index: trunk/Ohana/src/libohana/src/ohana_allocate.c
===================================================================
--- trunk/Ohana/src/libohana/src/ohana_allocate.c	(revision 38543)
+++ trunk/Ohana/src/libohana/src/ohana_allocate.c	(revision 38553)
@@ -4,4 +4,8 @@
 # include <stdint.h>
 # include <pthread.h>
+# include <string.h>
+
+# define TEST_SAVE_FREE_BLOCKS 0
+# define TEST_SAVE_DROP_BLOCKS 0
 
 # undef OHANA_MEMORY
@@ -13,18 +17,13 @@
 # define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
 
-# define OHANA_MEMMAGIC (uint32_t) 0xdeadbeef
-
-typedef struct Memblock {
-  uint32_t startblock;	      // endpost marker
-  struct Memblock *prevBlock; // previously allocated memory
-  struct Memblock *nextBlock; // next allocated memory
-  size_t size;		      // size of memory
-  const char *file;	      // file (re)allocated 
-  const char *func;	      // func (re)allocated 
-  int line;		      // line (re)allocated
-  uint32_t endblock;	      // endpost marker
-} Memblock;
-
-static Memblock *lastBlock = NULL;
+static OhanaMemblock *lastBlock = NULL;
+
+# if (TEST_SAVE_FREE_BLOCKS) 
+static OhanaMemblock *freeBlock = NULL;
+# endif
+
+# if (TEST_SAVE_DROP_BLOCKS) 
+static OhanaMemblock *dropBlock = NULL;
+# endif
 
 static pthread_mutex_t memBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
@@ -46,5 +45,5 @@
 
   void *ptr;		      // actual user memory allocated
-  Memblock *new;	      // new memblock created to track the user memory
+  OhanaMemblock *new;	      // new memblock created to track the user memory
   size_t size;		      // total number of bytes requested (not items)
 
@@ -53,5 +52,5 @@
 
   // total size is : memblock + data + endpost
-  new = (Memblock *) malloc (sizeof(Memblock) + size + sizeof(void *)); 
+  new = (OhanaMemblock *) malloc (sizeof(OhanaMemblock) + size + sizeof(void *)); 
   if (new == NULL) ohana_memabort ("failed to allocate memory (%s, %d, %s)\n", file, line, func);
 
@@ -69,4 +68,8 @@
   new->line = line;
   new->func = func;
+  new->freed = FALSE;
+
+  // to be clean, zero out the memory
+  // memset (ptr, 0, new->size);
 
   // new memblock becomes the 'lastBlock':
@@ -99,17 +102,16 @@
 void *ohana_realloc (const char *file, int line, const char *func, void *in, size_t Nelem, size_t esize) {
 
-  void *ptr;		      // actual user memory allocated
-  Memblock *old;	      // original memblock associated with user memory
-  Memblock *new;	      // new memblock associated with user memory
+  OhanaMemblock *old;	      // original memblock associated with user memory
+  OhanaMemblock *new;	      // new memblock associated with user memory
   size_t size;
 
   // just allocate if not previously allocated
   if (!in) {
-    ptr = ohana_malloc (file, line, func, Nelem, esize);
+    void *ptr = ohana_malloc (file, line, func, Nelem, esize);
     return ptr;
   }
 
   // memblock of supplied pointer
-  old = (Memblock *) in - 1;
+  old = (OhanaMemblock *) in - 1;
 
   if (old->startblock != OHANA_MEMMAGIC) ohana_memabort ("corrupt memory (%s, %d, %s)\n", file, line, func);
@@ -126,23 +128,45 @@
   pthread_mutex_lock(&memBlockListMutex);
 
-  Memblock *nextBlock = old->nextBlock;
-  Memblock *prevBlock = old->prevBlock;
+  OhanaMemblock *nextBlock = old->nextBlock;
+  OhanaMemblock *prevBlock = old->prevBlock;
 
   int isLast = (old == lastBlock);
 
+  // ask for new memory
+
+# if (TEST_SAVE_DROP_BLOCKS) 
+  // XXX for a test, we are going to always alloc a new block, copy the old data to the new block
+  // poison the old block, then free it
+  new = (OhanaMemblock *) malloc (sizeof(OhanaMemblock) + size + sizeof(void *));
+  if (new == NULL) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
+  void *ptr_new = (char *) (new + 1);
+  void *ptr_old = (char *) (old + 1);
+  size_t copy_bytes = old->size < size ? old->size : size;
+  memcpy (ptr_new, ptr_old, copy_bytes);
+  memset (ptr_old, 0x7f, old->size);
+  new->nextBlock = old->nextBlock;
+  new->prevBlock = old->prevBlock;
+# else
   // ask for new memory
   // total size is : memblock + data + endpost
-  new = (Memblock *) realloc (old, sizeof(Memblock) + size + sizeof(void *));
+  new = (OhanaMemblock *) realloc (old, sizeof(OhanaMemblock) + size + sizeof(void *));
   if (new == NULL) ohana_memabort ("failed to reallocate memory (%s, %d, %s)\n", file, line, func);
-  ptr = (char *) (new + 1);
-  
-  // give the realloc location:
+  void *ptr_new = (char *) (new + 1);
+# endif
+  
+  // set the end-post values
+  new->startblock = OHANA_MEMMAGIC;
+  new->endblock = OHANA_MEMMAGIC;
+  *(uint32_t *)(ptr_new + size) = OHANA_MEMMAGIC;
+
+  // set the memory metadata
   new->size = size; 
   new->file = file;
   new->line = line;
   new->func = func;
+  new->freed = FALSE;
 
   // update the endpost (the others were set originally
-  *(uint32_t *)(ptr + size) = OHANA_MEMMAGIC;
+  *(uint32_t *)(ptr_new + size) = OHANA_MEMMAGIC;
 
   // need to reset lastBlock in case we moved
@@ -159,7 +183,17 @@
   }
   
+  // XXX FOR TESTING, save the realloc blocks
+# if (TEST_SAVE_DROP_BLOCKS)
+  if (dropBlock) {
+    dropBlock->nextBlock = old;
+  }
+  old->nextBlock = NULL;
+  old->prevBlock = dropBlock;
+  dropBlock = old;
+# endif
+
   pthread_mutex_unlock(&memBlockListMutex);
 
-  return (ptr);
+  return (ptr_new);
 }
 
@@ -174,5 +208,5 @@
 void ohana_free (const char *file, int line, const char *func, void *in) {
 
-  Memblock *ref;
+  OhanaMemblock *ref;
 
   if (!in) return;
@@ -180,5 +214,8 @@
   // fprintf (stderr, "free %zx\n", (size_t) in);
 
-  ref = (Memblock *) in - 1;
+  ref = (OhanaMemblock *) in - 1;
+
+  if (ref->freed) ohana_memabort ("memory already freed (%s, %d, %s [%d bytes])\n", ref->file, ref->line, ref->func, ref->size);
+  ref->freed = TRUE;
 
   // fprintf (stderr, "  file: %s, line: %d, func: %s, size: %zd, addr: %zx\n", 
@@ -187,7 +224,8 @@
   pthread_mutex_lock(&memBlockListMutex);
   
-  Memblock *nextBlock = ref->nextBlock;
-  Memblock *prevBlock = ref->prevBlock;
-
+  OhanaMemblock *nextBlock = ref->nextBlock;
+  OhanaMemblock *prevBlock = ref->prevBlock;
+
+  // remove this memBlock from the list
   if (nextBlock) {
     nextBlock->prevBlock = prevBlock;
@@ -200,9 +238,29 @@
   }
   
+  // XXX FOR TESTING, save the freed blocks
+# if (TEST_SAVE_FREE_BLOCKS)
+  if (freeBlock) {
+    freeBlock->nextBlock = ref;
+  }
+  ref->nextBlock = NULL;
+  ref->prevBlock = freeBlock;
+  freeBlock = ref;
+# endif
+
+  // pointer to the start of the user memory
+  void *ptr = (char *)(ref + 1);
+  memset (ptr, 0x77, ref->size);
+
   pthread_mutex_unlock(&memBlockListMutex);
   
+# if (!TEST_SAVE_FREE_BLOCKS)
   free (ref);
+# endif
 
   return;
+}
+
+int ohana_memcheck_noop (int allmemory) {
+  return TRUE;
 }
 
@@ -211,8 +269,7 @@
   if (!lastBlock) {
     fprintf (stderr, "no memory allocated\n");
-    return TRUE;
-  }
-
-  Memblock *thisBlock = lastBlock;
+  }
+
+  OhanaMemblock *thisBlock = lastBlock;
 
   size_t Ngood  = 0;
@@ -220,4 +277,5 @@
   size_t Ntotal = 0;
   size_t Nbytes = 0;
+  int status = TRUE;
 
   while (thisBlock) {
@@ -250,9 +308,106 @@
     thisBlock = thisBlock->prevBlock;
   }
+  fprintf (stderr, "%zd memory blocks allocated (%zd bytes total), %zd good, %zd bad\n", Ntotal, Nbytes, Ngood, Nbad);
+  if (Nbad) status = FALSE;
+
+# if (TEST_SAVE_FREE_BLOCKS) 
  
-  fprintf (stderr, "%zd memory blocks allocated (%zd bytes total), %zd good, %zd bad\n", Ntotal, Nbytes, Ngood, Nbad);
-
-  if (Nbad) return FALSE;
-  return TRUE;
+  thisBlock = freeBlock;
+
+  size_t Ngood_free  = 0;
+  size_t Nbad_free   = 0;
+  size_t Ntotal_free = 0;
+  size_t Nbytes_free = 0;
+
+  while (thisBlock) {
+
+    int i;
+    int good = TRUE;
+    
+    if (thisBlock->startblock != OHANA_MEMMAGIC) good = FALSE;
+    if (thisBlock->endblock != OHANA_MEMMAGIC) good = FALSE;
+
+    // pointer to the end of the user memory
+    char *ptr = (char *)(thisBlock + 1) + thisBlock->size;
+    uint32_t endpost = *(uint32_t *)ptr;
+    if (endpost != OHANA_MEMMAGIC) good = FALSE;
+
+    // pointer to the start of the user memory
+    ptr = (char *)(thisBlock + 1);
+    for (i = 0; i < thisBlock->size; i++, ptr++) {
+      if (*ptr != 0x77) good = FALSE;
+    }
+
+    // XXX keep checking even if memory is corrupted?
+    if (!good) {
+      if (Nbad_free < 1) {
+	fprintf (stderr, "memory corruption\n");
+      }
+      if (Nbad_free < 100) {
+	fprintf (stderr, "  file: %s, line: %d, func: %s\n", thisBlock->file, thisBlock->line, thisBlock->func);
+      }
+      Nbad_free ++;
+    } else {
+      Ngood_free ++;
+    }
+    Ntotal_free ++;
+    Nbytes_free += thisBlock->size;
+
+    thisBlock = thisBlock->prevBlock;
+  }
+  fprintf (stderr, "%zd memory blocks freed     (%zd bytes total), %zd good, %zd bad\n", Ntotal_free, Nbytes_free, Ngood_free, Nbad_free);
+  if (Nbad_free) status = FALSE;
+
+# endif
+ 
+# if (TEST_SAVE_DROP_BLOCKS)
+  thisBlock = dropBlock;
+
+  size_t Ngood_drop  = 0;
+  size_t Nbad_drop   = 0;
+  size_t Ntotal_drop = 0;
+  size_t Nbytes_drop = 0;
+
+  while (thisBlock) {
+
+    int i;
+    int good = TRUE;
+    
+    if (thisBlock->startblock != OHANA_MEMMAGIC) good = FALSE;
+    if (thisBlock->endblock != OHANA_MEMMAGIC) good = FALSE;
+
+    // pointer to the end of the user memory
+    char *ptr = (char *)(thisBlock + 1) + thisBlock->size;
+    uint32_t endpost = *(uint32_t *)ptr;
+    if (endpost != OHANA_MEMMAGIC) good = FALSE;
+
+    // pointer to the start of the user memory
+    ptr = (char *)(thisBlock + 1);
+    for (i = 0; i < thisBlock->size; i++, ptr++) {
+      if (*ptr != 0x7f) good = FALSE;
+    }
+
+    // XXX keep checking even if memory is corrupted?
+    if (!good) {
+      if (Nbad_drop < 1) {
+	fprintf (stderr, "memory corruption\n");
+      }
+      if (Nbad_drop < 100) {
+	fprintf (stderr, "  file: %s, line: %d, func: %s\n", thisBlock->file, thisBlock->line, thisBlock->func);
+      }
+      Nbad_drop ++;
+    } else {
+      Ngood_drop ++;
+    }
+    Ntotal_drop ++;
+    Nbytes_drop += thisBlock->size;
+
+    thisBlock = thisBlock->prevBlock;
+  }
+  fprintf (stderr, "%zd memory blocks dropped   (%zd bytes total), %zd good, %zd bad\n", Ntotal_drop, Nbytes_drop, Ngood_drop, Nbad_drop);
+  if (Nbad_drop) status = FALSE;
+# endif
+ 
+  return status;
 }
 
@@ -264,5 +419,5 @@
   }
 
-  Memblock *thisBlock = lastBlock;
+  OhanaMemblock *thisBlock = lastBlock;
 
   size_t Ntotal = 0;
@@ -312,5 +467,5 @@
   memstats.Nbad = 0;
   
-  Memblock *thisBlock = lastBlock;
+  OhanaMemblock *thisBlock = lastBlock;
 
   while (thisBlock) {
Index: trunk/Ohana/src/libohana/src/time.c
===================================================================
--- trunk/Ohana/src/libohana/src/time.c	(revision 38543)
+++ trunk/Ohana/src/libohana/src/time.c	(revision 38553)
@@ -141,5 +141,5 @@
       ALLOCATE (tmpline, char, 64);
       gmt   = gmtime (&tsec);
-      sprintf (tmpline, "%04d/%02d/%02d,%s", 1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, &line[6]);
+      snprintf (tmpline, 64, "%04d/%02d/%02d,%s", 1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, &line[6]);
       *second = ohana_date_to_sec (tmpline);
       free (tmpline);
@@ -251,5 +251,5 @@
   ALLOCATE (line, char, 64);
   gmt   = gmtime (&second);
-  sprintf (line, "%04d/%02d/%02d,%02d:%02d:%02d", 1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+  snprintf (line, 64, "%04d/%02d/%02d,%02d:%02d:%02d", 1900 + gmt[0].tm_year, gmt[0].tm_mon+1, gmt[0].tm_mday, gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
   return (line);
 
Index: trunk/Ohana/src/opihi/cmd.astro/radec.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/radec.c	(revision 38543)
+++ trunk/Ohana/src/opihi/cmd.astro/radec.c	(revision 38553)
@@ -45,6 +45,6 @@
 
   // convert to hms, dms
-  hms_format (ra_string, ra/15.0);
-  hms_format (dec_string, dec);
+  hms_format (ra_string, 32, ra/15.0);
+  hms_format (dec_string, 32, dec);
 
   set_str_variable ("RA", ra_string);
Index: trunk/Ohana/src/opihi/cmd.astro/sexigesimal.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.astro/sexigesimal.c	(revision 38543)
+++ trunk/Ohana/src/opihi/cmd.astro/sexigesimal.c	(revision 38553)
@@ -35,5 +35,5 @@
   } else {
     value = atof (argv[1]);
-    hms_format (string, value);
+    hms_format (string, 80, value);
     if (argc == 3) {
       set_str_variable (argv[2], string);
Index: trunk/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 38543)
+++ trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 38553)
@@ -77,4 +77,14 @@
   if ((argc < 3) || !(argc % 2)) {
     gprint (GP_ERR, "USAGE: read name N name N ...\n");
+    gprint (GP_ERR, "  options:\n");
+    gprint (GP_ERR, "     -fits EXTNAME : read a fits file from the given extension (vector names are column names)\n");
+    gprint (GP_ERR, "     -v : verbose mode\n");
+    gprint (GP_ERR, "     -csv : comma-separated values (columns may be identified in excel-style: A, AC\n");
+    gprint (GP_ERR, "     -skip N : skip N lines before reading\n");
+    gprint (GP_ERR, "     column names may include a type: name:type\n");
+    gprint (GP_ERR, "       type is int, float, char, time\n");
+    gprint (GP_ERR, "       for char, values are placed into a list $name:0 - $name:n\n");
+    gprint (GP_ERR, "       for time, values are human-readable date/time strings YYYY/MM/DD,hh:mm:ss\n");
+    gprint (GP_ERR, "       the resulting vector is a float based on the TIMEFORMAT, TIMEREF values\n");
     return (FALSE);
   }
Index: trunk/Ohana/src/opihi/dimm/telescope_cmds.c
===================================================================
--- trunk/Ohana/src/opihi/dimm/telescope_cmds.c	(revision 38543)
+++ trunk/Ohana/src/opihi/dimm/telescope_cmds.c	(revision 38553)
@@ -87,7 +87,7 @@
     set_variable ("RA", ra);
     set_variable ("DEC", dec);
-    dms_format (line, (ra/15.0));
+    dms_format (line, 64, (ra/15.0));
     set_str_variable ("Rs", line);
-    dms_format (line, dec);
+    dms_format (line, 64, dec);
     set_str_variable ("Ds", line);
 
Index: trunk/Ohana/src/opihi/lib.shell/stack_math.c
===================================================================
--- trunk/Ohana/src/opihi/lib.shell/stack_math.c	(revision 38543)
+++ trunk/Ohana/src/opihi/lib.shell/stack_math.c	(revision 38553)
@@ -32,10 +32,10 @@
 
   switch (op[0]) {
-  case '?': SSS_FUNC(M1 ? M2: M3);
-  default:
-    snprintf (line, 512, "error: op %c not defined!", op[0]);
-    push_error (line);
-    return (FALSE);
-}
+    case '?': SSS_FUNC(M1 ? M2: M3);
+    default:
+      snprintf (line, 512, "error: op %c not defined!", op[0]);
+      push_error (line);
+      return (FALSE);
+  }
 # undef SSS_FUNC
 
@@ -447,36 +447,36 @@
 
   switch (op[0]) { 
-  case '+': SV_FUNC(ST_SCALAR_INT, M1 + *M2);
-  case '-': SV_FUNC(ST_SCALAR_INT, M1 - *M2);
-  case '*': SV_FUNC(ST_SCALAR_INT, M1 * *M2);
-  case '/': SV_FUNC(ST_SCALAR_FLT, M1 / (opihi_flt) *M2);
-  case '%': SV_FUNC(ST_SCALAR_INT, (long long) M1 % (long long) *M2);
-  case '^': SV_FUNC(ST_SCALAR_FLT, pow (M1, *M2));
-  case '@': SV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, *M2));
-  case 'a': SV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, *M2));
-  case 'D': SV_FUNC(ST_SCALAR_INT, MIN (M1, *M2));
-  case 'U': SV_FUNC(ST_SCALAR_INT, MAX (M1, *M2));
-  case '<': SV_FUNC(ST_SCALAR_INT, (M1 < *M2) ? 1 : 0);
-  case '>': SV_FUNC(ST_SCALAR_INT, (M1 > *M2) ? 1 : 0);
-  case '&': SV_FUNC(ST_SCALAR_INT, ((long long)M1 & (long long)*M2));
-  case '|': SV_FUNC(ST_SCALAR_INT, ((long long)M1 | (long long)*M2));
-  case 'E': SV_FUNC(ST_SCALAR_INT, (M1 == *M2) ? 1 : 0);
-  case 'N': SV_FUNC(ST_SCALAR_INT, (M1 != *M2) ? 1 : 0);
-  case 'L': SV_FUNC(ST_SCALAR_INT, (M1 <= *M2) ? 1 : 0);
-  case 'G': SV_FUNC(ST_SCALAR_INT, (M1 >= *M2) ? 1 : 0);
-  case 'A': SV_FUNC(ST_SCALAR_INT, (M1 && *M2) ? 1 : 0);
-  case 'O': SV_FUNC(ST_SCALAR_INT, (M1 || *M2) ? 1 : 0);
-  default:
-    snprintf (line, 512, "error: op %c not defined!", op[0]);
-    push_error (line);
-    return (FALSE);
-}
+    case '+': SV_FUNC(ST_SCALAR_INT, M1 + *M2);
+    case '-': SV_FUNC(ST_SCALAR_INT, M1 - *M2);
+    case '*': SV_FUNC(ST_SCALAR_INT, M1 * *M2);
+    case '/': SV_FUNC(ST_SCALAR_FLT, M1 / (opihi_flt) *M2);
+    case '%': SV_FUNC(ST_SCALAR_INT, (long long) M1 % (long long) *M2);
+    case '^': SV_FUNC(ST_SCALAR_FLT, pow (M1, *M2));
+    case '@': SV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, *M2));
+    case 'a': SV_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, *M2));
+    case 'D': SV_FUNC(ST_SCALAR_INT, MIN (M1, *M2));
+    case 'U': SV_FUNC(ST_SCALAR_INT, MAX (M1, *M2));
+    case '<': SV_FUNC(ST_SCALAR_INT, (M1 < *M2) ? 1 : 0);
+    case '>': SV_FUNC(ST_SCALAR_INT, (M1 > *M2) ? 1 : 0);
+    case '&': SV_FUNC(ST_SCALAR_INT, ((long long)M1 & (long long)*M2));
+    case '|': SV_FUNC(ST_SCALAR_INT, ((long long)M1 | (long long)*M2));
+    case 'E': SV_FUNC(ST_SCALAR_INT, (M1 == *M2) ? 1 : 0);
+    case 'N': SV_FUNC(ST_SCALAR_INT, (M1 != *M2) ? 1 : 0);
+    case 'L': SV_FUNC(ST_SCALAR_INT, (M1 <= *M2) ? 1 : 0);
+    case 'G': SV_FUNC(ST_SCALAR_INT, (M1 >= *M2) ? 1 : 0);
+    case 'A': SV_FUNC(ST_SCALAR_INT, (M1 && *M2) ? 1 : 0);
+    case 'O': SV_FUNC(ST_SCALAR_INT, (M1 || *M2) ? 1 : 0);
+    default:
+      snprintf (line, 512, "error: op %c not defined!", op[0]);
+      push_error (line);
+      return (FALSE);
+  }
 # undef SV_FUNC
 
   /** free up any temporary buffers: **/
   if (V2[0].type == ST_VECTOR_TMP) {
-  free (V2[0].vector[0].elements.Ptr);
-  free (V2[0].vector);
-}
+    free (V2[0].vector[0].elements.Ptr);
+    free (V2[0].vector);
+  }
 
   clear_stack (V1);
@@ -554,29 +554,29 @@
 
   switch (op[0]) { 
-  case '+': VS_FUNC(ST_SCALAR_INT, *M1 + M2);
-  case '-': VS_FUNC(ST_SCALAR_INT, *M1 - M2);
-  case '*': VS_FUNC(ST_SCALAR_INT, *M1 * M2);
-  case '/': VS_FUNC(ST_SCALAR_FLT, *M1 / (opihi_flt) M2);
-  case '%': VS_FUNC(ST_SCALAR_INT, (long long) *M1 % (long long) M2);
-  case '^': VS_FUNC(ST_SCALAR_FLT, pow (*M1, M2));
-  case '@': VS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, M2));
-  case 'a': VS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, M2));
-  case 'D': VS_FUNC(ST_SCALAR_INT, MIN (*M1, M2));
-  case 'U': VS_FUNC(ST_SCALAR_INT, MAX (*M1, M2));
-  case '<': VS_FUNC(ST_SCALAR_INT, (*M1 < M2) ? 1 : 0);
-  case '>': VS_FUNC(ST_SCALAR_INT, (*M1 > M2) ? 1 : 0);
-  case '&': VS_FUNC(ST_SCALAR_INT, ((long long)*M1 & (long long)M2));
-  case '|': VS_FUNC(ST_SCALAR_INT, ((long long)*M1 | (long long)M2));
-  case 'E': VS_FUNC(ST_SCALAR_INT, (*M1 == M2) ? 1 : 0);
-  case 'N': VS_FUNC(ST_SCALAR_INT, (*M1 != M2) ? 1 : 0);
-  case 'L': VS_FUNC(ST_SCALAR_INT, (*M1 <= M2) ? 1 : 0);
-  case 'G': VS_FUNC(ST_SCALAR_INT, (*M1 >= M2) ? 1 : 0);
-  case 'A': VS_FUNC(ST_SCALAR_INT, (*M1 && M2) ? 1 : 0);
-  case 'O': VS_FUNC(ST_SCALAR_INT, (*M1 || M2) ? 1 : 0);
-  default:
-    snprintf (line, 512, "error: op %c not defined!", op[0]);
-    push_error (line);
-    return (FALSE);
-}
+    case '+': VS_FUNC(ST_SCALAR_INT, *M1 + M2);
+    case '-': VS_FUNC(ST_SCALAR_INT, *M1 - M2);
+    case '*': VS_FUNC(ST_SCALAR_INT, *M1 * M2);
+    case '/': VS_FUNC(ST_SCALAR_FLT, *M1 / (opihi_flt) M2);
+    case '%': VS_FUNC(ST_SCALAR_INT, (long long) *M1 % (long long) M2);
+    case '^': VS_FUNC(ST_SCALAR_FLT, pow (*M1, M2));
+    case '@': VS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, M2));
+    case 'a': VS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (*M1, M2));
+    case 'D': VS_FUNC(ST_SCALAR_INT, MIN (*M1, M2));
+    case 'U': VS_FUNC(ST_SCALAR_INT, MAX (*M1, M2));
+    case '<': VS_FUNC(ST_SCALAR_INT, (*M1 < M2) ? 1 : 0);
+    case '>': VS_FUNC(ST_SCALAR_INT, (*M1 > M2) ? 1 : 0);
+    case '&': VS_FUNC(ST_SCALAR_INT, ((long long)*M1 & (long long)M2));
+    case '|': VS_FUNC(ST_SCALAR_INT, ((long long)*M1 | (long long)M2));
+    case 'E': VS_FUNC(ST_SCALAR_INT, (*M1 == M2) ? 1 : 0);
+    case 'N': VS_FUNC(ST_SCALAR_INT, (*M1 != M2) ? 1 : 0);
+    case 'L': VS_FUNC(ST_SCALAR_INT, (*M1 <= M2) ? 1 : 0);
+    case 'G': VS_FUNC(ST_SCALAR_INT, (*M1 >= M2) ? 1 : 0);
+    case 'A': VS_FUNC(ST_SCALAR_INT, (*M1 && M2) ? 1 : 0);
+    case 'O': VS_FUNC(ST_SCALAR_INT, (*M1 || M2) ? 1 : 0);
+    default:
+      snprintf (line, 512, "error: op %c not defined!", op[0]);
+      push_error (line);
+      return (FALSE);
+  }
 # undef VS_FUNC
 
@@ -584,7 +584,7 @@
 
   if (V1[0].type == ST_VECTOR_TMP) {
-  free (V1[0].vector[0].elements.Ptr);
-  free (V1[0].vector);
-}
+    free (V1[0].vector[0].elements.Ptr);
+    free (V1[0].vector);
+  }
 
   clear_stack (V1);
@@ -1061,29 +1061,29 @@
 
   switch (op[0]) { 
-  case '+': SS_FUNC(ST_SCALAR_INT, M1 + M2);
-  case '-': SS_FUNC(ST_SCALAR_INT, M1 - M2);
-  case '*': SS_FUNC(ST_SCALAR_INT, M1 * M2);
-  case '/': SS_FUNC(ST_SCALAR_FLT, M1 / (opihi_flt) M2);
-  case '%': SS_FUNC(ST_SCALAR_INT, (long long) M1 % (long long) M2);
-  case '^': SS_FUNC(ST_SCALAR_FLT, pow (M1, M2));
-  case '@': SS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, M2));
-  case 'a': SS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, M2));
-  case 'D': SS_FUNC(ST_SCALAR_INT, MIN (M1, M2));
-  case 'U': SS_FUNC(ST_SCALAR_INT, MAX (M1, M2));
-  case '<': SS_FUNC(ST_SCALAR_INT, (M1 < M2) ? 1 : 0);
-  case '>': SS_FUNC(ST_SCALAR_INT, (M1 > M2) ? 1 : 0);
-  case '&': SS_FUNC(ST_SCALAR_INT, ((long long)M1 & (long long)M2));
-  case '|': SS_FUNC(ST_SCALAR_INT, ((long long)M1 | (long long)M2));
-  case 'E': SS_FUNC(ST_SCALAR_INT, (M1 == M2) ? 1 : 0);
-  case 'N': SS_FUNC(ST_SCALAR_INT, (M1 != M2) ? 1 : 0);
-  case 'L': SS_FUNC(ST_SCALAR_INT, (M1 <= M2) ? 1 : 0);
-  case 'G': SS_FUNC(ST_SCALAR_INT, (M1 >= M2) ? 1 : 0);
-  case 'A': SS_FUNC(ST_SCALAR_INT, (M1 && M2) ? 1 : 0);
-  case 'O': SS_FUNC(ST_SCALAR_INT, (M1 || M2) ? 1 : 0);
-  default:
-    snprintf (line, 512, "error: op %c not defined!", op[0]);
-    push_error (line);
-    return (FALSE);
-}
+    case '+': SS_FUNC(ST_SCALAR_INT, M1 + M2);
+    case '-': SS_FUNC(ST_SCALAR_INT, M1 - M2);
+    case '*': SS_FUNC(ST_SCALAR_INT, M1 * M2);
+    case '/': SS_FUNC(ST_SCALAR_FLT, M1 / (opihi_flt) M2);
+    case '%': SS_FUNC(ST_SCALAR_INT, (long long) M1 % (long long) M2);
+    case '^': SS_FUNC(ST_SCALAR_FLT, pow (M1, M2));
+    case '@': SS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, M2));
+    case 'a': SS_FUNC(ST_SCALAR_FLT, DEG_RAD*atan2 (M1, M2));
+    case 'D': SS_FUNC(ST_SCALAR_INT, MIN (M1, M2));
+    case 'U': SS_FUNC(ST_SCALAR_INT, MAX (M1, M2));
+    case '<': SS_FUNC(ST_SCALAR_INT, (M1 < M2) ? 1 : 0);
+    case '>': SS_FUNC(ST_SCALAR_INT, (M1 > M2) ? 1 : 0);
+    case '&': SS_FUNC(ST_SCALAR_INT, ((long long)M1 & (long long)M2));
+    case '|': SS_FUNC(ST_SCALAR_INT, ((long long)M1 | (long long)M2));
+    case 'E': SS_FUNC(ST_SCALAR_INT, (M1 == M2) ? 1 : 0);
+    case 'N': SS_FUNC(ST_SCALAR_INT, (M1 != M2) ? 1 : 0);
+    case 'L': SS_FUNC(ST_SCALAR_INT, (M1 <= M2) ? 1 : 0);
+    case 'G': SS_FUNC(ST_SCALAR_INT, (M1 >= M2) ? 1 : 0);
+    case 'A': SS_FUNC(ST_SCALAR_INT, (M1 && M2) ? 1 : 0);
+    case 'O': SS_FUNC(ST_SCALAR_INT, (M1 || M2) ? 1 : 0);
+    default:
+      snprintf (line, 512, "error: op %c not defined!", op[0]);
+      push_error (line);
+      return (FALSE);
+  }
 # undef SS_FUNC
 
@@ -1133,8 +1133,8 @@
     case 'E': 
       value = strcmp (V1[0].name, V2[0].name) ? 0 : 1;
-    break; 
+      break; 
     case 'N': 
       value = strcmp (V1[0].name, V2[0].name) ? 1 : 0;
-    break; 
+      break; 
     default:
       snprintf (line, 512, "error: op %c not defined for string operations!", op[0]);
Index: trunk/Ohana/src/relastro/src/BrightCatalog.c
===================================================================
--- trunk/Ohana/src/relastro/src/BrightCatalog.c	(revision 38543)
+++ trunk/Ohana/src/relastro/src/BrightCatalog.c	(revision 38553)
@@ -349,8 +349,8 @@
   /*** MeasureTiny ***/
   {
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
     gfits_create_table_header (&theader, "BINTABLE", "MEASURE_TINY");
 
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
     gfits_define_bintable_column (&theader, "D", "RA",       "ra",                         "degrees", 1.0, 0.0);
     gfits_define_bintable_column (&theader, "D", "DEC",      "dec",                        "degrees", 1.0, 0.0);
@@ -375,7 +375,7 @@
 
     // generate the output array that carries the data
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
     gfits_create_table (&theader, &ftable);
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
 
     // create intermediate storage arrays
@@ -400,5 +400,5 @@
     int    *catID     ; ALLOCATE (catID    ,  int  ,  catalog->Nmeasure);
     short  *photcode  ; ALLOCATE (photcode ,  short,  catalog->Nmeasure);
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
 
     // assign the storage arrays
@@ -426,11 +426,11 @@
       photcode[i] = measure[i].photcode ;
     }
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
 
     // add the columns to the output array
     gfits_set_bintable_column (&theader, &ftable, "RA",   	R,         catalog->Nmeasure);
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
     gfits_set_bintable_column (&theader, &ftable, "DEC",  	D,         catalog->Nmeasure);
-    ohana_memcheck_func (1);
+    ohana_memcheck (1);
     gfits_set_bintable_column (&theader, &ftable, "ROFF_GAL",   RoffGAL,   catalog->Nmeasure);
     gfits_set_bintable_column (&theader, &ftable, "DOFF_GAL",   DoffGAL,   catalog->Nmeasure);
Index: trunk/Ohana/src/relastro/src/FrameCorrectionUtils.c
===================================================================
--- trunk/Ohana/src/relastro/src/FrameCorrectionUtils.c	(revision 38543)
+++ trunk/Ohana/src/relastro/src/FrameCorrectionUtils.c	(revision 38553)
@@ -62,5 +62,5 @@
     ALLOCATE (frame->Roff[i], double, frame->Nra[i]);
     ALLOCATE (frame->Doff[i], double, frame->Nra[i]);
-    // ohana_memcheck_func (TRUE);
+    // ohana_memcheck (TRUE);
     // fprintf (stderr, "alloc : %d : %lx %lx\n", i, (long unsigned int)(size_t *) frame->Roff[i], (long unsigned int) (size_t *) frame->Doff[i]);
   }
