Index: trunk/Ohana/src/libdvo/Makefile
===================================================================
--- trunk/Ohana/src/libdvo/Makefile	(revision 31496)
+++ trunk/Ohana/src/libdvo/Makefile	(revision 31635)
@@ -36,5 +36,5 @@
 $(DESTINC)/ps1_ref_defs.h
 
-INCS = $(DEFS) $(DESTINC)/dvo.h $(DESTINC)/autocode.h $(DESTINC)/dvo_util.h
+INCS = $(DEFS) $(DESTINC)/dvo.h $(DESTINC)/autocode.h $(DESTINC)/dvo_util.h $(DESTINC)/dvodb.h $(DESTINC)/libdvo_astro.h $(DESTINC)/convert.h
 
 OBJS = \
@@ -73,7 +73,27 @@
 $(SRC)/skyregion_gsc.$(ARCH).o    \
 $(SRC)/skyregion_ops.$(ARCH).o \
+$(SRC)/dvo_set_skyregion.$(ARCH).o \
+$(SRC)/dvo_set_catdir.$(ARCH).o \
 $(SRC)/cmf-ps1-v1-alt.$(ARCH).o \
 $(SRC)/cmf-ps1-sv1-alt.$(ARCH).o \
-$(SRC)/dvo_util.$(ARCH).o
+$(SRC)/dvo_util.$(ARCH).o \
+$(SRC)/dbBooleanCond.$(ARCH).o		\
+$(SRC)/dbCheckStack.$(ARCH).o		\
+$(SRC)/dbCmdlineFields.$(ARCH).o	\
+$(SRC)/dbExtractAverages.$(ARCH).o	\
+$(SRC)/dbExtractMeasures.$(ARCH).o	\
+$(SRC)/dbExtractImages.$(ARCH).o	\
+$(SRC)/dbFields.$(ARCH).o	\
+$(SRC)/dbRPN.$(ARCH).o			\
+$(SRC)/dbStackMath.$(ARCH).o		\
+$(SRC)/dbStackOps.$(ARCH).o 		\
+$(SRC)/coord_systems.$(ARCH).o		\
+$(SRC)/LoadImages.$(ARCH).o		\
+$(SRC)/ImageSelection.$(ARCH).o		\
+$(SRC)/ImageOps.$(ARCH).o		\
+$(SRC)/match_image.$(ARCH).o		\
+$(SRC)/db_utils.$(ARCH).o		\
+$(SRC)/convert.$(ARCH).o
+
 
 # $(SRC)/dvo_convert_panstarrs.$(ARCH).o 
Index: trunk/Ohana/src/libdvo/include/convert.h
===================================================================
--- trunk/Ohana/src/libdvo/include/convert.h	(revision 31635)
+++ trunk/Ohana/src/libdvo/include/convert.h	(revision 31635)
@@ -0,0 +1,28 @@
+// # include "external.h"
+
+#include <ohana.h>
+#include <dvo.h>
+
+# ifndef CONVERT_H
+# define CONVERT_H
+
+/*** time/coord conversion functions not supplied by libohana ***/
+time_t        TimeRef               PROTO((double time, time_t TimeReference, int TimeFormat));
+double        TimeValue             PROTO((time_t time, time_t TimeReference, int TimeFormat));
+
+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           hh_hm                 PROTO((double hh, int *hr, double *mn));
+int           day_to_sec            PROTO((char *string, time_t *second));
+int           hms_to_sec            PROTO((char *string, time_t *second));
+char         *ohana_sec_to_hms      PROTO((time_t second));
+char         *ohana_sec_to_day      PROTO((time_t second));
+
+char         *meade_deg_to_str      PROTO((double deg));
+char         *meade_ra_to_str       PROTO((double deg));
+char         *meade_dec_to_str      PROTO((double deg));
+char         *strptime              PROTO((const char *s, const char *format, struct tm *tm));
+
+# endif
Index: trunk/Ohana/src/libdvo/include/dvo.h
===================================================================
--- trunk/Ohana/src/libdvo/include/dvo.h	(revision 31496)
+++ trunk/Ohana/src/libdvo/include/dvo.h	(revision 31635)
@@ -1,8 +1,11 @@
+# ifndef DVO_H
+# define DVO_H
+
 # include <ohana.h>
 # include <gfitsio.h>
 # include <autocode.h>
 
-# ifndef DVO_H
-# define DVO_H
+# include <libdvo_astro.h>
+# include <dvodb.h>
 
 /* DVO table modes */
@@ -501,4 +504,10 @@
 SkyList   *SkyListChildrenByBounds_List PROTO((SkyList *table, int depth, double Rmin, double Rmax, double Dmin, double Dmax));
 
+int set_skyregion(double Rs, double Re, double Ds, double De);
+int get_skyregion (double *Rs, double *Re, double *Ds, double *De);
+
+void dvo_set_catdir(char *catdir);
+char *dvo_get_catdir();
+
 /* dvo-specific sorting functions */
 void sortave (Average *ave, off_t N);
@@ -508,3 +517,9 @@
 void sort_regions (SkyRegion *region, off_t N);
 
+#ifdef MOVED_TO_LIBOHANA
+int  print_error(void);
+int  init_error(void);
+int  push_error(char *);
+#endif
+
 # endif
Index: trunk/Ohana/src/libdvo/include/dvodb.h
===================================================================
--- trunk/Ohana/src/libdvo/include/dvodb.h	(revision 31635)
+++ trunk/Ohana/src/libdvo/include/dvodb.h	(revision 31635)
@@ -0,0 +1,337 @@
+# ifndef DVODB_H
+# define DVODB_H
+
+// to get definition of Graphdata
+# include "kapa.h"
+
+typedef enum {
+  DB_STACK_NONE  = 0,
+  DB_STACK_INT   = 0x01,
+  DB_STACK_FIELD = 0x02,
+  DB_STACK_TEMP  = 0x04,
+  DB_STACK_VALUE = 0x08,
+  DB_STACK_CLOSE_PAR = 0x10,
+  DB_STACK_OPEN_PAR,
+  DB_STACK_LOGIC,
+  DB_STACK_COMPARE,
+  DB_STACK_BITWISE,
+  DB_STACK_SUM,
+  DB_STACK_MULTIPLY,
+  DB_STACK_POWER,
+  DB_STACK_UNARY,
+} dbStackTypes;
+
+/* magnitude types */
+enum {MAG_NONE, 
+      MAG_INST, 
+      MAG_CAT, 
+      MAG_APER, 
+      MAG_SYS, 
+      MAG_REL, 
+      MAG_CAL, 
+      MAG_AVE, 
+      MAG_REF, 
+      MAG_ERR, 
+      MAG_AVE_ERR, 
+      MAG_PHOT_FLAGS, 
+      MAG_CHISQ,
+      MAG_NCODE,
+      MAG_NPHOT,
+};
+
+/* measure fields */
+enum {MEAS_ZERO, 
+      MEAS_GLON, 
+      MEAS_GLAT, 
+      MEAS_GLON_AVE, 
+      MEAS_GLAT_AVE,
+      MEAS_ELON, 
+      MEAS_ELAT, 
+      MEAS_ELON_AVE, 
+      MEAS_ELAT_AVE,
+      MEAS_RA, 
+      MEAS_DEC, 
+      MEAS_RA_AVE, 
+      MEAS_DEC_AVE,
+      MEAS_RA_AVE_ERR, 
+      MEAS_DEC_AVE_ERR, 
+      MEAS_U_RA, 
+      MEAS_U_DEC, 
+      MEAS_U_RA_ERR, 
+      MEAS_U_DEC_ERR, 
+      MEAS_PAR, 
+      MEAS_PAR_ERR, 
+      MEAS_RA_OFFSET, 
+      MEAS_DEC_OFFSET, 
+      MEAS_RA_FIT_OFFSET, 
+      MEAS_DEC_FIT_OFFSET, 
+      MEAS_RA_OFFSET_ERR, 
+      MEAS_DEC_OFFSET_ERR, 
+      MEAS_CHISQ_POS, 
+      MEAS_CHISQ_PM,  
+      MEAS_CHISQ_PAR, 
+      MEAS_TMEAN, 
+      MEAS_TRANGE, 
+      MEAS_NMEAS, 
+      MEAS_NMISS, 
+      MEAS_NPOS, 
+      MEAS_OBJ_FLAGS, 
+      MEAS_MAG, 
+      MEAS_MINST, 
+      MEAS_MCAT, 
+      MEAS_MSYS, 
+      MEAS_MREL, 
+      MEAS_MCAL, 
+      MEAS_EXPTIME, 
+      MEAS_AIRMASS, 
+      MEAS_ALT, 
+      MEAS_AZ, 
+      MEAS_PHOTCODE, 
+      MEAS_PHOTCODE_EQUIV, 
+      MEAS_TIME, 
+      MEAS_FWHM, 
+      MEAS_FWHM_MAJ, 
+      MEAS_FWHM_MIN, 
+      MEAS_THETA, 
+      MEAS_POSANGLE, 
+      MEAS_PLATESCALE, 
+      MEAS_MXX, 
+      MEAS_MXY, 
+      MEAS_MYY, 
+      MEAS_DOPHOT, 
+      MEAS_DB_FLAGS, 
+      MEAS_PHOT_FLAGS, 
+      MEAS_XCCD, 
+      MEAS_YCCD, 
+      MEAS_XCCD_ERR, 
+      MEAS_YCCD_ERR, 
+      MEAS_POS_SYS_ERR, 
+      MEAS_XMOSAIC, 
+      MEAS_YMOSAIC, 
+      MEAS_SKY, 
+      MEAS_dSKY, 
+      MEAS_DET_ID, 
+      MEAS_OBJ_ID, 
+      MEAS_CAT_ID, 
+      MEAS_IMAGE_ID, 
+      MEAS_PSF_QF, 
+      MEAS_PSF_QF_PERFECT, 
+      MEAS_PSF_CHISQ, 
+      MEAS_PSF_NDOF,
+      MEAS_PSF_NPIX,
+      MEAS_CR_NSIGMA, 
+      MEAS_EXT_NSIGMA, 
+      MEAS_EXTERN_ID,
+};
+
+/* average fields */
+enum {AVE_ZERO, 
+      AVE_RA, 
+      AVE_DEC, 
+      AVE_RA_ERR, 
+      AVE_DEC_ERR, 
+      AVE_GLON, 
+      AVE_GLAT, 
+      AVE_ELON, 
+      AVE_ELAT, 
+      AVE_U_RA, 
+      AVE_U_DEC, 
+      AVE_U_RA_ERR, 
+      AVE_U_DEC_ERR, 
+      AVE_PAR, 
+      AVE_PAR_ERR, 
+      AVE_CHISQ_POS, 
+      AVE_CHISQ_PM, 
+      AVE_CHISQ_PAR, 
+      AVE_TMEAN,
+      AVE_TRANGE, 
+      AVE_Xp, 
+      AVE_NMEAS, 
+      AVE_NMISS, 
+      AVE_NPOS, 
+      AVE_NPHOT, 
+      AVE_NCODE, 
+      AVE_MAG, 
+      AVE_dMAG, 
+      AVE_Xm, 
+      AVE_OBJ_FLAGS, 
+      AVE_TYPE, 
+      AVE_TYPEFRAC,
+      AVE_OBJID,
+      AVE_CATID,
+      AVE_EXTID_HI,
+      AVE_EXTID_LO,
+};
+
+enum {IMAGE_ZERO, 
+      IMAGE_RA, 
+      IMAGE_DEC, 
+      IMAGE_GLON, 
+      IMAGE_GLAT, 
+      IMAGE_ELON, 
+      IMAGE_ELAT, 
+      IMAGE_XM, 
+      IMAGE_AIRMASS, 
+      IMAGE_MCAL, 
+      IMAGE_dMCAL, 
+      IMAGE_PHOTCODE, 
+      IMAGE_TIME, 
+      IMAGE_FWHM, 
+      IMAGE_FWHM_MEDIAN, 
+      IMAGE_EXPTIME, 
+      IMAGE_NSTAR, 
+      IMAGE_NCAL, 
+      IMAGE_SKY, 
+      IMAGE_FLAGS, 
+      IMAGE_CCDNUM, 
+      IMAGE_NX_PIX, 
+      IMAGE_NY_PIX, 
+      IMAGE_THETA, 
+      IMAGE_SKEW, 
+      IMAGE_SCALE, 
+      IMAGE_DSCALE, 
+      IMAGE_APRESID,
+      IMAGE_DAPRESID,
+      IMAGE_SIDTIME,
+      IMAGE_LATITUDE,
+      IMAGE_DET_LIMIT,
+      IMAGE_SAT_LIMIT,
+      IMAGE_CERROR,
+      IMAGE_FWHM_MAJ,
+      IMAGE_FWHM_MIN,
+      IMAGE_FWHM_MAJ_MEDIAN,
+      IMAGE_FWHM_MIN_MEDIAN,
+      IMAGE_TRATE,
+      IMAGE_IMAGE_ID,
+      IMAGE_EXTERN_ID,
+      IMAGE_SOURCE_ID,
+      IMAGE_X_LL_CHIP,
+      IMAGE_X_LR_CHIP,
+      IMAGE_X_UL_CHIP,
+      IMAGE_X_UR_CHIP,
+      IMAGE_Y_LL_CHIP,
+      IMAGE_Y_LR_CHIP,
+      IMAGE_Y_UL_CHIP,
+      IMAGE_Y_UR_CHIP,
+      IMAGE_X_LL_FP,
+      IMAGE_X_LR_FP,
+      IMAGE_X_UL_FP,
+      IMAGE_X_UR_FP,
+      IMAGE_Y_LL_FP,
+      IMAGE_Y_LR_FP,
+      IMAGE_Y_UL_FP,
+      IMAGE_Y_UR_FP,
+      IMAGE_X_ERR_SYS,
+      IMAGE_Y_ERR_SYS,
+      IMAGE_MAG_ERR_SYS,
+      IMAGE_NFIT_PHOTOM,
+      IMAGE_NFIT_ASTROM,
+      IMAGE_NLINK_PHOTOM,
+      IMAGE_NLINK_ASTROM
+};
+
+enum {DVO_TABLE_AVERAGE, DVO_TABLE_MEASURE, DVO_TABLE_IMAGE};
+enum {DVO_DB_CMDLINE_ERROR, DVO_DB_CMDLINE_IS_END, DVO_DB_CMDLINE_IS_WHERE, DVO_DB_CMDLINE_IS_MATCH}; 
+
+// options for selecting the ra,dec limits of the db selections
+typedef struct {
+  char *name;
+  char *list;
+  int useDisplay;
+  int useSkyregion;
+} SkyRegionSelection;
+
+// a single db field 
+typedef struct {
+  char *name;
+  int extract;
+  int table;
+  int ID;
+  int magMode;
+  char type;
+  PhotCode *photcode;
+} dbField;
+
+// db boolean operations
+typedef struct {
+  char   *name;
+  char    type;
+  int     field;
+  // opihi_flt FltValue;
+  // opihi_int IntValue;
+  double FltValue;
+  int IntValue;
+} dbStack;
+
+typedef struct {
+  // opihi_flt Flt;
+  // opihi_int Int;
+  double Flt;
+  int Int;
+} dbValue;
+
+Image        *LoadImagesDVO         PROTO((off_t *Nimage));
+void          FreeImagesDVO         PROTO((Image *images));
+Image        *MatchImageDVO         PROTO((unsigned int time, short int source, unsigned int imageID));
+Coords       *MatchMosaic           PROTO((unsigned int time, short int source));
+int           GetTimeSelection      PROTO((time_t *tz, time_t *te));
+int           GetTimeFormat         PROTO((time_t *TimeReference, int *TimeFormat));
+double        TimeValue (time_t time, time_t TimeReference, int TimeFormat);
+
+void          image_subset          PROTO((Image *image, off_t Nimage, off_t **Subset, off_t *Nsubset, SkyRegionSelection *selection, unsigned long int tzero, double trange, int TimeSelect));
+off_t         match_image_subset    PROTO((Image *image, off_t *subset, off_t Nsubset, unsigned int T, short int S));
+
+// dvo DB field functions
+dbField     *dbCmdlineFields        PROTO((int argc, char **argv, int table, int *last, int *nfields));
+int          dbCmdlineConditions    PROTO((int argc, char **argv, int first, int *nextField));
+dbStack     *dbRPN                  PROTO((int argc, char **argv, int *nstack));
+int          dbCheckStack           PROTO((dbStack *stack, int Nstack, int table, dbField **inFields, int *Nfields));
+int          dbBooleanCond          PROTO((dbStack *inStack, int NinStack, dbValue *fields));
+void         dbInitStack            PROTO((dbStack *stack));
+void 	     dbFreeStack            PROTO((dbStack *stack, int Nstack));
+void 	     dbFreeEntry            PROTO((dbStack *stack));
+void         dbFreeTempEntry        PROTO((dbStack *stack));
+
+dbStack     *dbBinary               PROTO((dbStack *V1, dbStack *V2, char *op, dbValue *fields));
+dbStack     *dbUnary                PROTO((dbStack *V1, char *op, dbValue *fields));
+
+int          GetMagMode             PROTO((char *string));
+PhotCode    *ParsePhotcodeField     PROTO((char *field, int *mode, int def));
+int          ParseMeasureField      PROTO((dbField *field, char *fieldName));
+int          ParseAverageField      PROTO((dbField *field, char *fieldName));
+int          ParseImageField        PROTO((dbField *field, char *fieldName));
+
+dbValue      dbExtractAverages      PROTO((Average *average, SecFilt *secfilt, Measure *measure, dbField *field));
+dbValue      dbExtractMeasures      PROTO((Average *average, SecFilt *secfilt, Measure *measure, dbField *field));
+dbValue      dbExtractImages        PROTO((Image *image, off_t Nimage, off_t N, dbField *field));
+
+void 	     dbInitField            PROTO((dbField *field));
+void 	     dbFreeFields           PROTO((dbField *fields, int Nfields));
+int          dbAstroRegionLimits    PROTO((dbStack **stack, int *nstack, SkyRegionSelection *selection, int table));
+char        *strfloat               PROTO((float value));
+
+void FreeImageSelection (void);
+
+void FreeSkyRegionSelection (SkyRegionSelection *selection);
+int wordhash (char *word);
+
+int dbExtractMeasuresInitTransform (CoordTransformSystem target);
+int dbExtractMeasuresInitAve (void);
+int dbExtractMeasuresInitMeas (void);
+int dbExtractMeasuresInit (void);
+
+int dbExtractAveragesInitTransform (CoordTransformSystem target);
+int dbExtractAveragesInit (void);
+
+int dbExtractImagesInitTransform (CoordTransformSystem target);
+int dbExtractImagesInit (void);
+int dbExtractImagesReset (void);
+
+// Some values used by code moved to libdvo from opihi.
+enum {OPIHI_FLT, OPIHI_INT};
+#define opihi_flt double
+#define opihi_int int
+
+int GetGraphdata PROTO((Graphdata *data, int *kapa, char *name));
+
+# endif
Index: trunk/Ohana/src/libdvo/include/libdvo_astro.h
===================================================================
--- trunk/Ohana/src/libdvo/include/libdvo_astro.h	(revision 31635)
+++ trunk/Ohana/src/libdvo/include/libdvo_astro.h	(revision 31635)
@@ -0,0 +1,36 @@
+#ifdef notdef
+# include "external.h"
+# include "shell.h"
+# include "dvomath.h"
+# include "convert.h"
+# include "display.h"
+# include "data.h"
+#endif
+
+# ifndef ASTRO_H
+# define ASTRO_H
+
+void InitAstro (void);
+void FreeAstro (void);
+
+typedef struct {
+  int    isIdentity;	      // identity transformation 
+  double phi;		      // saved in radians
+  double Xo;		      // saved in radians
+  double xo;		      // saved in degrees
+  double sin_phi_cos_Xo;      // pre-computed values
+  double sin_phi_sin_Xo;      // pre-computed values
+  double cos_phi_cos_Xo;      // pre-computed values
+  double cos_phi_sin_Xo;      // pre-computed values
+  double cos_phi;	      // pre-computed values
+  double sin_phi;	      // pre-computed values
+  double cos_Xo;	      // pre-computed values
+  double sin_Xo;	      // pre-computed values
+} CoordTransform;
+
+typedef enum {COORD_NONE, COORD_CELESTIAL, COORD_GALACTIC, COORD_ECLIPTIC} CoordTransformSystem;
+
+CoordTransform *InitTransform (CoordTransformSystem input, CoordTransformSystem output);
+int ApplyTransform (double *x, double *y, double X, double Y, CoordTransform *transform);
+
+# endif
Index: trunk/Ohana/src/libdvo/src/ImageOps.c
===================================================================
--- trunk/Ohana/src/libdvo/src/ImageOps.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/ImageOps.c	(revision 31635)
@@ -0,0 +1,133 @@
+# include "dvo.h"
+# include "dvodb.h"
+
+void image_subset (Image *image, off_t Nimage, off_t **Subset, off_t *Nsubset,
+		   SkyRegionSelection *selection, 
+		   unsigned long int tzero, double trange, int TimeSelect) 
+{
+
+  int j, flipped, status, InPic;
+  off_t i, n, *subset;
+  int npts;
+  double r, d, X, Y, x[4], y[4], Rmin, Rmax, Rmid;
+  Graphdata graph;
+  SkyRegion patch;
+
+  Rmin = Rmax = Rmid = 0;
+
+  if (selection->useDisplay) {
+    if (!GetGraphdata (&graph, NULL, NULL)) {
+      gprint (GP_ERR, "region display not available\n");
+      return;
+    }
+    Rmin = graph.coords.crval1 - 182.0;
+    Rmax = graph.coords.crval1 + 182.0;
+    Rmid = 0.5*(Rmin + Rmax);
+    BuildChipMatch (image, Nimage);
+  }
+
+  patch.Rmin = 0;
+  patch.Rmax = 0;
+  patch.Dmin = 0;
+  patch.Dmax = 0;
+  if (selection->useSkyregion) {
+    double Rs, Re, Ds, De;
+    get_skyregion (&Rs, &Re, &Ds, &De);
+    patch.Rmin = Rs;
+    patch.Rmax = Re;
+    patch.Dmin = Ds;
+    patch.Dmax = De;
+    Rmin = patch.Rmin - 182.0;
+    Rmax = patch.Rmax + 182.0;
+    Rmid = 0.5*(Rmin + Rmax);
+  }
+
+  if (trange < 0) {
+    tzero = tzero + trange;
+    trange = fabs (trange);
+  }
+
+  npts = 200;
+  ALLOCATE (subset, off_t, npts);
+  n = 0;
+  for (i = 0; i < Nimage; i++) {
+    if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
+    if (selection->useDisplay) {
+      if (!FindMosaicForImage (image, Nimage, i)) continue;
+      // first check if region center is in image
+      status = RD_to_XY (&X, &Y, Rmid, graph.coords.crval2, &image[i].coords);
+      if (status && (X >= 0) && (X < image[i].NX) && (Y >= 0) && (Y < image[i].NY)) goto in_region;
+
+      /* project this image to screen display coords */
+      x[0] = 0;           y[0] = 0;
+      x[1] = image[i].NX; y[1] = 0;
+      x[2] = image[i].NX; y[2] = image[i].NY;
+      x[3] = 0;           y[3] = image[i].NY;
+      InPic = flipped = FALSE;
+      for (j = 0; j < 4; j++) {
+	XY_to_RD (&r, &d, x[j], y[j], &image[i].coords);
+	/* use same side of 0,360 boundary for all corners */
+	if ((j == 0) && (r < Rmin)) flipped = TRUE; 
+	if ((j == 0) && (r > Rmax)) flipped = TRUE; 
+	r = ohana_normalize_angle (r);
+	while (flipped && (r < Rmid)) r+= 360.0;
+	while (flipped && (r > Rmid)) r-= 360.0;
+	status = RD_to_XY (&X, &Y, r, d, &graph.coords);
+	if (!status) continue;
+	if (X < graph.xmin) continue;
+	if (X > graph.xmax) continue;
+	if (Y < graph.ymin) continue;
+	if (Y > graph.ymax) continue;
+	goto in_region;
+	/** we miss any images which surround the region.  we are also
+	    missing the DIS images for which the corners don't touch
+	    the region, but which are needed for WRP images with
+	    corners touching the region **/
+      }
+      continue;
+    }
+    if (selection->useSkyregion) {
+      if (!FindMosaicForImage (image, Nimage, i)) continue;
+      /* project this image to screen display coords */
+      x[0] = 0;           y[0] = 0;
+      x[1] = image[i].NX; y[1] = 0;
+      x[2] = image[i].NX; y[2] = image[i].NY;
+      x[3] = 0;           y[3] = image[i].NY;
+      InPic = flipped = FALSE;
+      for (j = 0; j < 4; j++) {
+	XY_to_RD (&r, &d, x[j], y[j], &image[i].coords);
+	/* use same side of 0,360 boundary for all corners */
+	if ((j == 0) && (r < Rmin)) flipped = TRUE; 
+	if ((j == 0) && (r > Rmax)) flipped = TRUE; 
+	while (flipped && (r < Rmid)) r+= 360.0;
+	while (flipped && (r > Rmid)) r-= 360.0;
+	if (r < patch.Rmin) continue;
+	if (r > patch.Rmax) continue;
+	if (d < patch.Dmin) continue;
+	if (d > patch.Dmax) continue;
+	goto in_region;
+	/** we miss any images which surround the region.  we are also
+	    missing the DIS images for which the corners don't touch
+	    the region, but which are needed for WRP images with
+	    corners touching the region **/
+      }
+      continue;
+    }
+  in_region:
+    subset[n] = i;
+    n++;
+    if (n > npts - 1) {
+      npts += 200;
+      REALLOCATE (subset, off_t, npts);
+    }
+  }
+
+  REALLOCATE (subset, off_t, MAX (n, 1));
+  *Subset = subset;
+  *Nsubset = n;
+  return;
+}
+
+/* this routine fills the subset index with the list of selected images.
+   images may be selected on the basis of the region or on a time range 
+*/
Index: trunk/Ohana/src/libdvo/src/ImageSelection.c
===================================================================
--- trunk/Ohana/src/libdvo/src/ImageSelection.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/ImageSelection.c	(revision 31635)
@@ -0,0 +1,77 @@
+# include "dvo.h"
+
+/* db image table */
+static Image *image = NULL;
+static off_t *subset = NULL;
+static off_t Nimage = 0;
+static off_t Nsubset = 0;
+static Coords mosaic;
+
+/* load images based on parameters and region, etc */
+int SetImageSelection (int mosaicMode, SkyRegionSelection *selection) {
+
+  int TimeSelect;
+  time_t tzero, tend;
+
+  image = NULL;
+  subset = NULL;
+  
+  TimeSelect = GetTimeSelection (&tzero, &tend);
+
+  if (mosaicMode) {
+      /* mosaic defines a frame with 0,0 at the mosaic center, and 1 arcsec / pixel */
+      mosaic.crpix1 = mosaic.crpix2 = 0.0;
+      mosaic.cdelt1 = mosaic.cdelt2 = 1.0 / 3600;
+      mosaic.pc1_1  = mosaic.pc2_2  = 1.0;
+      mosaic.pc1_2  = mosaic.pc2_1  = 0.0;
+      mosaic.Npolyterms = 0;
+      strcpy (mosaic.ctype, "RA---SIN");
+  }
+
+  if ((image = LoadImagesDVO (&Nimage)) == NULL) return (FALSE);
+  BuildChipMatch (image, Nimage);
+  image_subset (image, Nimage, &subset, &Nsubset, selection, tzero, (double) tend - tzero, TimeSelect);
+  sort_image_subset (image, subset, Nsubset);
+  return (TRUE);
+}
+
+/* free loaded images */
+void FreeImageSelection () {
+  if (image != NULL) FreeImagesDVO(image);
+  if (subset != NULL) free (subset);
+  image = NULL;
+  subset = NULL;
+  return;
+}
+
+Image *MatchImageDVO (unsigned int time, short int source, unsigned int imageID) { 
+
+  int m = -1;
+
+  if ((imageID != 0) && (imageID < Nimage)) {
+    // imageID is in range for the array of images. If the table is still in order and
+    // no images have been deleted the index of the image we are looking for will be imageID - 1
+    // If this is the case, we have it. Otherwise we'll have to go search for it below
+    int guess = (int) imageID - 1;
+    if (image[guess].imageID == imageID) {
+        m = guess;
+    }
+  } 
+  if (m == -1) {
+    m = match_image_subset (image, subset, Nsubset, time, source);
+  }
+  if (m == -1) return (NULL);
+  if (!FindMosaicForImage (image, Nimage, m)) return (NULL);
+  return (&image[m]);
+}
+
+Coords *MatchMosaic (unsigned int time, short int source) { 
+
+  int m;
+
+  m = match_image_subset (image, subset, Nsubset, time, source);
+  if (m == -1) return (NULL);
+  mosaic.crval1 = image[m].coords.crval1;
+  mosaic.crval2 = image[m].coords.crval2;
+  return (&mosaic);
+}
Index: trunk/Ohana/src/libdvo/src/LoadImages.c
===================================================================
--- trunk/Ohana/src/libdvo/src/LoadImages.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/LoadImages.c	(revision 31635)
@@ -0,0 +1,98 @@
+# include "dvo.h"
+# include "dvodb.h"
+
+// XXX: Maybe make this a command line option
+int dvoUseImageCache = 1;
+
+static char *lastFilename = NULL;
+static time_t lastModified = 0;
+static Image *imageCache = NULL;
+static off_t cacheNimage = 0;
+
+static time_t getLastModified(char *filename);
+
+Image *LoadImagesDVO (off_t *Nimage) {
+
+  int status;
+  char *catdir, filename[256];
+  Image *image;
+  FITS_DB db;
+  
+  /* VarConfig ("IMAGE_CATALOG", "%s", filename); */
+
+  catdir = dvo_get_catdir ();
+  sprintf (filename, "%s/Images.dat", catdir);
+
+  if (lastFilename) {
+    if (dvoUseImageCache && !strcmp(lastFilename, filename)) {
+      // Make sure the file hasn't changed since we loaded it
+      if (getLastModified(filename) == lastModified) {
+        *Nimage = cacheNimage;
+        return  imageCache;
+      }
+    }
+    free(lastFilename);
+    lastFilename = NULL;
+    free(imageCache);
+    imageCache = NULL;
+    cacheNimage = 0;
+    lastModified = 0;
+  }
+
+
+  gfits_db_init (&db);
+  db.lockstate = LCK_SOFT;
+  db.timeout   = 120.0;
+
+  if (!gfits_db_lock (&db, filename)) {
+    gprint (GP_ERR, "error opening image catalog %s (1)\n", filename);
+    return (NULL);
+  }
+
+  if (db.dbstate == LCK_EMPTY) {
+    gprint (GP_ERR, "note: image catalog is empty\n");
+    ALLOCATE (image, Image, 1);
+    *Nimage = 1;
+    return (image);
+  }
+
+  status = dvo_image_load (&db, TRUE, FALSE);
+  gfits_db_close (&db);
+
+  if (!status) {
+    gprint (GP_ERR, "problem loading image database table\n");
+    return (NULL);
+  }
+
+  image = gfits_table_get_Image (&db.ftable, Nimage, &db.swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    return (NULL);
+  }
+  if (dvoUseImageCache && image) {
+    cacheNimage = *Nimage;
+    imageCache = image;
+    lastFilename = strdup(filename);
+    lastModified = getLastModified(filename);
+  }
+
+  return (image);
+}
+
+static time_t getLastModified(char *filename) {
+  struct stat statbuf;
+  if (!stat(filename, &statbuf)) {
+    return statbuf.st_mtime;
+  } else {
+    return 0;
+  }
+}
+
+void FreeImagesDVO(Image *images) {
+  if (!dvoUseImageCache && (images != NULL)) {
+    free(images);
+  } else {
+    // defer free until next LoadImages with a different or modified Images.dat
+  }
+}
+
Index: trunk/Ohana/src/libdvo/src/convert.c
===================================================================
--- trunk/Ohana/src/libdvo/src/convert.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/convert.c	(revision 31635)
@@ -0,0 +1,305 @@
+# include "convert.h"
+# define _XOPEN_SOURCE /* glibc2 (strptime) needs this */
+# include <time.h>
+
+/** additional time / coordinate conversions not supplied by libohana **/
+
+int hh_hms (double hh, int *hr, int *mn, double *sc) {
+
+  int N, flag;
+
+  flag = SIGN(hh);
+  hh = fabs(hh);
+
+  // rationalize hh to range -24.0 < hh < 24.0
+  if (hh >= 24.0) {
+    N = (int)(hh/24.0);
+    hh -= 24.0*N;
+  }
+
+  *hr = (int) hh;
+  *mn = (int) 60*(hh - *hr);
+  *sc = 3600.0*(hh - *hr - *mn / 60.0);
+  if (*sc > 59.99) {
+    *sc = 0.0;
+    *mn += 1.0;
+  }
+  *hr *= flag;
+  return (TRUE);
+}
+ 
+int dd_dms (double dd, int *dg, int *mn, double *sc) {
+
+  int flag;
+
+  flag = SIGN(dd);
+  dd = fabs (dd);
+  *dg = (int) dd;
+  *mn = (int) 60*(dd - *dg);
+  *sc = 3600.0*(dd - *dg - *mn/60.0);
+  if (*sc > 59.99) {
+    *sc = 0;
+    *mn += 1.0;
+  }
+  *dg *= flag;
+  return (TRUE);
+}
+ 
+int hms_format (char *line, double value) {
+
+  int hr, mn;
+  double sc;
+
+  hh_hms (value, &hr, &mn, &sc);
+  hr = (int) value;
+  if (isnan (value))
+    sprintf (line, "xx:xx:xx.xx");
+  else {
+    if (value < 0) {
+      sprintf (line, "-%02d:%02d:%05.2f", abs(hr), mn, sc);
+    } else {
+      sprintf (line, "+%02d:%02d:%05.2f", hr, mn, sc);
+    }
+  }      
+  return (TRUE);
+}
+
+int dms_format (char *line, double value) {
+
+  int dg, mn;
+  double sc;
+
+  dd_dms (value, &dg, &mn, &sc);
+  if (value < 0) {
+    sprintf (line, "-%02d:%02d:%05.2f", abs(dg), mn, sc);
+  } else {
+    sprintf (line, "+%02d:%02d:%05.2f", dg, mn, sc);
+  }
+  return (TRUE);
+}
+
+/***** convert 00:00:00 or 00:00 to 0 - 86400 ****/
+int hms_to_sec (char *string, time_t *second) {
+  
+  char *p;
+  struct tm time;
+
+  p = strptime (string, "%H:%M:%S", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%H:%M", &time);
+  if (p != NULL) goto valid;
+
+  return (FALSE);
+    
+valid:
+  if (*p) return (FALSE);
+  *second = time.tm_hour*3600 + time.tm_min*60 + time.tm_sec;
+  return (TRUE);
+}
+
+/***** convert Mon[@00:00:00] or 00:00 to 0 - 86400*7 ****/
+int day_to_sec (char *string, time_t *second) {
+  
+  char *p;
+  struct tm time;
+
+  bzero (&time, sizeof(time));
+  p = strptime (string, "%A@%H:%M:%S", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%A@%H:%M", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%A@%H", &time);
+  if (p != NULL) goto valid;
+
+  p = strptime (string, "%A", &time);
+  if (p != NULL) goto valid;
+
+  return (FALSE);
+
+valid:
+  if (*p) return (FALSE);
+  *second = time.tm_wday*86400 + time.tm_hour*3600 + time.tm_min*60 + time.tm_sec;
+  return (TRUE);
+}
+
+/***** convert seconds to HH:MM:SS ****/
+char *ohana_sec_to_hms (time_t second) {
+  
+  struct tm *gmt;
+  char *line;
+
+  ALLOCATE (line, char, 64);
+  gmt   = gmtime (&second);
+  sprintf (line, "%02d:%02d:%02d", gmt[0].tm_hour, gmt[0].tm_min, gmt[0].tm_sec); 
+  return (line);
+}
+
+/***** convert seconds to Day@HH:MM:SS ****/
+char *ohana_sec_to_day (time_t second) {
+  
+  struct tm *gmt;
+  char *line;
+
+  ALLOCATE (line, char, 64);
+  gmt   = gmtime (&second);
+  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); 
+      break;
+    case 1:
+      sprintf (line, "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); 
+      break;
+    case 3:
+      sprintf (line, "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); 
+      break;
+    case 5:
+      sprintf (line, "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); 
+      break;
+  }
+  return (line);
+}
+
+int hh_hm (double hh, int *hr, double *mn) {
+
+  int flag;
+
+  flag = SIGN(hh);
+  hh = fabs (hh);
+
+  *mn = 60.0*(hh - (int)hh);
+  *hr = (int) hh;
+  *hr *= flag;
+  return (TRUE);
+}
+
+char *meade_deg_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg, &hr, &mn);
+
+  sprintf (line, "%03d:%04.1f", abs(hr), mn);
+  return (line);
+}
+
+char *meade_ra_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg/15.0, &hr, &mn);
+
+  sprintf (line, "%02d:%04.1f", abs(hr), mn);
+  return (line);
+}
+
+char *meade_dec_to_str (double deg) {
+
+  int hr;
+  double mn;
+  char *line;
+
+  ALLOCATE (line, char, 16);
+
+  hh_hm (deg, &hr, &mn);
+
+  if (deg < 0) {
+    sprintf (line, "-%02d:%04.1f", abs(hr), mn);
+  } else {
+    sprintf (line, "+%02d:%04.1f", hr, mn);
+  }      
+  return (line);
+}
+
+/* convert UNIX time to a value referenced to the TimeReference in the given unit */
+double TimeValue (time_t time, time_t TimeReference, int TimeFormat) {
+
+  double value, dt;
+
+  dt = (time > TimeReference) ? (time - TimeReference) : -1 * (double)(TimeReference - time);
+  switch (TimeFormat) {
+  case TIME_JD:
+    value = time / 86400.0 + 2440587.5;
+    break;
+  case TIME_MJD:
+    value = time / 86400.0 + 40587.0;
+    break;
+  case TIME_DAYS:
+    value = dt / 86400.0;
+    break;
+  case TIME_HOURS:
+    value = dt / 3600.0;
+    break;
+  case TIME_MINUTES:
+    value = dt / 60.0;
+    break;
+  case TIME_SECONDS:
+  default:
+    value = dt;
+    break;
+  }
+  return (value);
+}
+  
+/* convert time value referenced to the TimeReference in the given unit to UNIX time */
+time_t TimeRef (double value, time_t TimeReference, int TimeFormat) {
+
+  int dt;
+  time_t time;
+
+  switch (TimeFormat) {
+  case TIME_JD:
+    time = (value -  2440587.5) * 86400.0;
+    return (time);
+    break;
+  case TIME_MJD:
+    time = (value -  40587.0) * 86400.0;
+    return (time);
+    break;
+  case TIME_DAYS:
+    dt = value * 86400.0;
+    break;
+  case TIME_HOURS:
+    dt = value * 3600.0;
+    break;
+  case TIME_MINUTES:
+    dt = value * 60.0;
+    break;
+  case TIME_SECONDS:
+  default:
+    dt = value;
+    break;
+  }
+
+  time = TimeReference + dt;
+  return (time);
+}
+
+/* times may be in forms as:
+ * 20040200450s (N seconds since 1970.0)
+ * 2440900.232j (julian date)
+ * 99/02/23,03:22:18 (date string)
+ * (separators may be anything except space, +, -)
+ * 99:02:15:12:23:30
+ * 99:02:15:12h23m30s
+ */
+
Index: trunk/Ohana/src/libdvo/src/coord_systems.c
===================================================================
--- trunk/Ohana/src/libdvo/src/coord_systems.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/coord_systems.c	(revision 31635)
@@ -0,0 +1,174 @@
+# include "dvo.h"
+# include "libdvo_astro.h"
+    
+CoordTransform *InitTransform (CoordTransformSystem input, CoordTransformSystem output) {
+
+  CoordTransform *transform;
+  struct timeval now;
+  struct tm *local;
+  double T;
+
+  ALLOCATE (transform, CoordTransform, 1);
+  transform->isIdentity = FALSE;
+  
+  switch (input) {
+    case COORD_CELESTIAL:
+      switch (output) {
+	case COORD_CELESTIAL:
+	  transform->phi = 0.0;
+	  transform->Xo  = 0.0;
+	  transform->xo  = 0.0;
+	  transform->isIdentity = TRUE;
+	  break;
+	case COORD_GALACTIC:
+
+	  // J2000 FK5 transformation from Liu et al 2011 (A&A 526, A16)
+	  transform->phi = -62.8717488056*RAD_DEG;
+	  transform->Xo  = 282.8594812080*RAD_DEG;
+	  transform->xo  =  32.9319185700;
+
+	  // these are derived from their eqn (10):
+	  // \alpha^p_J =  12h 51m 26.27549s
+	  // \delta^p_J = +27d 07' 41.7043"
+	  // \theta_J   = 122.93191857 deg
+	  // phi = -90 - \alpha^p_J
+	  // Xo  = +90 - \delta^p_J
+	  // xo  = \theta_J - 90
+
+	  // Liu et al also propose an alternative ICRS definition using:
+	  // \alpha^p_J =  12h 51m 26.27469s
+	  // \delta^p_J = +27d 07' 41.7087"
+	  // \theta_J   = 122.93192526 deg
+	  // these differ from the above at the several milliarcsec level
+
+
+	  // These values were used in the past, but transform to/from B1950.0
+	  // transform->phi = -62.60*RAD_DEG;
+	  // transform->Xo  = 282.25*RAD_DEG;
+	  // transform->xo  =  33.00;
+
+	  break;
+	case COORD_ECLIPTIC:
+	  gettimeofday (&now, NULL);
+	  local = localtime (&now.tv_sec);
+	  T = local[0].tm_year / 100.0;
+	  transform->phi = -1.0*RAD_DEG*(23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T);
+	  transform->Xo  = 0.0;
+	  transform->xo  = 0.0;
+	  break;
+	default:
+	  abort();
+      }
+      break;
+    case COORD_ECLIPTIC:
+      switch (output) {
+	case COORD_CELESTIAL:
+	  gettimeofday (&now, (struct timezone *) NULL);
+	  local = localtime (&now.tv_sec);
+	  T = local[0].tm_year / 100.0;
+	  transform->phi = RAD_DEG*(23.452294 - 0.013013*T - 0.000001639*T*T + 0.000000503*T*T*T);
+	  transform->Xo = 0.0;
+	  transform->xo = 0.0;
+	  break;
+	case COORD_GALACTIC:
+	  return NULL;
+	  break;
+	case COORD_ECLIPTIC:
+	  transform->phi = 0.0;
+	  transform->Xo  = 0.0;
+	  transform->xo  = 0.0;
+	  transform->isIdentity = TRUE;
+	  break;
+	default:
+	  abort();
+      }
+      break;
+    case COORD_GALACTIC:
+      switch (output) {
+	case COORD_CELESTIAL:
+	  // J2000 transformation from Liu et al 2011 ()
+	  transform->phi =  62.8717488056*RAD_DEG;
+	  transform->Xo  =  32.9319185700*RAD_DEG;
+	  transform->xo  = 282.8594812080;
+
+	  // These values were used in the past, but transform to/from B1950.0
+	  // transform->phi =  62.60*RAD_DEG;
+	  // transform->Xo  =  33.00*RAD_DEG;
+	  // transform->xo  = 282.25;
+	  break;
+	case COORD_GALACTIC:
+	  transform->phi = 0.0;
+	  transform->Xo  = 0.0;
+	  transform->xo  = 0.0;
+	  transform->isIdentity = TRUE;
+	  break;
+	case COORD_ECLIPTIC:
+	  return NULL;
+	default:
+	  abort();
+      }
+      break;
+    default:
+      abort();
+  }
+ 
+  // pre-calculated constants:
+  transform->sin_phi_cos_Xo = sin(transform->phi)*cos(transform->Xo);
+  transform->sin_phi_sin_Xo = sin(transform->phi)*sin(transform->Xo);
+  transform->cos_phi        = cos(transform->phi);
+  
+  transform->cos_phi_cos_Xo = cos(transform->phi)*cos(transform->Xo);
+  transform->cos_phi_sin_Xo = cos(transform->phi)*sin(transform->Xo);
+  transform->sin_phi        = sin(transform->phi);
+  transform->cos_Xo 	    = cos(transform->Xo);
+  transform->sin_Xo 	    = sin(transform->Xo);
+
+  return transform;
+}
+
+// input and output coordinates are in degrees
+int ApplyTransform (double *x, double *y, double X, double Y, CoordTransform *transform) {
+
+  double sin_x, sin_y, cos_x, cos_y;
+
+
+  if (transform == NULL) return (FALSE);
+
+  if (transform->isIdentity) {
+    *x = X;
+    *y = Y;
+    return (TRUE);
+  }
+
+  X *= RAD_DEG;
+  Y *= RAD_DEG;
+
+  // recast with constants extracted:
+  sin_y = cos(Y)*sin(X)*transform->sin_phi_cos_Xo - cos(Y)*cos(X)*transform->sin_phi_sin_Xo + sin(Y)*transform->cos_phi;
+  cos_y = sqrt (1 - sin_y*sin_y);
+
+  sin_x = cos(Y)*sin(X)*transform->cos_phi_cos_Xo - cos(Y)*cos(X)*transform->cos_phi_sin_Xo - sin(Y)*transform->sin_phi;
+  cos_x = cos(Y)*cos(X)*transform->cos_Xo + cos(Y)*sin(X)*transform->sin_Xo;
+      
+  // atan2 returns -pi : +pi
+  *x = DEG_RAD * atan2 (sin_x, cos_x) + transform->xo;
+  if ((*x) <   0.0) (*x) += 360;
+  if ((*x) > 360.0) (*x) -= 360;
+
+  // should be in range -pi/2 : +pi/2
+  *y = DEG_RAD * atan2 (sin_y, cos_y);
+
+  return (TRUE);
+}
+
+// sin_y = cos(Y)*sin(X - Xo)*sin(phi) + sin(Y)*cos(phi);
+
+// sin_x = (cos(Y)*sin(X - Xo)*cos(phi) - sin(Y)*sin(phi)) /  cos_y;
+// cos_x = cos(Y)*cos(X - Xo) / cos_y;
+
+// multiplying both sides by cos_y:
+// sin_x = (cos(Y)*sin(X - Xo)*cos(phi) - sin(Y)*sin(phi));
+// cos_x = cos(Y)*cos(X - Xo);
+      
+// sin(a - b) = sin(a)*cos(b) - sin(b)*cos(a);
+// cos(a - b) = sin(a)*sin(b) + cos(a)*cos(b);
Index: trunk/Ohana/src/libdvo/src/dbBooleanCond.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbBooleanCond.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbBooleanCond.c	(revision 31635)
@@ -0,0 +1,85 @@
+# include "dvo.h"
+
+// evaluate the expression in inStack as a boolean; necessary db field values are
+// supplied by fields, in order 0 - Nfields (validate before calling)
+// XXX fields needs to be typed (dbValue), stack math needs to deal with the type cases
+int dbBooleanCond (dbStack *inStack, int NinStack, dbValue *fields) {
+  
+  float value;
+  int i, j, N, Nstack;
+  dbStack **stack, *output;
+
+  // 'no stack' means 'no where statement'
+  if (NinStack == 0) return (TRUE);
+
+  Nstack = NinStack;
+  ALLOCATE (stack, dbStack *, NinStack);
+  for (i = 0; i < NinStack; i++) {
+    stack[i] = &inStack[i];
+  }
+
+  for (i = 0; i < Nstack; i++) {
+
+    /***** binary operators *****/
+    if ((stack[i][0].type >= DB_STACK_LOGIC) && (stack[i][0].type <= DB_STACK_POWER)) {
+
+      // pre-test that op and entries match
+      output = dbBinary (stack[i-2], stack[i-1], stack[i][0].name, fields); 
+
+      // free temporary stack items, drop external items
+      dbFreeTempEntry (stack[i-2]);
+      dbFreeTempEntry (stack[i-1]);
+
+      stack[i-2] = output;
+      for (j = i + 1; j < Nstack; j++) {
+	stack[j-2] = stack[j];
+      }
+
+      Nstack -= 2;
+      i -= 2;
+      continue;
+    }
+
+    /***** unary operators **/
+    if (stack[i][0].type == DB_STACK_UNARY) {
+
+      // pre-test that op and entries match
+      output = dbUnary (stack[i-1], stack[i][0].name, fields); 
+
+      // free temporary stack items, drop external items
+      dbFreeTempEntry (stack[i-1]);
+
+      stack[i-1] = output;
+      for (j = i + 1; j < Nstack; j++) {
+	stack[j-1] = stack[j];
+      }
+
+      Nstack -= 1;
+      i -= 1;
+      continue;
+    } 
+  }
+
+  // the result here is a single stack entry with a value:
+  if (stack[0][0].type & DB_STACK_FIELD) {
+    N = stack[0][0].field;
+    value = (stack[0][0].type & DB_STACK_INT) ? fields[N].Int : fields[N].Flt;
+  } else {
+    value = (stack[0][0].type & DB_STACK_INT) ? stack[0][0].IntValue : stack[0][0].FltValue;
+  }
+    
+  for (i = 0; i < Nstack; i++) {
+    dbFreeEntry (stack[i]);
+  }
+  free (stack);
+
+  // XXX fix this limit
+  if (fabs(value) > 1e-7) {
+    return (TRUE);
+  } else {
+    return (FALSE);
+  }
+
+  // pre-test that op and entries match
+  return (TRUE);
+}
Index: trunk/Ohana/src/libdvo/src/dbCheckStack.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbCheckStack.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbCheckStack.c	(revision 31635)
@@ -0,0 +1,129 @@
+# include "dvo.h"
+
+// XXX we are using a fairly bogus set of char values to distinguish a few cases:
+// 's', 'S' : value is a scalar (upper == float; lower == int)
+// 'f', 'F' : value is a field (upper == float; lower == int)
+// 't', 'T' : value is a temp scalar (upper == float; lower == int)
+// these would be better done using bit values to test for field? temp? float?
+//
+
+#define OPIHI_INT 1
+
+int dbCheckStack (dbStack *stack, int Nstack, int table, dbField **inFields, int *inNfields) {
+
+  int i, j, status, NFIELDS, Nfields;
+  char *c1, *c2;
+  dbField *fields;
+
+  fields = *inFields;
+  Nfields = *inNfields;
+
+  NFIELDS = Nfields + 10;
+  REALLOCATE (fields, dbField, NFIELDS);
+
+  for (i = 0; i < Nstack; i++) {
+    if (stack[i].type == DB_STACK_VALUE) {
+
+      /** if this is a number, put it on the list of scalars and move on.  assume value is
+       * an int unless proven otherwise **/
+      stack[i].FltValue = strtod (stack[i].name, &c1);
+      stack[i].IntValue = strtol (stack[i].name, &c2, 0);
+      if (c2 == stack[i].name + strlen (stack[i].name)) {
+	stack[i].type  |= DB_STACK_INT;
+	continue;
+      } 
+      if (c1 == stack[i].name + strlen (stack[i].name)) {
+	// this is a float value
+	continue;
+      } 
+
+      // the value might be a special type of number: RA,DEC in sexigesimal or 
+      // time in YYYY/MM/DD, etc
+      // status = ohana_str_to_time (stack[i].name, &seconds);
+      // keep as time_t
+      // status = ohana_dms_to_ddd (&ddd, stack[i].name);
+      // keep as either hours (RA) or deg (DEC).
+
+      // strings protected by double quotes should parse to be special types of numbers
+      // (photcodes, dates, ra / dec)
+      if (stack[i].name[0] == '"') {
+	  if (stack[i].name[strlen(stack[i].name) - 1] != '"') {
+	      gprint (GP_ERR, "syntax error for field %s\n", stack[i].name);
+	      goto failure;
+	  }
+	  char *tmpstring;
+	  tmpstring = strncreate (&stack[i].name[1], strlen(stack[i].name) - 2);
+
+	  // attempt to parse the string as a special word:
+	  PhotCode *code;
+	  code = GetPhotcodebyName (tmpstring);
+	  if (code) {
+	      stack[i].IntValue = code->code;
+	      stack[i].type = DB_STACK_INT;
+	      continue;
+	  } 
+
+	  // add in tests for sexigesimal, date/time
+	  // TimeRefPM = ohana_date_to_sec ("2000/01/01");
+	  
+	  gprint (GP_ERR, "syntax error for field %s\n", stack[i].name);
+	  goto failure;
+      }
+
+      // this must be a field : is it already in the list?
+      for (j = 0; (j < Nfields) && strcasecmp (stack[i].name, fields[j].name); j++);
+      if (j < Nfields) {
+	stack[i].field = j;
+	stack[i].type |= DB_STACK_FIELD;
+	if (fields[j].type == OPIHI_INT) {
+	  stack[i].type |= DB_STACK_INT;
+	}
+	stack[i].name  = NULL;
+	stack[i].FltValue = 0.0;
+	stack[i].IntValue =   0;
+	continue;
+      }
+
+      // this must be a field : is it a valid name?
+      status = FALSE;
+      if (table == DVO_TABLE_MEASURE) {
+	status = ParseMeasureField (&fields[Nfields], stack[i].name);
+      } 
+      if (table == DVO_TABLE_AVERAGE) {
+	status = ParseAverageField (&fields[Nfields], stack[i].name);
+      } 
+      if (table == DVO_TABLE_IMAGE) {
+	status = ParseImageField (&fields[Nfields], stack[i].name);
+      } 
+      if (!status) {
+	goto failure;
+      }
+      stack[i].field = Nfields;
+      stack[i].type |= DB_STACK_FIELD;
+      if (fields[Nfields].type == OPIHI_INT) {
+	stack[i].type |= DB_STACK_INT;
+      }
+      stack[i].name  = NULL;
+      stack[i].FltValue = 0.0; // 'F'
+      stack[i].IntValue =   0; // 'f'
+
+      Nfields ++;
+      CHECK_REALLOCATE (fields, dbField, NFIELDS, Nfields, 10);
+    }
+  }
+
+  *inNfields = Nfields;
+  *inFields = fields;
+  return (TRUE);
+
+failure:
+  *inNfields = Nfields;
+  *inFields = fields;
+  return (FALSE);
+}
+
+/* check stack identifies the data elements as plain scalars or table fields
+   operators have already been identified.  
+   check stack returns the total stack dimensionality (0,1,2)
+   on error, check stack returns FALSE
+*/
Index: trunk/Ohana/src/libdvo/src/dbCmdlineFields.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbCmdlineFields.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbCmdlineFields.c	(revision 31635)
@@ -0,0 +1,215 @@
+# include "dvo.h"
+
+// check for 'where' or 'matched to'; return first field after the word, and the value
+int dbCmdlineConditions (int argc, char **argv, int first, int *nextField) {
+
+  int isWhere, isMatch;
+
+  *nextField = argc;
+
+  // require 'where' or 'matched to' before boolean math
+  if (first == argc) return DVO_DB_CMDLINE_IS_END;
+
+  isWhere = !strcasecmp(argv[first], "where");
+  isMatch = !strcasecmp(argv[first], "match");
+    
+  if (!isMatch && !isWhere) {
+    gprint (GP_ERR, "WHERE or MATCH TO\n");
+    return DVO_DB_CMDLINE_ERROR;
+  }
+  if (isMatch && ((first + 1 >= argc - 1) || strcasecmp(argv[first+1], "to"))) {
+    gprint (GP_ERR, "missing boolean expression\n");
+    return DVO_DB_CMDLINE_ERROR;
+  }
+  if (isWhere && (first >= argc - 1)) {
+    gprint (GP_ERR, "missing boolean expression\n");
+    return DVO_DB_CMDLINE_ERROR;
+  }
+
+  if (isWhere) {
+    *nextField = first + 1;
+    return DVO_DB_CMDLINE_IS_WHERE;
+  }
+
+  if (isMatch) {
+    *nextField = first + 2;
+    return DVO_DB_CMDLINE_IS_MATCH;
+  }
+
+  gprint (GP_ERR, "programming error?\n");
+  return DVO_DB_CMDLINE_ERROR;
+}
+
+// identify the fields to be extracted (check syntax)
+// the 'last' pointer ends on the first word after the fields (where, match or EOL) 
+dbField *dbCmdlineFields (int argc, char **argv, int table, int *last, int *nfields) {
+
+  int i, status, Nfields, NFIELDS;
+  char *p, *q, *field;
+  dbField *fields;
+
+  *nfields = 0;
+  Nfields = 0;
+  NFIELDS = 10;
+  ALLOCATE (fields, dbField, NFIELDS);
+  dbInitField (&fields[0]);
+
+  status = FALSE;
+
+  // examine each argv[i] entry until we reach a 'where', a 'matched', or the end of the line
+  for (i = 1; (i < argc) && strcasecmp (argv[i], "where") && strcasecmp (argv[i], "match"); i++) {
+    // split the word by ","
+    p = argv[i];
+    while (*p) {
+      q = strchr (p, ',');
+      if (q == NULL) {
+	field = strcreate (p);
+	p = p + strlen(p);
+      } else {
+	field = strncreate (p, q-p);
+	p = q + 1;
+      }
+      // identify field for word
+      // need to know which type of fields to look for...
+      // xxx extend this more generally later
+      if (table == DVO_TABLE_MEASURE) {
+	status = ParseMeasureField (&fields[Nfields], field);
+      } 
+      if (table == DVO_TABLE_AVERAGE) {
+	status = ParseAverageField (&fields[Nfields], field);
+      } 
+      if (table == DVO_TABLE_IMAGE) {
+	status = ParseImageField (&fields[Nfields], field);
+      } 
+      if (!status) {
+	free (field);
+	dbFreeFields (fields, Nfields);
+	return (NULL);
+      }
+      free (field);
+
+      Nfields ++;
+      CHECK_REALLOCATE (fields, dbField, NFIELDS, Nfields, 10);
+      dbInitField (&fields[Nfields]);
+    }
+  }
+
+  *last = i;
+  *nfields = Nfields;
+
+  return (fields);
+}
+
+char *strfloat (float value) {
+
+  int Nbyte;
+  char *output;
+  char tmp;
+
+  Nbyte = snprintf (&tmp, 0, "%f", value);
+  ALLOCATE (output, char, Nbyte + 1);
+  snprintf (output, Nbyte + 1, "%f", value);
+  return output;
+}
+
+// identify the fields to be extracted (test for where, check syntax)
+int dbAstroRegionLimits (dbStack **stack, int *nstack, SkyRegionSelection *selection, int table) {
+  
+  int N;
+  double Rmin, Rmax, Dmin, Dmax;
+  char *Rname, *Dname;
+
+  if (!selection->useDisplay && !selection->useSkyregion) return (TRUE);
+
+  // get the ra,dec limits...
+  if (selection->useDisplay) {
+    return (TRUE);
+    // XXX fix this: be more careful with the projection & limits
+
+    Graphdata graphsky;
+    if (!GetGraphdata (&graphsky, NULL, NULL)) {
+      gprint (GP_ERR, "region display not available\n");
+      return (FALSE);
+    }
+    
+    // XXX the ra and dec range depend on the projection. 
+    // XXX this is wrong...
+    int status;
+    status = XY_to_RD (&Rmin, &Dmin, graphsky.xmin, graphsky.ymin, &graphsky.coords);
+    status = XY_to_RD (&Rmax, &Dmax, graphsky.xmax, graphsky.ymax, &graphsky.coords);
+  }
+
+  if (selection->useSkyregion) {
+    get_skyregion (&Rmin, &Rmax, &Dmin, &Dmax);
+  }    
+
+  N = *nstack;
+  REALLOCATE (*stack, dbStack, N + 20);
+
+  Rname = Dname = NULL;
+  if (table == DVO_TABLE_MEASURE) {
+    Rname = strcreate ("RA:AVE");
+    Dname = strcreate ("DEC:AVE");
+  }
+  if (table == DVO_TABLE_AVERAGE) {
+    Rname = strcreate ("RA");
+    Dname = strcreate ("DEC");
+  }
+  if (table == DVO_TABLE_IMAGE) {
+    Rname = strcreate ("RA");
+    Dname = strcreate ("DEC");
+  } 
+  if (Rname == NULL) return (FALSE);
+
+  // add: ((ra > rmin) && (ra < rmax) && (dec > dmin) && (dec < dmax))
+  // prepend with && if *nstack > 0
+
+  stack[0][N +  0].name = strcreate (Rname);
+  stack[0][N +  0].type = DB_STACK_VALUE;
+  stack[0][N +  1].name = strfloat (Rmin);
+  stack[0][N +  1].type = DB_STACK_VALUE;
+  stack[0][N +  2].name = strcreate (">");
+  stack[0][N +  2].type = DB_STACK_COMPARE;
+
+  stack[0][N +  3].name = strcreate (Rname);
+  stack[0][N +  3].type = DB_STACK_VALUE;
+  stack[0][N +  4].name = strfloat (Rmax);
+  stack[0][N +  4].type = DB_STACK_VALUE;
+  stack[0][N +  5].name = strcreate ("<");
+  stack[0][N +  5].type = DB_STACK_COMPARE;
+  stack[0][N +  6].name = strcreate ("A");
+  stack[0][N +  6].type = DB_STACK_LOGIC;
+
+  stack[0][N +  7].name = strcreate (Dname);
+  stack[0][N +  7].type = DB_STACK_VALUE;
+  stack[0][N +  8].name = strfloat (Dmin);
+  stack[0][N +  8].type = DB_STACK_VALUE;
+  stack[0][N +  9].name = strcreate (">");
+  stack[0][N +  9].type = DB_STACK_COMPARE;
+  stack[0][N + 10].name = strcreate ("A");
+  stack[0][N + 10].type = DB_STACK_LOGIC;
+
+  stack[0][N + 11].name = strcreate (Dname);
+  stack[0][N + 11].type = DB_STACK_VALUE;
+  stack[0][N + 12].name = strfloat (Dmax);
+  stack[0][N + 12].type = DB_STACK_VALUE;
+  stack[0][N + 13].name = strcreate ("<");
+  stack[0][N + 13].type = DB_STACK_COMPARE;
+  stack[0][N + 14].name = strcreate ("A");
+  stack[0][N + 14].type = DB_STACK_LOGIC;
+
+  if (N == 0) {
+    N += 15;
+  } else {
+    stack[0][N + 15].name = strcreate ("A");
+    stack[0][N + 15].type = DB_STACK_LOGIC;
+    N += 16;
+  }    
+
+  free (Rname);
+  free (Dname);
+
+  *nstack = N;
+  return (TRUE);
+}
+
Index: trunk/Ohana/src/libdvo/src/dbExtractAverages.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbExtractAverages.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbExtractAverages.c	(revision 31635)
@@ -0,0 +1,241 @@
+# include "dvo.h"
+# include "libdvo_astro.h"
+
+/* time concepts */
+static time_t TimeReference;
+static int TimeFormat;
+
+static CoordTransform *celestial_to_galactic = NULL;
+static CoordTransform *celestial_to_ecliptic = NULL;
+
+static int haveGalactic = FALSE;
+static double GLON = 0.0;
+static double GLAT = 0.0;
+
+static int haveEcliptic = FALSE;
+static double ELON = 0.0;
+static double ELAT = 0.0;
+
+// define a locally-static transform
+int dbExtractAveragesInitTransform (CoordTransformSystem target) {
+
+  // galactic transform is kept forever
+  if (target == COORD_GALACTIC) {
+    if (celestial_to_galactic != NULL) return (TRUE);
+    celestial_to_galactic = InitTransform (COORD_CELESTIAL, target);
+    return (TRUE);
+  }
+
+  // ecliptic transform must be updated (is weakly time-dependent)
+  if (target == COORD_ECLIPTIC) {
+    if (celestial_to_ecliptic != NULL) {
+      free (celestial_to_ecliptic);
+    }
+    celestial_to_ecliptic = InitTransform (COORD_CELESTIAL, target);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+int dbExtractAveragesInit () {
+  GetTimeFormat (&TimeReference, &TimeFormat);
+  haveGalactic = FALSE;
+  haveEcliptic = FALSE;
+  return (TRUE);
+}
+
+/* return average.field based on the selection */
+dbValue dbExtractAverages (Average *average, SecFilt *secfilt, Measure *measure, dbField *field) {
+
+  off_t i;
+  int Nsec;
+  dbValue value;
+
+  value.Flt = NAN;
+  value.Int =   0;
+
+  /* assign vector values */
+  switch (field->ID) {
+    case AVE_RA:
+      value.Flt = average[0].R;
+      break;
+    case AVE_DEC:
+      value.Flt = average[0].D;
+      break;
+    case AVE_GLON:
+      if (!haveGalactic) {
+	ApplyTransform (&GLON, &GLAT, average[0].R, average[0].D, celestial_to_galactic);
+	haveGalactic = TRUE;
+      }
+      value.Flt = GLON;
+      break;
+    case AVE_GLAT:
+      if (!haveGalactic) {
+	ApplyTransform (&GLON, &GLAT, average[0].R, average[0].D, celestial_to_galactic);
+	haveGalactic = TRUE;
+      }
+      value.Flt = GLAT;
+      break;
+    case AVE_ELON:
+      if (!haveEcliptic) {
+	ApplyTransform (&ELON, &ELAT, average[0].R, average[0].D, celestial_to_ecliptic);
+	haveEcliptic = TRUE;
+      }
+      value.Flt = ELON;
+      break;
+    case AVE_ELAT:
+      if (!haveEcliptic) {
+	ApplyTransform (&ELON, &ELAT, average[0].R, average[0].D, celestial_to_ecliptic);
+	haveEcliptic = TRUE;
+      }
+      value.Flt = ELAT;
+      break;
+    case AVE_RA_ERR:
+      value.Flt = average[0].dR;
+      break;
+    case AVE_DEC_ERR:
+      value.Flt = average[0].dD;
+      break;
+
+    case AVE_U_RA:
+      value.Flt = average[0].uR;
+      break;
+    case AVE_U_DEC:
+      value.Flt = average[0].uD;
+      break;
+    case AVE_U_RA_ERR:
+      value.Flt = average[0].duR;
+      break;
+    case AVE_U_DEC_ERR:
+      value.Flt = average[0].duD;
+      break;
+
+    case AVE_PAR:
+      value.Flt = average[0].P;
+      break;
+    case AVE_PAR_ERR:
+      value.Flt = average[0].dP;
+      break;
+
+    case AVE_NMEAS:
+      value.Int = average[0].Nmeasure;
+      break;
+    case AVE_NMISS:
+      value.Int = average[0].Nmissing;
+      break;
+    case AVE_NPOS:
+      value.Int = average[0].Npos;
+      break;
+
+    case AVE_CHISQ_POS:
+      value.Flt = average[0].ChiSqAve;
+      break;
+    case AVE_CHISQ_PM:
+      value.Flt = average[0].ChiSqPM;
+      break;
+    case AVE_CHISQ_PAR:
+      value.Flt = average[0].ChiSqPar;
+      break;
+
+    case AVE_TMEAN:
+      value.Flt = TimeValue (average[0].Tmean, TimeReference, TimeFormat);
+      break;
+    case AVE_TRANGE:
+      value.Flt = TimeValue (average[0].Trange, 0, TimeFormat);
+      break;
+
+    case AVE_Xp:
+      value.Flt = 0.01*average[0].Xp;
+      break;
+
+    case AVE_OBJ_FLAGS:
+      value.Int = average[0].flags;
+      break;
+    case AVE_OBJID:
+      value.Int = average[0].objID;
+      break;
+    case AVE_CATID:
+      value.Int = average[0].catID;
+      break;
+    case AVE_EXTID_HI:
+      value.Int = (0x00000000FFFFFFFF & (average[0].extID >> 32));
+      break;
+    case AVE_EXTID_LO:
+      value.Int = (0x00000000FFFFFFFF & average[0].extID);
+      break;
+
+    case AVE_MAG:
+      switch (field->magMode) {
+	case MAG_AVE:
+	  value.Flt = PhotAve  (field->photcode, average, secfilt);
+	  break;
+	case MAG_REF:
+	  value.Flt = PhotRef  (field->photcode, average, secfilt, measure);
+	  break;
+	case MAG_INST:
+	case MAG_CAT:
+	case MAG_SYS:
+	case MAG_REL:
+	case MAG_CAL:
+	  // XXX need to code this correctly: this returns just the first matching value
+	  value.Flt = NAN;
+	  for (i = 0; i < average[0].Nmeasure; i++) {
+	    if (field->photcode->code != measure[i].photcode) continue;
+	    value.Flt = measure[i].M;
+	    break;
+	  }
+	  break;
+	case MAG_CHISQ:
+	  value.Flt = PhotXm (field->photcode, average, secfilt);
+	  break;
+	case MAG_ERR:
+	  if ((field->photcode->type == PHOT_REF) || (field->photcode->type == PHOT_DEP)) {
+	    for (i = 0; i < average[0].Nmeasure; i++) {
+	      if (field->photcode->code != measure[i].photcode) continue;
+	      value.Flt = measure[i].dM;
+	      break;
+	    }
+	  } else {
+	    value.Flt = PhotdM (field->photcode, average, secfilt);
+	  }
+	  break;
+	case MAG_PHOT_FLAGS:
+	  if ((field->photcode->type == PHOT_REF) || (field->photcode->type == PHOT_DEP)) {
+	    for (i = 0; i < average[0].Nmeasure; i++) {
+	      if (field->photcode->code != measure[i].photcode) continue;
+	      value.Int = measure[i].photFlags;
+	      break;
+	    }
+	  } else {
+	    value.Int = 0;
+	  }
+	  break;
+	case MAG_NCODE:
+	  // XXX push these into dvo_photcode_ops APIs
+	  // XXX do I need to allow for conversion to equiv?
+	  Nsec = GetPhotcodeNsec (field->photcode->code);
+	  if (Nsec == -1) break;
+	  value.Int = secfilt[Nsec].Ncode;
+	  break;
+	case MAG_NPHOT:
+	  Nsec = GetPhotcodeNsec (field->photcode->code);
+	  if (Nsec == -1) break;
+	  value.Int = secfilt[Nsec].Nused;
+	  break;
+
+      }
+      break;
+    case AVE_dMAG:
+      value.Flt = PhotdM (field->photcode, average, secfilt);
+      break;
+    case AVE_Xm:
+      value.Flt = PhotXm (field->photcode, average, secfilt);
+      break;
+    case AVE_TYPE:
+      break;
+    case AVE_TYPEFRAC:
+      break;
+  }
+  return (value);
+}  
+
Index: trunk/Ohana/src/libdvo/src/dbExtractImages.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbExtractImages.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbExtractImages.c	(revision 31635)
@@ -0,0 +1,345 @@
+# include "dvo.h"
+
+/* time concepts */
+static time_t TimeReference;
+static int TimeFormat;
+
+static CoordTransform *celestial_to_galactic = NULL;
+static CoordTransform *celestial_to_ecliptic = NULL;
+
+static int haveGalactic = FALSE;
+static double GLON = 0.0;
+static double GLAT = 0.0;
+
+static int haveEcliptic = FALSE;
+static double ELON = 0.0;
+static double ELAT = 0.0;
+
+static int haveCelestial = FALSE;
+static double RAo = 0.0;
+static double DECo = 0.0;
+
+// define a locally-static transform
+int dbExtractImagesInitTransform (CoordTransformSystem target) {
+
+  // galactic transform is kept forever
+  if (target == COORD_GALACTIC) {
+    if (celestial_to_galactic != NULL) return (TRUE);
+    celestial_to_galactic = InitTransform (COORD_CELESTIAL, target);
+    return (TRUE);
+  }
+
+  // ecliptic transform must be updated (is weakly time-dependent)
+  if (target == COORD_ECLIPTIC) {
+    if (celestial_to_ecliptic != NULL) {
+      free (celestial_to_ecliptic);
+    }
+    celestial_to_ecliptic = InitTransform (COORD_CELESTIAL, target);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+int dbExtractImagesInit () {
+  GetTimeFormat (&TimeReference, &TimeFormat);
+  return (TRUE);
+}
+
+int dbExtractImagesReset () {
+  haveGalactic  = FALSE;
+  haveEcliptic  = FALSE;
+  haveCelestial = FALSE;
+  return (TRUE);
+}
+
+/* return image.field based on the selection */
+dbValue dbExtractImages (Image *image, off_t Nimage, off_t N, dbField *field) {
+
+  double x, y;
+  time_t t;
+  dbValue value;
+  off_t Nmosaic;
+
+  value.Flt = NAN;
+  value.Int =   0;
+
+  /* assign vector values */
+  switch (field->ID) {
+    case IMAGE_RA:
+      if (!haveCelestial) {
+	if (!FindMosaicForImage (image, Nimage, N)) return value;
+	x = 0.5*image[N].NX;
+	y = 0.5*image[N].NY;
+	XY_to_RD (&RAo, &DECo, x, y, &image[N].coords);
+	haveCelestial = TRUE;
+      }
+      value.Flt = RAo;
+      break;
+    case IMAGE_DEC:
+      if (!haveCelestial) {
+	if (!FindMosaicForImage (image, Nimage, N)) return value;
+	x = 0.5*image[N].NX;
+	y = 0.5*image[N].NY;
+	XY_to_RD (&RAo, &DECo, x, y, &image[N].coords);
+	haveCelestial = TRUE;
+      }
+      value.Flt = DECo;
+      break;
+    case IMAGE_GLON:
+      if (!haveGalactic) {
+	if (!haveCelestial) {
+	  if (!FindMosaicForImage (image, Nimage, N)) return value;
+	  x = 0.5*image[N].NX;
+	  y = 0.5*image[N].NY;
+	  XY_to_RD (&RAo, &DECo, x, y, &image[N].coords);
+	  haveCelestial = TRUE;
+	}
+	ApplyTransform (&GLON, &GLAT, RAo, DECo, celestial_to_galactic);
+	haveGalactic = TRUE;
+      }
+      value.Flt = GLON;
+      break;
+    case IMAGE_GLAT:
+      if (!haveGalactic) {
+	if (!haveCelestial) {
+	  if (!FindMosaicForImage (image, Nimage, N)) return value;
+	  x = 0.5*image[N].NX;
+	  y = 0.5*image[N].NY;
+	  XY_to_RD (&RAo, &DECo, x, y, &image[N].coords);
+	  haveCelestial = TRUE;
+	}
+	ApplyTransform (&GLON, &GLAT, RAo, DECo, celestial_to_galactic);
+	haveGalactic = TRUE;
+      }
+      value.Flt = GLAT;
+      break;
+    case IMAGE_ELON:
+      if (!haveEcliptic) {
+	if (!haveCelestial) {
+	  if (!FindMosaicForImage (image, Nimage, N)) return value;
+	  x = 0.5*image[N].NX;
+	  y = 0.5*image[N].NY;
+	  XY_to_RD (&RAo, &DECo, x, y, &image[N].coords);
+	  haveCelestial = TRUE;
+	}
+	ApplyTransform (&ELON, &ELAT, RAo, DECo, celestial_to_ecliptic);
+	haveEcliptic = TRUE;
+      }
+      value.Flt = ELON;
+      break;
+    case IMAGE_ELAT:
+      if (!haveEcliptic) {
+	if (!haveCelestial) {
+	  if (!FindMosaicForImage (image, Nimage, N)) return value;
+	  x = 0.5*image[N].NX;
+	  y = 0.5*image[N].NY;
+	  XY_to_RD (&RAo, &DECo, x, y, &image[N].coords);
+	  haveCelestial = TRUE;
+	}
+	ApplyTransform (&ELON, &ELAT, RAo, DECo, celestial_to_ecliptic);
+	haveEcliptic = TRUE;
+      }
+      value.Flt = ELAT;
+      break;
+
+    case IMAGE_THETA: {
+      double theta1, theta2, s1, s2;
+      s1 = SIGN(image[N].coords.pc1_1);
+      s2 = SIGN(image[N].coords.pc2_2);
+      theta1 = DEG_RAD*atan2 (+s1*image[N].coords.pc1_2, s1*image[N].coords.pc1_1);
+      theta2 = DEG_RAD*atan2 (-s2*image[N].coords.pc2_1, s2*image[N].coords.pc2_2);
+      value.Flt = 0.5*(theta1+theta2);
+      break; }
+    case IMAGE_SKEW: {
+      double theta1, theta2, s1, s2;
+      s1 = SIGN(image[N].coords.pc1_1);
+      s2 = SIGN(image[N].coords.pc2_2);
+      theta1 = DEG_RAD*atan2 (+s1*image[N].coords.pc1_2, s1*image[N].coords.pc1_1);
+      theta2 = DEG_RAD*atan2 (-s2*image[N].coords.pc2_1, s2*image[N].coords.pc2_2);
+      value.Flt = (theta1-theta2);
+      break; }
+    case IMAGE_SCALE: {
+      double scale1, scale2;
+      scale1 = fabs(image[N].coords.cdelt1);
+      scale2 = fabs(image[N].coords.cdelt2);
+      value.Flt = 0.5*(scale1+scale2);
+      break; }
+    case IMAGE_DSCALE: {
+      double scale1, scale2;
+      scale1 = fabs(image[N].coords.cdelt1);
+      scale2 = fabs(image[N].coords.cdelt2);
+      value.Flt = (scale1-scale2);
+      break; }
+
+    case IMAGE_TIME:
+      t = image[N].tzero + 0.5*image[N].NY * image[N].trate / 10000;
+      value.Flt = TimeValue (t, TimeReference, TimeFormat);
+      break;
+    case IMAGE_NSTAR:
+      value.Int = image[N].nstar;
+      break;
+    case IMAGE_AIRMASS:
+      value.Flt = image[N].secz;
+      break;
+    case IMAGE_NX_PIX:
+      value.Int = image[N].NX;
+      break;
+    case IMAGE_NY_PIX:
+      value.Int = image[N].NY;
+      break;
+    case IMAGE_APRESID:
+      value.Flt = image[N].apmifit;
+      break;
+    case IMAGE_DAPRESID:
+      value.Flt = image[N].dapmifit;
+      break;
+
+    case IMAGE_MCAL:
+      value.Flt = image[N].Mcal;
+      break;
+    case IMAGE_dMCAL:
+      value.Flt = image[N].dMcal;
+      break;
+    case IMAGE_XM:
+      value.Flt = pow(10.0, 0.01*image[N].Xm);
+      break;
+    case IMAGE_PHOTCODE:
+      value.Int = image[N].photcode;
+      break;
+    case IMAGE_EXPTIME:
+      value.Flt = image[N].exptime;
+      break;
+    case IMAGE_SIDTIME:
+      value.Flt = image[N].sidtime;
+      break;
+
+    case IMAGE_LATITUDE:
+      value.Flt = image[N].latitude;
+      break;
+
+    case IMAGE_DET_LIMIT:
+      value.Flt = image[N].detection_limit * 0.1;
+      break;
+    case IMAGE_SAT_LIMIT:
+      value.Flt = image[N].saturation_limit * 0.1;
+      break;
+    case IMAGE_CERROR:
+      value.Flt = image[N].cerror / 50.0;
+      break;
+
+    case IMAGE_FWHM:
+      value.Flt = (image[N].fwhm_x + image[N].fwhm_y) / 50.0;
+      break;
+    case IMAGE_FWHM_MAJ:
+      value.Flt = image[N].fwhm_x / 25.0;
+      break;
+    case IMAGE_FWHM_MIN:
+      value.Flt = image[N].fwhm_y / 25.0;
+      break;
+
+    case IMAGE_FWHM_MEDIAN:
+      if (!(Nmosaic = FindMosaicForImage (image, Nimage, N))) return value;
+      Nmosaic --; // XXX kind of a hack: FindMosaicForImage returns 0 or the mosaic seq number + 1
+      value.Flt = (image[Nmosaic].fwhm_x + image[Nmosaic].fwhm_y) / 50.0;
+      break;
+    case IMAGE_FWHM_MAJ_MEDIAN:
+      if (!(Nmosaic = FindMosaicForImage (image, Nimage, N))) return value;
+      Nmosaic --; // XXX kind of a hack: FindMosaicForImage returns 0 or the mosaic seq number + 1
+      value.Flt = image[Nmosaic].fwhm_x / 25.0;
+      break;
+    case IMAGE_FWHM_MIN_MEDIAN:
+      if (!(Nmosaic = FindMosaicForImage (image, Nimage, N))) return value;
+      Nmosaic --; // XXX kind of a hack: FindMosaicForImage returns 0 or the mosaic seq number + 1
+      value.Flt = image[Nmosaic].fwhm_y / 25.0;
+      break;
+
+    case IMAGE_TRATE:
+      value.Flt = image[N].trate / 10000.0;
+      break;
+
+    case IMAGE_NCAL:
+      value.Int = image[N].nFitPhotom;
+      break;
+    case IMAGE_SKY:
+      value.Flt = NAN;
+      break;
+    case IMAGE_FLAGS:
+      value.Int = image[N].flags;
+      break;
+    case IMAGE_CCDNUM:
+      value.Int = image[N].ccdnum;
+      break;
+
+    case IMAGE_IMAGE_ID:
+      value.Int = image[N].imageID;
+      break;
+    case IMAGE_EXTERN_ID:
+      value.Int = image[N].externID;
+      break;
+    case IMAGE_SOURCE_ID:
+      value.Int = image[N].sourceID;
+      break;
+
+      // reference pixel extractions
+    case IMAGE_X_LL_CHIP:
+    case IMAGE_Y_LL_CHIP:
+    case IMAGE_Y_LR_CHIP:
+    case IMAGE_X_UL_CHIP:
+      value.Flt = 0.0;
+      break;
+    case IMAGE_X_LR_CHIP:
+    case IMAGE_X_UR_CHIP:
+      value.Flt = image[N].NX;
+      break;
+    case IMAGE_Y_UL_CHIP:
+    case IMAGE_Y_UR_CHIP:
+      value.Flt = image[N].NX;
+      break;
+
+    case IMAGE_X_LL_FP:
+    case IMAGE_Y_LL_FP:
+      XY_to_LM (&x, &y, 0.0, 0.0, &image[N].coords);
+      value.Flt = (field->ID == IMAGE_X_LL_FP) ? x : y;
+      break;
+    case IMAGE_X_LR_FP:
+    case IMAGE_Y_LR_FP:
+      XY_to_LM (&x, &y, image[N].NX, 0.0, &image[N].coords);
+      value.Flt = (field->ID == IMAGE_X_LR_FP) ? x : y;
+      break;
+    case IMAGE_X_UL_FP:
+    case IMAGE_Y_UL_FP:
+      XY_to_LM (&x, &y, 0.0, image[N].NY, &image[N].coords);
+      value.Flt = (field->ID == IMAGE_X_UL_FP) ? x : y;
+      break;
+    case IMAGE_X_UR_FP:
+    case IMAGE_Y_UR_FP:
+      XY_to_LM (&x, &y, image[N].NX, image[N].NY, &image[N].coords);
+      value.Flt = (field->ID == IMAGE_X_UR_FP) ? x : y;
+      break;
+
+    case IMAGE_X_ERR_SYS:
+      value.Flt = image[N].dXpixSys;
+      break;
+    case IMAGE_Y_ERR_SYS:
+      value.Flt = image[N].dXpixSys;
+      break;
+    case IMAGE_MAG_ERR_SYS:
+      value.Flt = image[N].dMagSys;
+      break;
+
+    case IMAGE_NFIT_PHOTOM:
+      value.Int = image[N].nFitPhotom;
+      break;
+    case IMAGE_NFIT_ASTROM:
+      value.Int = image[N].nFitAstrom;
+      break;
+    case IMAGE_NLINK_PHOTOM:
+      value.Int = image[N].nLinkPhotom;
+      break;
+    case IMAGE_NLINK_ASTROM:
+      value.Int = image[N].nLinkAstrom;
+      break;
+  }
+  return (value);
+}  
+
Index: trunk/Ohana/src/libdvo/src/dbExtractMeasures.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbExtractMeasures.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbExtractMeasures.c	(revision 31635)
@@ -0,0 +1,466 @@
+# include "dvo.h"
+# include "dvodb.h"
+
+// to add a new field to the extractions:
+// 1) add the selection for the field below
+// 2) add the field to the ParseMeasureField in dbFields.c
+// 3) add the field to the measure enum list in dvoshell.h
+
+/* time concepts */
+static time_t TimeReference;
+static int TimeFormat;
+
+static CoordTransform *celestial_to_galactic = NULL;
+static CoordTransform *celestial_to_ecliptic = NULL;
+
+static int haveGalacticAve = FALSE;
+static double GLON_AVE = 0.0;
+static double GLAT_AVE = 0.0;
+
+static int haveEclipticAve = FALSE;
+static double ELON_AVE = 0.0;
+static double ELAT_AVE = 0.0;
+
+static int haveGalacticMeas = FALSE;
+static double GLON_MEAS = 0.0;
+static double GLAT_MEAS = 0.0;
+
+static int haveEclipticMeas = FALSE;
+static double ELON_MEAS = 0.0;
+static double ELAT_MEAS = 0.0;
+
+int dbExtractMeasuresInit () {
+  GetTimeFormat (&TimeReference, &TimeFormat);
+  return (TRUE);
+}
+
+// define a locally-static transform
+int dbExtractMeasuresInitTransform (CoordTransformSystem target) {
+
+  // galactic transform is kept forever
+  if (target == COORD_GALACTIC) {
+    if (celestial_to_galactic != NULL) return (TRUE);
+    celestial_to_galactic = InitTransform (COORD_CELESTIAL, target);
+    return (TRUE);
+  }
+
+  // ecliptic transform must be updated (is weakly time-dependent)
+  if (target == COORD_ECLIPTIC) {
+    if (celestial_to_ecliptic != NULL) {
+      free (celestial_to_ecliptic);
+    }
+    celestial_to_ecliptic = InitTransform (COORD_CELESTIAL, target);
+    return (TRUE);
+  }
+  return (FALSE);
+}
+
+int dbExtractMeasuresInitAve () {
+  haveGalacticAve = FALSE;
+  haveEclipticAve = FALSE;
+  return (TRUE);
+}
+
+int dbExtractMeasuresInitMeas () {
+  haveGalacticMeas = FALSE;
+  haveEclipticMeas = FALSE;
+  return (TRUE);
+}
+
+/* return measure.field based on the selection */
+dbValue dbExtractMeasures (Average *average, SecFilt *secfilt, Measure *measure, dbField *field) {
+
+  int Nsec;
+  dbValue value;
+  double ra, dec, x, y, dT;
+
+  Coords *mosaic;
+  PhotCode *equiv;
+
+  value.Flt = NAN;
+  value.Int =   0;
+
+  switch (field->ID) {
+    case MEAS_MAG: /* magnitudes are already determined above */
+      equiv = GetPhotcodeEquivbyCode (measure[0].photcode);
+
+      // we return the magnitude for this measure if:
+      if (field->photcode->type == PHOT_MAG) goto valid_photcode;
+      if ((field->photcode->type == PHOT_REF) && (measure[0].photcode == field->photcode->code)) goto valid_photcode;
+      if ((field->photcode->type == PHOT_DEP) && (measure[0].photcode == field->photcode->code)) goto valid_photcode;
+
+      if ((equiv != NULL) && (field->photcode->type == PHOT_SEC) && (equiv[0].code == field->photcode->code)) goto valid_photcode;
+      break;
+
+  valid_photcode:
+      switch (field->magMode) {
+	case MAG_INST:
+	  value.Flt = PhotInst (measure);  
+	  break;
+	case MAG_CAT:
+	  value.Flt = PhotCat  (measure); 
+	  break;
+	case MAG_SYS:
+	  value.Flt = PhotSys  (measure, average, secfilt); 
+	  break;
+	case MAG_REL:
+	  value.Flt = PhotRel  (measure, average, secfilt); 
+	  break;
+	case MAG_CAL:
+	  value.Flt = PhotCal  (measure, average, secfilt, measure, equiv); 
+	  break;
+	case MAG_AVE:
+	  value.Flt = PhotAve  (equiv, average, secfilt); 
+	  break;
+	case MAG_REF:
+	  value.Flt = PhotRef  (equiv, average, secfilt, measure); 
+	  break;
+	case MAG_APER:
+	  value.Flt = PhotAper  (measure); 
+	  break;
+	case MAG_ERR:
+	  value.Flt = measure[0].dM;
+	  break;
+	case MAG_AVE_ERR:
+	  value.Flt = PhotdM  (equiv, average, secfilt); 
+	  break;
+	case MAG_PHOT_FLAGS:
+	  if ((field->photcode->type == PHOT_REF) || (field->photcode->type == PHOT_DEP)) {
+	    value.Int = measure[0].photFlags;
+	  } else {
+	    value.Int = 0;
+	  }
+	  break;
+	case MAG_CHISQ:
+	  value.Flt = PhotXm  (equiv, average, secfilt); 
+	  break;
+	case MAG_NCODE:
+	  if (equiv == NULL) {
+	    value.Int = 0;
+	    break;
+	  }
+	  Nsec = GetPhotcodeNsec (equiv->code);
+	  if (Nsec == -1) break;
+	  value.Int = secfilt[Nsec].Ncode;
+	  break;
+	case MAG_NPHOT:
+	  if (equiv == NULL) {
+	    value.Int = 0;
+	    break;
+	  }
+	  Nsec = GetPhotcodeNsec (equiv->code);
+	  if (Nsec == -1) break;
+	  value.Int = secfilt[Nsec].Nused;
+	  break;
+      }
+      break;
+    case MEAS_RA: /* OK */
+      value.Flt = average[0].R - measure[0].dR / 3600.0;
+      break;
+    case MEAS_DEC: /* OK */
+      value.Flt = average[0].D - measure[0].dD / 3600.0;
+      break;
+    case MEAS_RA_AVE: /* OK */
+      value.Flt = average[0].R;
+      break;
+    case MEAS_DEC_AVE: /* OK */
+      value.Flt = average[0].D;
+      break;
+
+    case MEAS_GLON:
+      if (!haveGalacticMeas) {
+	ApplyTransform (&GLON_MEAS, &GLAT_MEAS, average[0].R - measure[0].dR / 3600.0, average[0].D - measure[0].dD / 3600.0, celestial_to_galactic);
+	haveGalacticMeas = TRUE;
+      }
+      value.Flt = GLON_MEAS;
+      break;
+    case MEAS_GLAT:
+      if (!haveGalacticMeas) {
+	ApplyTransform (&GLON_MEAS, &GLAT_MEAS, average[0].R - measure[0].dR / 3600.0, average[0].D - measure[0].dD / 3600.0, celestial_to_galactic);
+	haveGalacticMeas = TRUE;
+      }
+      value.Flt = GLAT_MEAS;
+      break;
+    case MEAS_ELON:
+      if (!haveEclipticMeas) {
+	ApplyTransform (&ELON_MEAS, &ELAT_MEAS, average[0].R - measure[0].dR / 3600.0, average[0].D - measure[0].dD / 3600.0, celestial_to_ecliptic);
+	haveEclipticMeas = TRUE;
+      }
+      value.Flt = ELON_MEAS;
+      break;
+    case MEAS_ELAT:
+      if (!haveEclipticMeas) {
+	ApplyTransform (&ELON_MEAS, &ELAT_MEAS, average[0].R - measure[0].dR / 3600.0, average[0].D - measure[0].dD / 3600.0, celestial_to_ecliptic);
+	haveEclipticMeas = TRUE;
+      }
+      value.Flt = ELAT_MEAS;
+      break;
+
+    case MEAS_GLON_AVE:
+      if (!haveGalacticAve) {
+	ApplyTransform (&GLON_AVE, &GLAT_AVE, average[0].R, average[0].D, celestial_to_galactic);
+	haveGalacticAve = TRUE;
+      }
+      value.Flt = GLON_AVE;
+      break;
+    case MEAS_GLAT_AVE:
+      if (!haveGalacticAve) {
+	ApplyTransform (&GLON_AVE, &GLAT_AVE, average[0].R, average[0].D, celestial_to_galactic);
+	haveGalacticAve = TRUE;
+      }
+      value.Flt = GLAT_AVE;
+      break;
+    case MEAS_ELON_AVE:
+      if (!haveEclipticAve) {
+	ApplyTransform (&ELON_AVE, &ELAT_AVE, average[0].R, average[0].D, celestial_to_ecliptic);
+	haveEclipticAve = TRUE;
+      }
+      value.Flt = ELON_AVE;
+      break;
+    case MEAS_ELAT_AVE:
+      if (!haveEclipticAve) {
+	ApplyTransform (&ELON_AVE, &ELAT_AVE, average[0].R, average[0].D, celestial_to_ecliptic);
+	haveEclipticAve = TRUE;
+      }
+      value.Flt = ELAT_AVE;
+      break;
+
+    case MEAS_RA_AVE_ERR: /* OK */
+      value.Flt = average[0].dR;
+      break;
+    case MEAS_DEC_AVE_ERR: /* OK */
+      value.Flt = average[0].dD;
+      break;
+    case MEAS_U_RA: /* OK */
+      value.Flt = average[0].uR;
+      break;
+    case MEAS_U_DEC: /* OK */
+      value.Flt = average[0].uD;
+      break;
+    case MEAS_U_RA_ERR: /* OK */
+      value.Flt = average[0].duR;
+      break;
+    case MEAS_U_DEC_ERR: /* OK */
+      value.Flt = average[0].duD;
+      break;
+    case MEAS_PAR: /* OK */
+      value.Flt = average[0].R;
+      break;
+    case MEAS_PAR_ERR: /* OK */
+      value.Flt = average[0].D;
+      break;
+    case MEAS_CHISQ_POS: /* OK */
+      value.Flt = average[0].ChiSqAve;
+      break;
+    case MEAS_CHISQ_PM: /* OK */
+      value.Flt = average[0].ChiSqPM;
+      break;
+    case MEAS_CHISQ_PAR: /* OK */
+      value.Flt = average[0].ChiSqPar;
+      break;
+    case MEAS_TMEAN: /* OK */
+      value.Flt = TimeValue (average[0].Tmean, TimeReference, TimeFormat);
+      break;
+    case MEAS_TRANGE: /* OK */
+      value.Flt = TimeValue (average[0].Trange, 0, TimeFormat);
+      break;
+    case MEAS_NMEAS: /* OK */
+      value.Int = average[0].Nmeasure;
+      break;
+    case MEAS_NMISS: /* OK */
+      value.Int = average[0].Nmissing;
+      break;
+    case MEAS_NPOS: /* OK */
+      value.Int = average[0].Npos;
+      break;
+    case MEAS_OBJ_FLAGS: /* OK */
+      value.Int = average[0].flags;
+      break;
+    // note that these represent the ra displacement relative to the average, not 
+    // the error.
+    case MEAS_RA_OFFSET: /* OK */
+      value.Flt = measure[0].dR;
+      break;
+    case MEAS_DEC_OFFSET: /* OK */
+      value.Flt = measure[0].dD;
+      break;
+    case MEAS_RA_FIT_OFFSET: /* OK */
+      dT = (measure[0].t - average[0].Tmean) / (86400*365.25);
+      value.Flt = average[0].uR * dT + measure[0].dR;
+      break;
+    case MEAS_DEC_FIT_OFFSET: /* OK */
+      dT = (measure[0].t - average[0].Tmean) / (86400*365.25);
+      value.Flt = average[0].uD * dT + measure[0].dD;
+      break;
+    case MEAS_RA_OFFSET_ERR: /* OK */
+      value.Flt = NAN;
+      break;
+    case MEAS_DEC_OFFSET_ERR: /* OK */
+      value.Flt = NAN;
+      break;
+    case MEAS_AIRMASS: /* OK */
+      value.Flt = measure[0].airmass;
+      break;
+    case MEAS_AZ: /* OK */
+      value.Flt = measure[0].az;
+      break;
+    case MEAS_ALT: /* OK */
+      value.Flt = 90.0 - DEG_RAD*acos(1.0/measure[0].airmass);
+      break;
+    case MEAS_EXPTIME: /* OK */
+      value.Flt = pow (10.0, measure[0].dt * 0.4);
+      break;
+    case MEAS_PHOTCODE_EQUIV: /* OK */
+      value.Int = GetPhotcodeEquivCodebyCode (measure[0].photcode);
+      break;
+    case MEAS_PHOTCODE: /* OK */
+      value.Int = measure[0].photcode;
+      break;
+    case MEAS_TIME: /* OK */
+      value.Flt = TimeValue (measure[0].t, TimeReference, TimeFormat);
+      break;
+    case MEAS_FWHM: /* OK */
+      value.Flt = FromShortPixels(measure[0].FWx + measure[0].FWy) / 2.0;
+      break;
+    case MEAS_FWHM_MAJ: /* OK */
+      value.Flt = FromShortPixels(measure[0].FWx);
+      break;
+    case MEAS_FWHM_MIN: /* OK */
+      value.Flt = FromShortPixels(measure[0].FWy);
+      break;
+    case MEAS_THETA: /* OK */
+      value.Flt = FromShortDegrees(measure[0].theta);
+      break;
+    case MEAS_MXX: /* OK */
+      value.Flt = FromShortPixels(measure[0].Mxx);
+      break;
+    case MEAS_MXY: /* OK */
+      value.Flt = FromShortPixels(measure[0].Mxy);
+      break;
+    case MEAS_MYY: /* OK */
+      value.Flt = FromShortPixels(measure[0].Myy);
+      break;
+    case MEAS_DOPHOT: /* OK */
+      value.Int = (measure[0].photFlags >> 16);
+      break;
+    case MEAS_DB_FLAGS: /* ? */
+      value.Int = measure[0].dbFlags;
+      break;
+    case MEAS_PHOT_FLAGS: /* ? */
+      value.Int = measure[0].photFlags;
+      break;
+    case MEAS_XCCD: /* OK */
+/* I need to perform this conversion for ELIXIR and LONEOS formats on load */      
+# if 1
+      value.Flt = measure[0].Xccd;
+# else
+      { 
+	Image *image;
+	ra  = average[0].R - measure[0].dR / 3600.0;
+	dec = average[0].D - measure[0].dD / 3600.0;
+	image = MatchImageDVO (measure[0].t, measure[0].photcode, measure[0].imageID);
+	if (image == NULL) break;
+	RD_to_XY (&x, &y, ra, dec, &image[0].coords);
+	value.Flt = x;
+      }
+# endif
+      break;
+    case MEAS_YCCD: /* OK */
+/* I need to perform this conversion for ELIXIR and LONEOS formats on load */      
+# if 1
+      value.Flt = measure[0].Yccd;
+# else
+      {
+	Image *image;
+	ra  = average[0].R - measure[0].dR / 3600.0;
+	dec = average[0].D - measure[0].dD / 3600.0;
+	image = MatchImageDVO (measure[0].t, measure[0].photcode, measure[0].imageID);
+	if (image == NULL) break;
+	RD_to_XY (&x, &y, ra, dec, &image[0].coords);
+	value.Flt = y;
+      }
+# endif
+      break;
+    case MEAS_XCCD_ERR: /* OK */
+      value.Flt = FromShortPixels(measure[0].dXccd);
+      break;
+    case MEAS_YCCD_ERR: /* OK */
+      value.Flt = FromShortPixels(measure[0].dYccd);
+      break;
+    case MEAS_POS_SYS_ERR: /* OK */
+      value.Flt = FromShortPixels(measure[0].dRsys);
+      break;
+    case MEAS_XMOSAIC: /* OK */
+      ra  = average[0].R - measure[0].dR / 3600.0;
+      dec = average[0].D - measure[0].dD / 3600.0;
+      mosaic = MatchMosaic (measure[0].t, measure[0].photcode);
+      if (mosaic == NULL) break;
+      RD_to_XY (&x, &y, ra, dec, mosaic);
+      value.Flt = x;
+      break;
+    case MEAS_YMOSAIC: /* OK */
+      ra  = average[0].R - measure[0].dR / 3600.0;
+      dec = average[0].D - measure[0].dD / 3600.0;
+      mosaic = MatchMosaic (measure[0].t, measure[0].photcode);
+      if (mosaic == NULL) break;
+      RD_to_XY (&x, &y, ra, dec, mosaic);
+      value.Flt = y;
+      break;
+
+    case MEAS_SKY: /* OK */
+      value.Flt = measure[0].Sky;
+      break;
+    case MEAS_dSKY: /* OK */
+      value.Flt = measure[0].dSky;
+      break;
+    case MEAS_DET_ID: /* OK */
+      value.Int = measure[0].detID;
+      break;
+    case MEAS_OBJ_ID: /* OK */
+      value.Int = average[0].objID;
+      break;
+    case MEAS_CAT_ID: /* OK */
+      value.Int = average[0].catID;
+      break;
+    case MEAS_IMAGE_ID: /* OK */
+      value.Int = measure[0].imageID;
+      break;
+    case MEAS_PSF_QF: /* OK */
+      value.Flt = measure[0].psfQual;
+      break;
+    case MEAS_PSF_QF_PERFECT: /* OK */
+      value.Flt = NAN;
+      break;
+    case MEAS_PSF_CHISQ: /* OK */
+      value.Flt = measure[0].psfChisq;
+      break;
+    case MEAS_PSF_NDOF: /* OK */
+      value.Int = measure[0].psfNdof;
+      break;
+    case MEAS_PSF_NPIX: /* OK */
+      value.Int = measure[0].psfNpix;
+      break;
+    case MEAS_CR_NSIGMA: /* OK */
+      value.Flt = measure[0].crNsigma;
+      break;
+    case MEAS_EXT_NSIGMA: /* OK */
+      value.Flt = measure[0].extNsigma;
+      break;
+    case MEAS_EXTERN_ID: /* OK */
+      {
+	Image *image;
+	image = MatchImageDVO (measure[0].t, measure[0].photcode, measure[0].imageID);
+	if (image == NULL) break;
+	value.Int = image->externID;
+      }
+      break;
+
+      // add the star/galaxy sep -- 
+  }
+  return (value);
+}
+
+/** the mosaic entries do not use the registered mosaic found 
+    by MatchImage (via FindMosaicForImage).  Rather, they use
+    a coordinate frame saved by SetImageSelection 
+**/
Index: trunk/Ohana/src/libdvo/src/dbFields.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbFields.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbFields.c	(revision 31635)
@@ -0,0 +1,451 @@
+# include "dvo.h"
+
+void dbFreeFields (dbField *fields, int Nfields) {
+
+  int i;
+
+  if (fields == NULL) return;
+
+  for (i = 0; i < Nfields; i++) {
+    if (fields[i].name != NULL) free (fields[i].name);
+    if (fields[i].photcode != NULL) {
+      if (fields[i].photcode[0].type == PHOT_MAG) {
+        free (fields[i].photcode);
+      }
+    }
+  }
+  free (fields);
+}
+
+void dbInitField (dbField *field) {
+  field->name = NULL;
+  field->extract = FALSE;
+  field->table = 0;
+  field->ID = 0;
+  field->type = OPIHI_FLT;
+  field->magMode = 0;
+  field->photcode = NULL;
+}
+
+int GetMagMode (char *string) {
+
+  if (!strcasecmp (string, "inst"))      return (MAG_INST);
+  if (!strcasecmp (string, "cat"))       return (MAG_CAT);
+  if (!strcasecmp (string, "sys"))       return (MAG_SYS);
+  if (!strcasecmp (string, "rel"))       return (MAG_REL);
+  if (!strcasecmp (string, "cal"))       return (MAG_CAL);
+  if (!strcasecmp (string, "ave"))       return (MAG_AVE);
+  if (!strcasecmp (string, "ref"))       return (MAG_REF);
+  if (!strcasecmp (string, "ap"))        return (MAG_APER);
+  if (!strcasecmp (string, "aper"))      return (MAG_APER);
+  if (!strcasecmp (string, "err"))       return (MAG_ERR);
+  if (!strcasecmp (string, "aveerr"))    return (MAG_AVE_ERR);
+  if (!strcasecmp (string, "photflags")) return (MAG_PHOT_FLAGS);
+  if (!strcasecmp (string, "chisq"))     return (MAG_CHISQ);
+  if (!strcasecmp (string, "ncode"))     return (MAG_NCODE);
+  if (!strcasecmp (string, "nphot"))     return (MAG_NPHOT);
+  return (MAG_NONE);
+}
+
+PhotCode *ParsePhotcodeField (char *field, int *mode, int defMode) {
+
+  int useDefault;
+  char *tmpstring, *p;
+  PhotCode *code;
+
+  *mode = defMode;
+  useDefault = TRUE;
+
+  p = strchr (field, ':');
+  if (p != NULL) {
+    *mode = GetMagMode (p + 1);
+    useDefault = FALSE;
+    if (*mode == MAG_NONE) return (NULL);
+    tmpstring = strncreate (field, p - field);
+  } else {
+    tmpstring = strcreate (field);
+  }
+  if (!strcasecmp (tmpstring, "MAG")) {
+    ALLOCATE (code, PhotCode, 1);
+    code[0].code = 0;
+    strcpy (code[0].name, "MAG");
+    code[0].type = PHOT_MAG;
+    free (tmpstring);
+    return (code);
+  }
+  code = GetPhotcodebyName (tmpstring);
+  if (!code) {
+      return NULL;
+  }
+
+  // enforce compatibility
+  if (useDefault) {
+    if (code[0].type == PHOT_REF) {
+      *mode = MAG_CAT;
+    }
+    if (code[0].type == PHOT_DEP) {
+      *mode = MAG_REL;
+    }
+  } 
+  free (tmpstring);
+  return (code);
+}
+
+# define ESCAPE(F,M,T) { \
+  field->ID = (F); \
+  field->magMode = (M); \
+  field->type = (T); \
+  field->photcode = NULL; \
+  return (TRUE); }
+
+int ParseMeasureField (dbField *field, char *fieldName) {
+
+  int mode;
+  PhotCode *code;
+
+  field->table = DVO_TABLE_MEASURE;
+  field->name  = strcreate (fieldName);
+
+  if (!strcasecmp (fieldName, "GLON"))       {
+    dbExtractMeasuresInitTransform (COORD_GALACTIC);
+    ESCAPE (MEAS_GLON, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "GLAT")) {
+    dbExtractMeasuresInitTransform (COORD_GALACTIC);
+    ESCAPE (MEAS_GLAT, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "GLON:AVE")) {
+    dbExtractMeasuresInitTransform (COORD_GALACTIC);
+    ESCAPE (MEAS_GLON_AVE, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "GLAT:AVE")) {
+    dbExtractMeasuresInitTransform (COORD_GALACTIC);
+    ESCAPE (MEAS_GLAT_AVE, MAG_NONE, OPIHI_FLT);
+  }
+
+  if (!strcasecmp (fieldName, "ELON"))       {
+    dbExtractMeasuresInitTransform (COORD_ECLIPTIC);
+    ESCAPE (MEAS_ELON, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "ELAT")) {
+    dbExtractMeasuresInitTransform (COORD_ECLIPTIC);
+    ESCAPE (MEAS_ELAT, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "ELON:AVE")) {
+    dbExtractMeasuresInitTransform (COORD_ECLIPTIC);
+    ESCAPE (MEAS_ELON_AVE, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "ELAT:AVE")) {
+    dbExtractMeasuresInitTransform (COORD_ECLIPTIC);
+    ESCAPE (MEAS_ELAT_AVE, MAG_NONE, OPIHI_FLT);
+  }
+
+  if (!strcasecmp (fieldName, "RA"))         	 ESCAPE (MEAS_RA,             MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "DEC"))        	 ESCAPE (MEAS_DEC,            MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "RA:AVE"))     	 ESCAPE (MEAS_RA_AVE,         MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "DEC:AVE"))    	 ESCAPE (MEAS_DEC_AVE,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "RA:ERR"))     	 ESCAPE (MEAS_RA_AVE_ERR,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "DEC:ERR"))    	 ESCAPE (MEAS_DEC_AVE_ERR,    MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "uRA"))        	 ESCAPE (MEAS_U_RA,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "uDEC"))       	 ESCAPE (MEAS_U_DEC,          MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "duRA"))       	 ESCAPE (MEAS_U_RA_ERR,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "duDEC"))      	 ESCAPE (MEAS_U_DEC_ERR,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "PAR"))        	 ESCAPE (MEAS_PAR,            MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dPAR"))       	 ESCAPE (MEAS_PAR_ERR,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dR"))         	 ESCAPE (MEAS_RA_OFFSET,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dD"))         	 ESCAPE (MEAS_DEC_OFFSET,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dR:FIT"))     	 ESCAPE (MEAS_RA_FIT_OFFSET,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dD:FIT"))     	 ESCAPE (MEAS_DEC_FIT_OFFSET, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dR:ERR"))     	 ESCAPE (MEAS_RA_OFFSET_ERR,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dD:ERR"))     	 ESCAPE (MEAS_DEC_OFFSET_ERR, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ChiSqPos"))       ESCAPE (MEAS_CHISQ_POS,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ChiSqPM"))        ESCAPE (MEAS_CHISQ_PM,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ChiSqPar"))       ESCAPE (MEAS_CHISQ_PAR,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Tmean"))          ESCAPE (MEAS_TMEAN,          MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Trange"))         ESCAPE (MEAS_TRANGE,         MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "nmeas"))      	 ESCAPE (MEAS_NMEAS,          MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "nmiss"))      	 ESCAPE (MEAS_NMISS,          MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "npos"))      	 ESCAPE (MEAS_NPOS,           MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "OBJFLAGS"))   	 ESCAPE (MEAS_OBJ_FLAGS,      MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "OBJ_FLAGS"))   	 ESCAPE (MEAS_OBJ_FLAGS,      MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "DB_FLAGS"))   	 ESCAPE (MEAS_DB_FLAGS,       MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "PHOT_FLAGS")) 	 ESCAPE (MEAS_PHOT_FLAGS,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "DBFLAGS"))   	 ESCAPE (MEAS_DB_FLAGS,       MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "PHOTFLAGS")) 	 ESCAPE (MEAS_PHOT_FLAGS,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "AIRMASS"))    	 ESCAPE (MEAS_AIRMASS,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ALT"))        	 ESCAPE (MEAS_ALT,            MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "AZ"))         	 ESCAPE (MEAS_AZ,             MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "EXPTIME"))    	 ESCAPE (MEAS_EXPTIME,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "PHOTCODE"))   	 ESCAPE (MEAS_PHOTCODE,       MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "PHOTCODE:EQUIV")) ESCAPE (MEAS_PHOTCODE_EQUIV, MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "TIME"))       	 ESCAPE (MEAS_TIME,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM"))       	 ESCAPE (MEAS_FWHM,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MAJ"))   	 ESCAPE (MEAS_FWHM_MAJ,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MIN"))   	 ESCAPE (MEAS_FWHM_MIN,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "THETA"))      	 ESCAPE (MEAS_THETA,          MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "POSANGLE"))     	 ESCAPE (MEAS_POSANGLE,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "PLATESCALE"))   	 ESCAPE (MEAS_PLATESCALE,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "MXX"))       	 ESCAPE (MEAS_MXX,            MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "MYY"))       	 ESCAPE (MEAS_MYY,            MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "MXY"))       	 ESCAPE (MEAS_MXY,            MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "DOPHOT"))     	 ESCAPE (MEAS_DOPHOT,         MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "XCCD"))       	 ESCAPE (MEAS_XCCD,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "YCCD"))       	 ESCAPE (MEAS_YCCD,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "XCCD:ERR"))   	 ESCAPE (MEAS_XCCD_ERR,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "YCCD:ERR"))   	 ESCAPE (MEAS_YCCD_ERR,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "POS_SYS_ERR"))    ESCAPE (MEAS_POS_SYS_ERR,    MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "XMOSAIC"))    	 ESCAPE (MEAS_XMOSAIC,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "YMOSAIC"))    	 ESCAPE (MEAS_YMOSAIC,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "XCHIP"))      	 ESCAPE (MEAS_XCCD,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "YCHIP"))      	 ESCAPE (MEAS_YCCD,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "XFPA"))       	 ESCAPE (MEAS_XMOSAIC,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "YFPA"))       	 ESCAPE (MEAS_YMOSAIC,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "DETID"))      	 ESCAPE (MEAS_DET_ID,         MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "OBJID"))      	 ESCAPE (MEAS_OBJ_ID,         MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "CATID"))      	 ESCAPE (MEAS_CAT_ID,         MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "IMAGEID"))    	 ESCAPE (MEAS_IMAGE_ID,       MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "PSF_QF"))     	 ESCAPE (MEAS_PSF_QF,         MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "PSF_QF_PERFECT")) ESCAPE (MEAS_PSF_QF_PERFECT, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "PSF_CHISQ"))  	 ESCAPE (MEAS_PSF_CHISQ,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "PSF_NDOF"))  	 ESCAPE (MEAS_PSF_NDOF,       MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "PSF_NPIX"))  	 ESCAPE (MEAS_PSF_NPIX,       MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "CR_NSIGMA"))  	 ESCAPE (MEAS_CR_NSIGMA,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "EXT_NSIGMA")) 	 ESCAPE (MEAS_EXT_NSIGMA,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "SKY"))        	 ESCAPE (MEAS_SKY,            MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "SKY_ERR"))    	 ESCAPE (MEAS_dSKY,           MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "externID"))    	 ESCAPE (MEAS_EXTERN_ID,      MAG_NONE, OPIHI_INT);
+
+  // for words that don't parse, try a photcode
+
+  // check for code:mode in photcode name 
+  code = ParsePhotcodeField (fieldName, &mode, MAG_REL);
+  if (code == NULL) {
+    gprint (GP_ERR, "unknown field '%s' for measurement table in DVO database\n", fieldName);
+    return (FALSE);
+  }
+
+  field->ID = MEAS_MAG;
+  field->magMode = mode;
+  switch (mode) {
+    case MAG_NCODE:
+    case MAG_NPHOT:
+    case MAG_PHOT_FLAGS:
+      field->type = OPIHI_INT;
+      break;
+    default:
+      field->type = OPIHI_FLT;
+      break;
+  }
+  field->photcode = code;
+  return (TRUE);
+}
+
+int ParseAverageField (dbField *field, char *fieldName) {
+
+  int mode;
+  PhotCode *code;
+
+  field->table = DVO_TABLE_AVERAGE;
+  field->name  = strcreate (fieldName);
+
+  // if either GLON or GLAT is requested, we set up a static tranformation 
+  // at prepare to calculate the values only once for each row
+  if (!strcasecmp (fieldName, "GLON"))  { 
+    dbExtractAveragesInitTransform (COORD_GALACTIC);
+    ESCAPE (AVE_GLON, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "GLAT"))  {
+    dbExtractAveragesInitTransform (COORD_GALACTIC);
+    ESCAPE (AVE_GLAT, MAG_NONE, OPIHI_FLT);
+  }
+
+  // if either ELON or ELAT is requested, we set up a static tranformation 
+  // at prepare to calculate the values only once for each row
+  if (!strcasecmp (fieldName, "ELON"))  { 
+    dbExtractAveragesInitTransform (COORD_ECLIPTIC);
+    ESCAPE (AVE_ELON, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "ELAT"))  {
+    dbExtractAveragesInitTransform (COORD_ECLIPTIC);
+    ESCAPE (AVE_ELAT, MAG_NONE, OPIHI_FLT);
+  }
+
+  if (!strcasecmp (fieldName, "RA"))        ESCAPE (AVE_RA,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "DEC"))       ESCAPE (AVE_DEC,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "GLON"))      ESCAPE (AVE_GLON,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "GLAT"))      ESCAPE (AVE_GLAT,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ELON"))      ESCAPE (AVE_ELON,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ELAT"))      ESCAPE (AVE_ELAT,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dRA"))       ESCAPE (AVE_RA_ERR,    MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dDEC"))      ESCAPE (AVE_DEC_ERR,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "uRA"))       ESCAPE (AVE_U_RA,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "uDEC"))      ESCAPE (AVE_U_DEC,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "duRA"))      ESCAPE (AVE_U_RA_ERR,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "duDEC"))     ESCAPE (AVE_U_DEC_ERR, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "PAR"))       ESCAPE (AVE_PAR,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dPAR"))      ESCAPE (AVE_PAR_ERR,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ChiSqPos"))  ESCAPE (AVE_CHISQ_POS, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ChiSqPM"))   ESCAPE (AVE_CHISQ_PM, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ChiSqPar"))  ESCAPE (AVE_CHISQ_PAR, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Tmean"))     ESCAPE (AVE_TMEAN,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Trange"))    ESCAPE (AVE_TRANGE,    MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "NMEAS"))     ESCAPE (AVE_NMEAS,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "NMISS"))     ESCAPE (AVE_NMISS,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "NPOS"))      ESCAPE (AVE_NPOS,      MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "NASTROM"))   ESCAPE (AVE_NPOS,      MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "FLAGS"))     ESCAPE (AVE_OBJ_FLAGS, MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "OBJ_FLAGS")) ESCAPE (AVE_OBJ_FLAGS, MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "OBJFLAGS"))  ESCAPE (AVE_OBJ_FLAGS, MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "OBJID"))     ESCAPE (AVE_OBJID,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "CATID"))     ESCAPE (AVE_CATID,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "EXTID_HI"))  ESCAPE (AVE_EXTID_HI,  MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "EXTID_LO"))  ESCAPE (AVE_EXTID_LO,  MAG_NONE, OPIHI_INT);
+
+  // if (!strcasecmp (fieldName, "Xp"))      ESCAPE (AVE_Xp,        MAG_NONE, OPIHI_FLT);
+  // if (!strcasecmp (fieldName, "TYPE"))    ESCAPE (AVE_TYPE,      MAG_NONE, OPIHI_INT);
+  // for words that don't parse, try a photcode
+
+  // check for code:mode in photcode name 
+  code = ParsePhotcodeField (fieldName, &mode, MAG_AVE);
+  if (code == NULL) {
+    gprint (GP_ERR, "unknown field '%s' for average table in DVO database\n", fieldName);
+    return (FALSE);
+  }
+
+  if (code[0].type == PHOT_MAG) {
+    gprint (GP_ERR, "'mag' is ambiguous for avextract\n");
+    free (code);
+    return (FALSE);
+  }
+
+  field->ID = AVE_MAG;
+  field->magMode = mode;
+  switch (mode) {
+    case MAG_NCODE:
+    case MAG_NPHOT:
+    case MAG_PHOT_FLAGS:
+      field->type = OPIHI_INT;
+      break;
+    default:
+      field->type = OPIHI_FLT;
+      break;
+  }
+  field->photcode = code;
+  return (TRUE);
+}
+
+
+int ParseImageField (dbField *field, char *fieldName) {
+
+  field->table = DVO_TABLE_IMAGE;
+  field->name  = strcreate (fieldName);
+
+  // if either GLON or GLAT is requested, we set up a static tranformation 
+  // at prepare to calculate the values only once for each row
+  if (!strcasecmp (fieldName, "GLON"))  { 
+    dbExtractImagesInitTransform (COORD_GALACTIC);
+    ESCAPE (IMAGE_GLON, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "GLAT"))  {
+    dbExtractImagesInitTransform (COORD_GALACTIC);
+    ESCAPE (IMAGE_GLAT, MAG_NONE, OPIHI_FLT);
+  }
+
+  // if either ELON or ELAT is requested, we set up a static tranformation 
+  // at prepare to calculate the values only once for each row
+  if (!strcasecmp (fieldName, "ELON"))  { 
+    dbExtractImagesInitTransform (COORD_ECLIPTIC);
+    ESCAPE (IMAGE_ELON, MAG_NONE, OPIHI_FLT);
+  }
+  if (!strcasecmp (fieldName, "ELAT"))  {
+    dbExtractImagesInitTransform (COORD_ECLIPTIC);
+    ESCAPE (IMAGE_ELAT, MAG_NONE, OPIHI_FLT);
+  }
+
+  if (!strcasecmp (fieldName, "RA"       )) ESCAPE (IMAGE_RA,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "DEC"      )) ESCAPE (IMAGE_DEC,       MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "GLON"     )) ESCAPE (IMAGE_GLON,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "GLAT"     )) ESCAPE (IMAGE_GLAT,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ELON"     )) ESCAPE (IMAGE_ELON,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "ELAT"     )) ESCAPE (IMAGE_ELAT,      MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "theta"    )) ESCAPE (IMAGE_THETA,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "skew"     )) ESCAPE (IMAGE_SKEW,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "scale"    )) ESCAPE (IMAGE_SCALE,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dscale"   )) ESCAPE (IMAGE_DSCALE,    MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "time"     )) ESCAPE (IMAGE_TIME,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "nstar"    )) ESCAPE (IMAGE_NSTAR,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "airmass"  )) ESCAPE (IMAGE_AIRMASS,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "NX"       )) ESCAPE (IMAGE_NX_PIX,    MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "NY"       )) ESCAPE (IMAGE_NY_PIX,    MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "apresid"  )) ESCAPE (IMAGE_APRESID,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dapresid" )) ESCAPE (IMAGE_DAPRESID,  MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "Mcal"     )) ESCAPE (IMAGE_MCAL,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dMcal"    )) ESCAPE (IMAGE_dMCAL,     MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Xm"       )) ESCAPE (IMAGE_XM,        MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "photcode" )) ESCAPE (IMAGE_PHOTCODE,  MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "exptime"  )) ESCAPE (IMAGE_EXPTIME,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "sidtime"  )) ESCAPE (IMAGE_SIDTIME,   MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "latitude" )) ESCAPE (IMAGE_LATITUDE,  MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "detlimit" )) ESCAPE (IMAGE_DET_LIMIT, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "satlimit" )) ESCAPE (IMAGE_SAT_LIMIT, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "cerror"   )) ESCAPE (IMAGE_CERROR,    MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "FWHM"       )) ESCAPE (IMAGE_FWHM,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MAJ"   )) ESCAPE (IMAGE_FWHM_MAJ,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MIN"   )) ESCAPE (IMAGE_FWHM_MIN,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MAJOR" )) ESCAPE (IMAGE_FWHM_MAJ,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MINOR" )) ESCAPE (IMAGE_FWHM_MIN,  MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "FWHM_MEDIAN"    ))   ESCAPE (IMAGE_FWHM_MEDIAN,      MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MAJ_MEDIAN"))   ESCAPE (IMAGE_FWHM_MAJ_MEDIAN,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MIN_MEDIAN"))   ESCAPE (IMAGE_FWHM_MIN_MEDIAN,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MAJOR_MEDIAN")) ESCAPE (IMAGE_FWHM_MAJ_MEDIAN,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "FWHM_MINOR_MEDIAN")) ESCAPE (IMAGE_FWHM_MIN_MEDIAN,  MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "trate"    )) ESCAPE (IMAGE_TRATE,     MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "ncal"     )) ESCAPE (IMAGE_NCAL,      MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "sky"      )) ESCAPE (IMAGE_SKY,       MAG_NONE, OPIHI_FLT); // deprecated for now
+
+  if (!strcasecmp (fieldName, "imflags"  )) ESCAPE (IMAGE_FLAGS,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "flags"    )) ESCAPE (IMAGE_FLAGS,     MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "ccdnum"   )) ESCAPE (IMAGE_CCDNUM,    MAG_NONE, OPIHI_INT);
+
+  if (!strcasecmp (fieldName, "imageID"  )) ESCAPE (IMAGE_IMAGE_ID,  MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "externID" )) ESCAPE (IMAGE_EXTERN_ID, MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "sourceID" )) ESCAPE (IMAGE_SOURCE_ID, MAG_NONE, OPIHI_INT);
+
+  if (!strcasecmp (fieldName, "X_LL_CHIP")) ESCAPE (IMAGE_X_LL_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "X_LR_CHIP")) ESCAPE (IMAGE_X_LR_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "X_UL_CHIP")) ESCAPE (IMAGE_X_UL_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "X_UR_CHIP")) ESCAPE (IMAGE_X_UR_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_LL_CHIP")) ESCAPE (IMAGE_Y_LL_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_LR_CHIP")) ESCAPE (IMAGE_Y_LR_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_UL_CHIP")) ESCAPE (IMAGE_Y_UL_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_UR_CHIP")) ESCAPE (IMAGE_Y_UR_CHIP, MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "X_LL_FP"  )) ESCAPE (IMAGE_X_LL_FP,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "X_LR_FP"  )) ESCAPE (IMAGE_X_LR_FP,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "X_UL_FP"  )) ESCAPE (IMAGE_X_UL_FP,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "X_UR_FP"  )) ESCAPE (IMAGE_X_UR_FP,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_LL_FP"  )) ESCAPE (IMAGE_Y_LL_FP,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_LR_FP"  )) ESCAPE (IMAGE_Y_LR_FP,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_UL_FP"  )) ESCAPE (IMAGE_Y_UL_FP,   MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "Y_UR_FP"  )) ESCAPE (IMAGE_Y_UR_FP,   MAG_NONE, OPIHI_FLT);
+
+  if (!strcasecmp (fieldName, "dX_SYS"  )) ESCAPE (IMAGE_X_ERR_SYS,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dY_SYS"  )) ESCAPE (IMAGE_Y_ERR_SYS,  MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "dM_SYS"  )) ESCAPE (IMAGE_MAG_ERR_SYS,MAG_NONE, OPIHI_FLT);
+  if (!strcasecmp (fieldName, "NFIT_PHOTOM")) ESCAPE (IMAGE_NFIT_PHOTOM,MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "NFIT_ASTROM")) ESCAPE (IMAGE_NFIT_ASTROM,MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "NLINK_PHOTOM")) ESCAPE (IMAGE_NLINK_PHOTOM,MAG_NONE, OPIHI_INT);
+  if (!strcasecmp (fieldName, "NLINK_ASTROM")) ESCAPE (IMAGE_NLINK_ASTROM,MAG_NONE, OPIHI_INT);
+
+  // for words that don't parse, try a photcode
+  gprint (GP_ERR, "unknown field '%s' for image table in DVO database\n", fieldName);
+  return (FALSE);
+}
Index: trunk/Ohana/src/libdvo/src/dbRPN.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbRPN.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbRPN.c	(revision 31635)
@@ -0,0 +1,206 @@
+# include "dvo.h"
+# define DUMPSTACK 0
+
+dbStack *dbRPN (int argc, char **argv, int *nstack) {
+  
+  int type, Nx, Ny;
+  int i, j, Nstack, Nop_stack, NSTACK;
+  dbStack *stack, *op_stack;
+
+  /* max total stack size is argc, though should be less, this is safe */
+  NSTACK = argc + 5;
+  ALLOCATE (stack, dbStack, NSTACK);
+  ALLOCATE (op_stack, dbStack, NSTACK);
+  for (i = 0; i < NSTACK; i++) {
+    dbInitStack (&stack[i]);
+    dbInitStack (&op_stack[i]);
+  }
+  
+  Nx = Ny = Nstack = Nop_stack = 0;
+  for (i = 0; i < argc; i++) {
+    
+    /* decide on priority of object */
+    type = DB_STACK_NONE;
+    /* unary operations */
+    if (!strcmp (argv[i], "abs"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "int"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "exp"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "ten"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "log"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "ln"))     { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "sqrt"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "erf"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "sinh"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "cosh"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "asinh"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "acosh"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "sin"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "cos"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "tan"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "dsin"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "dcos"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "dtan"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "asin"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "acos"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "atan"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "dasin"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "dacos"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "datan"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "lgamma")) { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "rnd"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "xramp"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "yramp"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "ramp"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "zero"))   { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "--"))     { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "not"))    { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "isinf"))  { type = DB_STACK_UNARY; goto gotit; }
+    if (!strcmp (argv[i], "isnan"))  { type = DB_STACK_UNARY; goto gotit; }
+
+    /* binary operations */
+    if (!strcmp (argv[i], "^"))      { type = DB_STACK_POWER; goto gotit; }
+
+    if (!strcmp (argv[i], "@"))      { type = DB_STACK_MULTIPLY; goto gotit; }
+    if (!strcmp (argv[i], "/"))      { type = DB_STACK_MULTIPLY; goto gotit; }
+    if (!strcmp (argv[i], "*"))      { type = DB_STACK_MULTIPLY; goto gotit; }
+    if (!strcmp (argv[i], "%"))      { type = DB_STACK_MULTIPLY; goto gotit; }
+
+    if (!strcmp (argv[i], "+"))      { type = DB_STACK_SUM; goto gotit; }
+    if (!strcmp (argv[i], "-"))      { type = DB_STACK_SUM; goto gotit; }
+	
+    if (!strcmp (argv[i], "&"))      { type = DB_STACK_BITWISE; goto gotit; }
+    if (!strcmp (argv[i], "|"))      { type = DB_STACK_BITWISE; goto gotit; }
+
+    if (!strcmp (argv[i], "<"))      { type = DB_STACK_COMPARE; goto gotit; }
+    if (!strcmp (argv[i], ">"))      { type = DB_STACK_COMPARE; goto gotit; }
+    if (!strcmp (argv[i], "=="))     { type = DB_STACK_COMPARE; strcpy (argv[i], "E"); goto gotit; }
+    if (!strcmp (argv[i], "!="))     { type = DB_STACK_COMPARE; strcpy (argv[i], "N"); goto gotit; }
+    if (!strcmp (argv[i], "<="))     { type = DB_STACK_COMPARE; strcpy (argv[i], "L"); goto gotit; }
+    if (!strcmp (argv[i], ">="))     { type = DB_STACK_COMPARE; strcpy (argv[i], "G"); goto gotit; }
+    if (!strcmp (argv[i], ">>"))     { type = DB_STACK_COMPARE; strcpy (argv[i], "U"); goto gotit; }
+    if (!strcmp (argv[i], "<<"))     { type = DB_STACK_COMPARE; strcpy (argv[i], "D"); goto gotit; }
+
+    if (!strcmp (argv[i], "&&"))     { type = DB_STACK_LOGIC; strcpy (argv[i], "A"); goto gotit; }
+    if (!strcmp (argv[i], "||"))     { type = DB_STACK_LOGIC; strcpy (argv[i], "O"); goto gotit; }
+
+    if (!strcmp (argv[i], "("))      { type = DB_STACK_OPEN_PAR; goto gotit; }
+    if (!strcmp (argv[i], ")"))      { type = DB_STACK_CLOSE_PAR; goto gotit; }
+
+  gotit:
+    /* choose how to deal with object */
+    switch (type) {
+      case DB_STACK_POWER:  /* exponentiation: 2^2^3 = 64 != 256 (precedence is right-to-left, not left-to-right!) */
+	/* pop previous, higher operators from OP stack to stack */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type > type); j--) {
+	  stack[Nstack] = op_stack[j];
+	  op_stack[j].name = NULL;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	/* push operator on OP stack */
+	op_stack[Nop_stack].name = strcreate (argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case DB_STACK_UNARY: /* unary OPs */
+      case DB_STACK_MULTIPLY: /* binary OPs */
+      case DB_STACK_SUM:
+      case DB_STACK_BITWISE: 
+      case DB_STACK_COMPARE: 
+      case DB_STACK_LOGIC: 
+	/* pop previous, higher or equal operators from OP stack to stack */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type >= type); j--) {
+	  stack[Nstack] = op_stack[j];
+	  op_stack[j].name = NULL;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	/* push operator on OP stack */
+	op_stack[Nop_stack].name = strcreate (argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case DB_STACK_OPEN_PAR:  
+	/* push operator on OP stack */
+	op_stack[Nop_stack].name = strcreate (argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case DB_STACK_CLOSE_PAR: 
+	/* pop rest of operators from OP stack to stack, looking for '(' */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type != DB_STACK_OPEN_PAR); j--) {
+	  stack[Nstack] = op_stack[j];
+	  op_stack[j].name = NULL;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	if ((j == -1) || (op_stack[j].type != DB_STACK_OPEN_PAR)) {
+	  push_error ("syntax error: mismatched parenthesis");
+	  Nstack = 0;
+	  goto cleanup;
+	}
+	Nop_stack --;
+	break;
+      case 0:
+	/* place the value (number or vector/matrix name) on stack */
+	/* value of 'X' is used as sentinel until we sort out values */
+	stack[Nstack].name = strcreate (argv[i]);
+	stack[Nstack].type = DB_STACK_VALUE;
+	Nstack ++;
+	break;
+    }
+  }
+
+  /* dump remaining operators on stack, checking for '(' */
+  for (j = Nop_stack - 1; j >= 0; j--) {
+    if (op_stack[j].type == DB_STACK_OPEN_PAR) {
+      push_error ("syntax error: mismatched parenthesis");
+      Nstack = 0;
+      goto cleanup;
+    }
+    stack[Nstack] = op_stack[j];
+    op_stack[j].name = NULL;
+    Nstack ++;
+  }
+
+cleanup: 
+  /*** free up unused stack space ***/
+  dbFreeStack (op_stack, NSTACK);
+  free (op_stack);
+  dbFreeStack (&stack[Nstack], NSTACK - Nstack);
+  REALLOCATE (stack, dbStack, MAX (Nstack, 1));
+  *nstack = Nstack;
+
+  for (i = 0; i < argc; i++) {
+    free (argv[i]);
+  }
+  free (argv);
+
+# if (DUMPSTACK)
+  for (i = 0; i < Nstack; i++) {
+    gprint (GP_ERR, "%s ", stack[i].name);
+  }
+  if (Nstack > 0) gprint (GP_ERR, "\n");
+  for (i = 0; i < Nstack; i++) {
+    gprint (GP_ERR, "%d ", stack[i].type);
+  }
+  if (Nstack > 0) gprint (GP_ERR, "\n");
+# endif
+
+  return (stack);
+
+}
+
+/* here are the rules for parsing a math AOL expression to RPN:
+
+1) if object is a number, push on stack
+2) if object is a third order operand (exp, sin, cos), push on op stack
+3) if object is an open paren, push on op stack,
+4) if object is a second order operand, push on stack
+5) if object is a first order operand, pop all second order operands from stack 
+until paren, push on stack
+6) if object is an end paren, pop all objects from stack until paren, 
+pop next stack, if third order op
+7) if end of line, pop all remaining objects, second order first, etc.
+   
+*/
Index: trunk/Ohana/src/libdvo/src/dbStackMath.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbStackMath.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbStackMath.c	(revision 31635)
@@ -0,0 +1,151 @@
+# include "dvo.h"
+
+static int NallocBinary = 0;
+static int NallocUnary = 0;
+
+dbStack *dbBinary (dbStack *V1, dbStack *V2, char *op, dbValue *fields) {
+
+  dbStack *OUT;
+  
+# define SS_FUNC(OP) {							\
+    if (!(V1->type & DB_STACK_INT) && !(V2->type & DB_STACK_INT)) {	\
+      opihi_flt M1 = (V1->type & DB_STACK_FIELD) ? fields[V1->field].Flt : V1->FltValue; \
+      opihi_flt M2 = (V2->type & DB_STACK_FIELD) ? fields[V2->field].Flt : V2->FltValue; \
+      OUT[0].type = DB_STACK_VALUE | DB_STACK_TEMP;			\
+      OUT[0].FltValue = OP;						\
+      break;								\
+    }									\
+    if ((V1->type & DB_STACK_INT) && !(V2->type & DB_STACK_INT)) {	\
+      opihi_int M1 = (V1->type & DB_STACK_FIELD) ? fields[V1->field].Int : V1->IntValue; \
+      opihi_flt M2 = (V2->type & DB_STACK_FIELD) ? fields[V2->field].Flt : V2->FltValue; \
+      OUT[0].type = DB_STACK_VALUE | DB_STACK_TEMP;			\
+      OUT[0].FltValue = OP;						\
+      break;								\
+    }									\
+    if (!(V1->type & DB_STACK_INT) && (V2->type & DB_STACK_INT)) {	\
+      opihi_flt M1 = (V1->type & DB_STACK_FIELD) ? fields[V1->field].Flt : V1->FltValue; \
+      opihi_int M2 = (V2->type & DB_STACK_FIELD) ? fields[V2->field].Int : V2->IntValue; \
+      OUT[0].type = DB_STACK_VALUE | DB_STACK_TEMP;			\
+      OUT[0].FltValue = OP;						\
+      break;								\
+    }									\
+    if ((V1->type & DB_STACK_INT) && (V2->type & DB_STACK_INT)) {	\
+      opihi_int M1 = (V1->type & DB_STACK_FIELD) ? fields[V1->field].Int : V1->IntValue; \
+      opihi_int M2 = (V2->type & DB_STACK_FIELD) ? fields[V2->field].Int : V2->IntValue; \
+      OUT[0].type = DB_STACK_VALUE | DB_STACK_TEMP | DB_STACK_INT;	\
+      OUT[0].IntValue = OP;						\
+      break;								\
+    }									\
+  }
+
+  NallocBinary ++;
+  ALLOCATE (OUT, dbStack, 1);
+  OUT->name = NULL;
+
+  // XXX use an enum for the op...
+  switch (op[0]) { 
+    case '+': SS_FUNC(M1 + M2);
+    case '-': SS_FUNC(M1 - M2);
+    case '*': SS_FUNC(M1 * M2);
+    case '/': SS_FUNC(M1 / M2);
+    case '%': SS_FUNC((int) M1 % (int) M2);
+    case '^': SS_FUNC(pow (M1, M2));
+    case 'D': SS_FUNC(MIN (M1, M2));
+    case 'U': SS_FUNC(MAX (M1, M2));
+    case '<': SS_FUNC((M1 < M2) ? 1 : 0);
+    case '>': SS_FUNC((M1 > M2) ? 1 : 0);
+    case '&': SS_FUNC(((int)M1 & (int)M2));
+    case '|': SS_FUNC(((int)M1 | (int)M2));
+    case 'E': SS_FUNC((M1 == M2) ? 1 : 0);
+    case 'N': SS_FUNC((M1 != M2) ? 1 : 0);
+    case 'L': SS_FUNC((M1 <= M2) ? 1 : 0);
+    case 'G': SS_FUNC((M1 >= M2) ? 1 : 0);
+    case 'A': SS_FUNC((M1 && M2) ? 1 : 0);
+    case 'O': SS_FUNC((M1 || M2) ? 1 : 0);
+  default:
+    return (NULL);
+  }
+# undef SS_FUNC
+  
+  return (OUT);
+}
+
+dbStack *dbUnary (dbStack *V1, char *op, dbValue *fields) {
+
+  dbStack *OUT;
+  
+# define S_FUNC(OP,FTYPE) {						\
+    if (!(V1->type & DB_STACK_INT)) {					\
+      opihi_flt M1 = (V1->type & DB_STACK_FIELD) ? fields[V1->field].Flt : V1->FltValue; \
+      OUT[0].type = DB_STACK_VALUE | DB_STACK_TEMP;			\
+      OUT[0].FltValue = OP;						\
+      return (OUT);							\
+    }									\
+    if ((FTYPE != DB_STACK_INT) && (V1->type & DB_STACK_INT)) {		\
+      opihi_int M1 = (V1->type & DB_STACK_FIELD) ? fields[V1->field].Int : V1->IntValue; \
+      OUT[0].type = DB_STACK_VALUE | DB_STACK_TEMP;			\
+      OUT[0].FltValue = OP;						\
+      return (OUT);							\
+    }									\
+    if ((FTYPE == DB_STACK_INT) && (V1->type & DB_STACK_INT)) {		\
+      opihi_int M1 = (V1->type & DB_STACK_FIELD) ? fields[V1->field].Int : V1->IntValue; \
+      OUT[0].type = DB_STACK_VALUE | DB_STACK_TEMP | DB_STACK_INT;	\
+      OUT[0].IntValue = OP;						\
+      return (OUT);							\
+    }									\
+  }
+
+  NallocUnary ++;
+  ALLOCATE (OUT, dbStack, 1);
+  OUT->name = NULL;
+
+  if (!strcmp (op, "="))      S_FUNC(M1,0);
+  if (!strcmp (op, "abs"))    S_FUNC(fabs(M1),0);
+  if (!strcmp (op, "int"))    S_FUNC((int)(M1),DB_STACK_INT);
+  if (!strcmp (op, "exp"))    S_FUNC(exp (M1),0);
+  if (!strcmp (op, "ten"))    S_FUNC(pow (10.0,M1),0);
+  if (!strcmp (op, "log"))    S_FUNC(log10 (M1),0);
+  if (!strcmp (op, "ln"))     S_FUNC(log (M1),0);
+  if (!strcmp (op, "sqrt"))   S_FUNC(sqrt (M1),0);
+  if (!strcmp (op, "erf"))    S_FUNC(erf (M1),0);
+
+  if (!strcmp (op, "sinh"))   S_FUNC(sinh (M1),0);
+  if (!strcmp (op, "cosh"))   S_FUNC(cosh (M1),0);
+  if (!strcmp (op, "asinh"))  S_FUNC(asinh (M1),0);
+  if (!strcmp (op, "acosh"))  S_FUNC(acosh (M1),0);
+  if (!strcmp (op, "lgamma")) S_FUNC(lgamma (M1),0);
+
+  if (!strcmp (op, "sin"))    S_FUNC(sin (M1),0);
+  if (!strcmp (op, "cos"))    S_FUNC(cos (M1),0);
+  if (!strcmp (op, "tan"))    S_FUNC(tan (M1),0);
+  if (!strcmp (op, "dsin"))   S_FUNC(sin (M1*RAD_DEG),0);
+  if (!strcmp (op, "dcos"))   S_FUNC(cos (M1*RAD_DEG),0);
+  if (!strcmp (op, "dtan"))   S_FUNC(tan (M1*RAD_DEG),0);
+  if (!strcmp (op, "asin"))   S_FUNC(asin (M1),0);
+  if (!strcmp (op, "acos"))   S_FUNC(acos (M1),0);
+  if (!strcmp (op, "atan"))   S_FUNC(atan (M1),0);
+  if (!strcmp (op, "dasin"))  S_FUNC(asin (M1)*DEG_RAD,0);
+  if (!strcmp (op, "dacos"))  S_FUNC(acos (M1)*DEG_RAD,0);
+  if (!strcmp (op, "datan"))  S_FUNC(atan (M1)*DEG_RAD,0);
+  if (!strcmp (op, "rnd"))    S_FUNC(M1*0.0 + drand48(),0);
+  if (!strcmp (op, "not"))    S_FUNC(!(M1),DB_STACK_INT);
+  if (!strcmp (op, "--"))     S_FUNC(- (M1),DB_STACK_INT);
+  if (!strcmp (op, "isinf"))  S_FUNC(!finite(M1),DB_STACK_INT);
+  if (!strcmp (op, "isnan"))  S_FUNC(isnan(M1),DB_STACK_INT);
+
+  return (OUT);
+}
+
+int dbStackAllocPrint () {
+
+  fprintf (stderr, "dbAllocBinary: %d\n", NallocBinary);
+  fprintf (stderr, "dbAllocUnary:  %d\n", NallocUnary);
+  return (TRUE);
+}
+
+int dbStackAllocReset () {
+
+  NallocBinary = 0;
+  NallocUnary = 0;
+  return (TRUE);
+}
Index: trunk/Ohana/src/libdvo/src/dbStackOps.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dbStackOps.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dbStackOps.c	(revision 31635)
@@ -0,0 +1,54 @@
+# include "dvo.h"
+
+void dbInitStack (dbStack *stack) {
+  stack[0].type   = DB_STACK_NONE;
+  stack[0].name   = NULL;
+  stack[0].field  = 0;
+  stack[0].FltValue = 0.0;
+  stack[0].IntValue = 0;
+}
+
+// free data for stack entries (free stack explicitly)
+void dbFreeStack (dbStack *stack, int Nstack) {
+
+  int i;
+
+  if (stack == NULL) return;
+
+  for (i = 0; i < Nstack; i++) {
+    if (stack[i].name != NULL) {
+      free (stack[i].name);
+      stack[i].name = NULL;
+    }
+  }
+}
+
+static int NfreeStack = 0;
+
+/* delete name and data */
+void dbFreeEntry (dbStack *stack) {
+
+  if (stack[0].name != NULL)  free (stack[0].name);
+  free (stack);
+  NfreeStack ++;
+}
+
+/* delete name and data */
+void dbFreeTempEntry (dbStack *stack) {
+
+  if (!(stack->type & DB_STACK_TEMP)) return;
+
+  if (stack[0].name != NULL)  free (stack[0].name);
+  free (stack);
+  NfreeStack ++;
+}
+
+void dbStackFreePrint () {
+
+  fprintf (stderr, "dbFreeStack: %d\n", NfreeStack);
+}
+
+void dbStackFreeReset () {
+
+  NfreeStack = 0;
+}
Index: trunk/Ohana/src/libdvo/src/db_utils.c
===================================================================
--- trunk/Ohana/src/libdvo/src/db_utils.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/db_utils.c	(revision 31635)
@@ -0,0 +1,28 @@
+# include "dvo.h"
+
+// This file contains some functions used by the libdvo db lookup functions
+// that are really specific to dvo.
+//
+// These are declared weak so they can be overridden by the program.
+
+// overridden for opihi in opihi/lib.data/open_kapa.c
+// by default, no graphdata 
+int GetGraphdata(Graphdata *graph, int *kapa, char *name) {
+    return FALSE;
+}
+
+// overridden for opihi programs in opihi/lib.shell/timeformat.c
+int
+GetTimeFormat(time_t *TimeReference, int *TimeFormat) {
+    *TimeReference = 0;
+    *TimeFormat = TIME_SECONDS;
+    return (TRUE);
+}
+
+// overridden for dvo in opihi/dvo/photometry.c
+int GetTimeSelection (time_t *tz, time_t *te) {
+
+  *tz = 0;
+  *te = 0;
+  return (TRUE);
+}
Index: trunk/Ohana/src/libdvo/src/dvo_set_catdir.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_set_catdir.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dvo_set_catdir.c	(revision 31635)
@@ -0,0 +1,19 @@
+# include "ohana.h"
+
+// functions to set and get the current catdir.
+static char *current_catdir = NULL;
+
+char * dvo_get_catdir() {
+
+  return current_catdir;
+}
+
+void dvo_set_catdir (char *catdir) {
+    if (current_catdir) {
+        free(current_catdir);
+        current_catdir = NULL;
+    }
+    if (catdir) {
+        current_catdir = strdup(catdir);
+    }
+}
Index: trunk/Ohana/src/libdvo/src/dvo_set_skyregion.c
===================================================================
--- trunk/Ohana/src/libdvo/src/dvo_set_skyregion.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/dvo_set_skyregion.c	(revision 31635)
@@ -0,0 +1,25 @@
+# include "ohana.h"
+
+// functions to set and get the current skyregion.
+static double RAs = 0.0;
+static double RAe = 0.0;
+static double DECs = 0.0;
+static double DECe = 0.0;
+
+int get_skyregion (double *Rs, double *Re, double *Ds, double *De) {
+  *Rs = RAs;
+  *Re = RAe;
+  *Ds = DECs;
+  *De = DECe;
+
+  return TRUE;
+}
+
+int set_skyregion (double Rs, double Re, double Ds, double De) {
+  RAs  = Rs;
+  RAe  = Re;
+  DECs = Ds;
+  DECe = De;
+
+  return TRUE;
+}
Index: trunk/Ohana/src/libdvo/src/match_image.c
===================================================================
--- trunk/Ohana/src/libdvo/src/match_image.c	(revision 31635)
+++ trunk/Ohana/src/libdvo/src/match_image.c	(revision 31635)
@@ -0,0 +1,73 @@
+# include "dvo.h"
+
+off_t match_image (Image *image, off_t Nimage, unsigned int T, short int S) {
+
+  off_t N, Nlo, Nhi, N1, N2;
+
+  /* bracket first value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero < T) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  N1 = Nlo;
+
+  /* bracket last value of interest */
+  Nlo = 0; Nhi = Nimage;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[N].tzero > T) {
+      Nhi = N;
+    } else {
+      Nlo = N - 1;
+    }
+  }
+  N2 = Nhi;
+
+  for (N = N1; N < N2; N++) {
+    if ((image[N].tzero == T) && (image[N].photcode == S)) {
+      return (N);
+    }
+  }
+  return (-1);
+}
+
+off_t match_image_subset (Image *image, off_t *subset, off_t Nsubset, unsigned int T, short int S) {
+
+  off_t N, Nlo, Nhi, N1, N2;
+
+  /* bracket first value of interest */
+  Nlo = 0; Nhi = Nsubset;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[subset[N]].tzero < T) {
+      Nlo = N;
+    } else {
+      Nhi = N + 1;
+    }
+  }
+  N1 = Nlo;
+
+  /* bracket last value of interest */
+  Nlo = 0; Nhi = Nsubset;
+  while (Nhi - Nlo > 10) {
+    N = 0.5*(Nlo + Nhi);
+    if (image[subset[N]].tzero > T) {
+      Nhi = N;
+    } else {
+      Nlo = N - 1;
+    }
+  }
+  N2 = Nhi;
+
+  for (N = N1; N < N2; N++) {
+    if ((image[subset[N]].tzero == T) && (image[subset[N]].photcode == S)) {
+      return (subset[N]);
+    }
+  }
+  return (-1);
+}
