Index: /trunk/Ohana/src/opihi/cmd.basic/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/cmd.basic/Makefile	(revision 37048)
+++ /trunk/Ohana/src/opihi/cmd.basic/Makefile	(revision 37049)
@@ -55,4 +55,5 @@
 $(SRC)/substr.$(ARCH).o     \
 $(SRC)/strhash.$(ARCH).o     \
+$(SRC)/strmatch.$(ARCH).o     \
 $(SRC)/strpop.$(ARCH).o     \
 $(SRC)/strsub.$(ARCH).o     \
Index: /trunk/Ohana/src/opihi/cmd.basic/init.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.basic/init.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/cmd.basic/init.c	(revision 37049)
@@ -40,4 +40,5 @@
 int fprintf_opihi   PROTO((int, char **));
 int strlen_func     PROTO((int, char **));
+int strmatch        PROTO((int, char **));
 int substr_func     PROTO((int, char **));
 int strpop          PROTO((int, char **));
@@ -97,4 +98,5 @@
   {1, "strpop",        strpop,             "pop a string"},
   {1, "strsub",        strsub,             "replace instances of a key in a string"},
+  {1, "strmatch",      strmatch,           "string length"},
   {1, "wait",          wait_func,          "wait until return is typed"},
   {1, "which",         which,              "show command *"}
Index: /trunk/Ohana/src/opihi/cmd.basic/list.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.basic/list.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/cmd.basic/list.c	(revision 37049)
@@ -2,6 +2,4 @@
 # define D_NLINES 100
 static char prompt[] = ">> ";
-
-static int set_list_varname (char *line, char *base, int N, int excelStyle);
 
 int list (int argc, char **argv) {
@@ -311,32 +309,2 @@
   return (TRUE);
 }
-
-static int set_list_varname (char *line, char *base, int N, int excelStyle) {
-
-  int i;
-    
-  // A-Z correspond to 0 - 25
-
-  if (excelStyle) {
-    float f = log(26.0);
-    float g = (N == 0) ? 0.0 : log(1.0*N);
-    int Ndigit = (int) (g / f) + 1;
-    if (Ndigit > 10) {
-      sprintf (line, "%s:ZZZZZZZZZZ", base);
-      return FALSE;
-    }
-    char name[12];
-    memset (name, 0, 12);
-    for (i = 0; i < Ndigit; i++) {
-      float Npow = Ndigit - i - 1;
-      float g = pow(26.0, Npow);
-      int V = (int) (N / g);
-      name[i] = (Npow == 0.0) ? 'A' + V : 'A' + V - 1;
-      N -= V * g;
-    }
-    sprintf (line, "%s:%s", base, name);
-  } else {
-    sprintf (line, "%s:%d", base, N);
-  }
-  return TRUE;
-}
Index: /trunk/Ohana/src/opihi/cmd.basic/strmatch.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.basic/strmatch.c	(revision 37049)
+++ /trunk/Ohana/src/opihi/cmd.basic/strmatch.c	(revision 37049)
@@ -0,0 +1,176 @@
+# include "basic.h"
+
+int strmatch (int argc, char **argv) {
+
+  /* returns position of the first given character class */ 
+  int i, N;
+
+  char *startName = NULL;
+  char *lengthName = NULL;
+  if ((N = get_argument (argc, argv, "-output"))) {
+    remove_argument (N, &argc, argv);
+    startName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+    lengthName = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: strchr (string) (class) [-output start length]\n");
+    return (FALSE);
+  }
+
+  // 'class' may be alpha, float, int, 
+
+  if (!strcasecmp(argv[2], "alpha")) {
+    int myLength = strlen(argv[1]);
+    int found = FALSE;
+    int start = -1;
+    int length = -1;
+    for (i = 0; i < myLength; i++) {
+      int isUpper = (argv[1][i] >= 'A') && (argv[1][i] <= 'Z');
+      int isLower = (argv[1][i] >= 'a') && (argv[1][i] <= 'z');
+      if (!found && (isLower || isUpper)) {
+	start = i;
+	found = TRUE;
+	continue;
+      }
+      if (found && !(isLower || isUpper)) {
+	length = i - start;
+	break;
+      }
+    }
+    if (found && (length < 0)) {
+      length = myLength - start;
+    }
+    if (startName && lengthName) {
+      set_int_variable (startName, start);
+      set_int_variable (lengthName, length);
+    } else {
+      gprint (GP_LOG, "match: %d %d\n", start, length);
+    }
+    return TRUE;
+  }
+
+  if (!strcasecmp(argv[2], "upper")) {
+    int myLength = strlen(argv[1]);
+    int found = FALSE;
+    int start = -1;
+    int length = -1;
+    for (i = 0; i < myLength; i++) {
+      int isUpper = (argv[1][i] >= 'A') && (argv[1][i] <= 'Z');
+      // int isLower = (argv[1][i] >= 'a') && (argv[1][i] <= 'z');
+      if (!found && isUpper) {
+	start = i;
+	found = TRUE;
+	continue;
+      }
+      if (found && !isUpper) {
+	length = i - start;
+	break;
+      }
+    }
+    if (found && (length < 0)) {
+      length = myLength - start;
+    }
+    if (startName && lengthName) {
+      set_int_variable (startName, start);
+      set_int_variable (lengthName, length);
+    } else {
+      gprint (GP_LOG, "match: %d %d\n", start, length);
+    }
+    return TRUE;
+  }
+
+  if (!strcasecmp(argv[2], "lower")) {
+    int myLength = strlen(argv[1]);
+    int found = FALSE;
+    int start = -1;
+    int length = -1;
+    for (i = 0; i < myLength; i++) {
+      // int isUpper = (argv[1][i] >= 'A') && (argv[1][i] <= 'Z');
+      int isLower = (argv[1][i] >= 'a') && (argv[1][i] <= 'z');
+      if (!found && isLower) {
+	start = i;
+	found = TRUE;
+	continue;
+      }
+      if (found && !isLower) {
+	length = i - start;
+	break;
+      }
+    }
+    if (found && (length < 0)) {
+      length = myLength - start;
+    }
+    if (startName && lengthName) {
+      set_int_variable (startName, start);
+      set_int_variable (lengthName, length);
+    } else {
+      gprint (GP_LOG, "match: %d %d\n", start, length);
+    }
+    return TRUE;
+  }
+
+  if (!strcasecmp(argv[2], "float")) {
+    int myLength = strlen(argv[1]);
+    int found = FALSE;
+    int start = -1;
+    int length = -1;
+    for (i = 0; i < myLength; i++) {
+      int isDigit = (argv[1][i] >= '0') && (argv[1][i] <= '9');
+      int isFloat = isDigit || (argv[1][i] == '-') || (argv[1][i] == '.');
+      if (!found && isFloat) {
+	start = i;
+	found = TRUE;
+	continue;
+      }
+      if (found && !isFloat) {
+	length = i - start;
+	break;
+      }
+    }
+    if (found && (length < 0)) {
+      length = myLength - start;
+    }
+    if (startName && lengthName) {
+      set_int_variable (startName, start);
+      set_int_variable (lengthName, length);
+    } else {
+      gprint (GP_LOG, "match: %d %d\n", start, length);
+    }
+    return TRUE;
+  }
+
+  if (!strcasecmp(argv[2], "int")) {
+    int myLength = strlen(argv[1]);
+    int found = FALSE;
+    int start = -1;
+    int length = -1;
+    for (i = 0; i < myLength; i++) {
+      int isDigit = (argv[1][i] >= '0') && (argv[1][i] <= '9');
+      if (!found && isDigit) {
+	start = i;
+	found = TRUE;
+	continue;
+      }
+      if (found && !isDigit) {
+	length = i - start;
+	break;
+      }
+    }
+    if (found && (length < 0)) {
+      length = myLength - start;
+    }
+    if (startName && lengthName) {
+      set_int_variable (startName, start);
+      set_int_variable (lengthName, length);
+    } else {
+      gprint (GP_LOG, "match: %d %d\n", start, length);
+    }
+    return TRUE;
+  }
+
+  gprint (GP_ERR, "unknown character class %s\n", argv[2]);
+  return (TRUE);
+}
Index: /trunk/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 37048)
+++ /trunk/Ohana/src/opihi/cmd.data/Makefile	(revision 37049)
@@ -98,4 +98,5 @@
 $(SRC)/point.$(ARCH).o		\
 $(SRC)/ps.$(ARCH).o		\
+$(SRC)/print_vectors.$(ARCH).o 	\
 $(SRC)/queuedelete.$(ARCH).o	\
 $(SRC)/queuedrop.$(ARCH).o	\
Index: /trunk/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/init.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/cmd.data/init.c	(revision 37049)
@@ -87,4 +87,5 @@
 int point            PROTO((int, char **));
 int ps               PROTO((int, char **));
+int print_vectors    PROTO((int, char **));
 int queuelist        PROTO((int, char **));
 int queueload        PROTO((int, char **));
@@ -250,4 +251,5 @@
   {1, "ppm",          jpeg,             "convert display graphic to PPM"},
   {1, "ps",           ps,               "convert display to PostScript"},
+  {1, "print_vectors", print_vectors,   "print a set of vectors"},
   {1, "queuedelete",  queuedelete,      "delete a queue"},
   {1, "queuedrop",    queuedrop,        "drop values from queue matching a key"},
Index: /trunk/Ohana/src/opihi/cmd.data/print_vectors.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/print_vectors.c	(revision 37049)
+++ /trunk/Ohana/src/opihi/cmd.data/print_vectors.c	(revision 37049)
@@ -0,0 +1,47 @@
+# include "data.h"
+
+int print_vectors (int argc, char **argv) {
+
+  Vector **vec;
+  int i, j;
+
+  if (argc < 2) {
+    gprint (GP_ERR, "USAGE: print_vectors (vector)[,vector,...]\n");
+    return (FALSE);
+  }
+
+  int Nvec = argc - 1;
+  ALLOCATE (vec, Vector *, Nvec);
+  for (i = 1; i < argc; i++) {
+    vec[i-1] = SelectVector (argv[i], OLDVECTOR, FALSE);
+    if (!vec[i-1]) {
+      gprint (GP_ERR, "unknown vector %s\n", argv[i]);
+      free (vec);
+      return FALSE;
+    }
+  }
+
+  int MaxLen = 0;
+  for (i = 0; i < Nvec; i++) {
+    MaxLen = MAX (MaxLen, vec[i][0].Nelements);
+  }
+
+  for (j = 0; j < MaxLen; j++) {
+    for (i = 0; i < Nvec; i++) {
+      if (j >= vec[i][0].Nelements) {
+	gprint (GP_LOG, "NaN ");
+      } else {
+	if (vec[i][0].type == OPIHI_FLT) {
+	  gprint (GP_LOG, "%f ", vec[i][0].elements.Flt[j]);
+	} else {
+	  gprint (GP_LOG, "%d ", vec[i][0].elements.Int[j]);
+	}
+      }
+    }
+    gprint (GP_LOG, "\n");
+  }
+  free (vec);
+
+  return (TRUE);
+}
+
Index: /trunk/Ohana/src/opihi/cmd.data/read_vectors.c
===================================================================
--- /trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/cmd.data/read_vectors.c	(revision 37049)
@@ -3,4 +3,6 @@
 FILE *f = (FILE *) NULL;
 char filename[2048];
+
+void read_vectors_cleanup ();
 
 int datafile (int argc, char **argv) {
@@ -23,5 +25,11 @@
 // vector types
 enum {COLTYPE_NONE, COLTYPE_FLT, COLTYPE_INT, COLTYPE_TIME, COLTYPE_CHAR};
-static int FITS_TRANSPOSE;
+
+static int      Nvec     = 0;
+static Vector **vec      = NULL;
+static char   **listname = NULL;
+static int     *col      = NULL;
+static int     *coltype  = NULL;
+static char    *buffer   = NULL;
 
 int read_vectors (int argc, char **argv) {
@@ -29,16 +37,8 @@
   int TimeFormat;
   time_t TimeReference;
-  int i, j, Nskip, Narg, Nvec, *col, IsCSV, VERBOSE;
-  int Nbytes, Nstart, NELEM, Nelem, nread, *coltype;
+  int i, j, Nskip, Narg, IsCSV, VERBOSE;
+  int Nbytes, Nstart, NELEM, Nelem, nread;
   char *colstr, *c0, *c1, *extname;
-  Vector **vec;
-
-  char *buffer = NULL;
-
-  FITS_TRANSPOSE = FALSE;
-  if ((Narg = get_argument (argc, argv, "-transpose"))) {
-    remove_argument (Narg, &argc, argv);
-    FITS_TRANSPOSE = TRUE;
-  }
+  char varname[1024];  // used as a buffer for the names of string fields
 
   /* auto-sense table type */
@@ -88,7 +88,12 @@
 
   Nvec = (argc - 1) / 2;
+  ALLOCATE (listname, char *, Nvec);
   ALLOCATE (vec, Vector *, Nvec);
   ALLOCATE (col, int, Nvec);
   ALLOCATE (coltype, int, Nvec);
+  for (i = 0; i < Nvec; i++) {
+    listname[i] = NULL;
+    vec[i] = NULL;
+  }
 
   for (i = 0; i < Nvec; i++) {
@@ -115,9 +120,12 @@
     }
 
-    if ((vec[i] = SelectVector (argv[2*i + 1], ANYVECTOR, TRUE)) == NULL) {
-      gprint (GP_ERR, "USAGE: read name N name N ...\n");
-      free (vec);
-      free (col);
-      return (FALSE);    
+    if (coltype[i] == COLTYPE_CHAR) {
+      listname[i] = strcreate (argv[2*i + 1]);
+    } else {
+      if ((vec[i] = SelectVector (argv[2*i + 1], ANYVECTOR, TRUE)) == NULL) {
+	gprint (GP_ERR, "USAGE: read name N name N ...\n");
+	read_vectors_cleanup();
+	return (FALSE);    
+      }
     }
 
@@ -144,6 +152,5 @@
     bad_colname:
       gprint (GP_ERR, "USAGE: read name N name N ...\n");
-      free (vec);
-      free (col);
+      read_vectors_cleanup();
       return (FALSE);    
     }
@@ -153,9 +160,16 @@
   NELEM = 1000;
   for (i = 0; i < Nvec; i++) {
-    if ((coltype[i] == COLTYPE_INT) || (coltype[i] == COLTYPE_CHAR)) {
-      ResetVector (vec[i], OPIHI_INT, NELEM);
-    } else {
-      // note that COLTYPE_TIME is a type of float
-      ResetVector (vec[i], OPIHI_FLT, NELEM);
+    switch (coltype[i]) {
+      case COLTYPE_INT:
+	ResetVector (vec[i], OPIHI_INT, NELEM);
+	break;
+      case COLTYPE_FLT:
+      case COLTYPE_TIME:
+	// note that COLTYPE_TIME is a type of float
+	ResetVector (vec[i], OPIHI_FLT, NELEM);
+	break;
+      case COLTYPE_CHAR:
+      default:
+	break;
     }
   }
@@ -166,6 +180,5 @@
     if (scan_line_maxlen (f, buffer, 0x10000) == EOF) {
       gprint (GP_ERR, "problem reading file %s\n", filename);
-      free (vec);
-      free (col);
+      read_vectors_cleanup();
       return FALSE;
     }
@@ -213,5 +226,4 @@
       for (i = 0; i < Nvec; i++) {
 	int ivalue;
-	char cvalue;
 	double dvalue;
 	time_t tvalue;
@@ -224,7 +236,21 @@
 	    break;
 	  case COLTYPE_CHAR:
-	    readStatus = IsCSV ? charparse_csv (&cvalue, col[i], c0) : charparse (&cvalue, col[i], c0);
-	    vec[i][0].elements.Int[Nelem] = readStatus ? cvalue : 0;
-	    break;
+	    {
+	      // I need to get an isolated word in 'value' with the string value of this field 
+	      char *ptr = IsCSV ? ptrparse_csv (col[i], c0) : ptrparse (col[i], c0);
+	      char *value = NULL;
+	      if (IsCSV) {
+		char *end = parse_nextword_csv (ptr);
+		if (end) {
+		  value = end ? strncreate (ptr, end - ptr) : strcreate (ptr);
+		}
+	      } else {
+		value = thisword(ptr);
+	      }
+	      set_list_varname (varname, listname[i], Nelem, FALSE);
+	      set_str_variable (varname, value);
+	      free (value);
+	      break;
+	    }
 	  case COLTYPE_FLT:
 	    readStatus = IsCSV ? dparse_csv (&dvalue, col[i], c0) : dparse (&dvalue, col[i], c0);
@@ -256,8 +282,15 @@
 	NELEM += 1000;
 	for (i = 0; i < Nvec; i++) {
-	  if (coltype[i] == COLTYPE_INT) {
-	    REALLOCATE (vec[i][0].elements.Int, opihi_int, NELEM);
-	  } else {
-	    REALLOCATE (vec[i][0].elements.Flt, opihi_flt, NELEM);
+	  switch (coltype[i]) {
+	    case COLTYPE_INT:
+	      ResetVector (vec[i], OPIHI_INT, NELEM);
+	      break;
+	    case COLTYPE_FLT:
+	    case COLTYPE_TIME:
+	      ResetVector (vec[i], OPIHI_FLT, NELEM);
+	      break;
+	    case COLTYPE_CHAR:
+	    default:
+	      break;
 	  }
 	}
@@ -266,22 +299,28 @@
     }
   }
+  // set the final vector / list length
   for (i = 0; i < Nvec; i++) {
-    if (coltype[i] == COLTYPE_INT) {
-      REALLOCATE (vec[i][0].elements.Int, opihi_int, MAX (Nelem,1));
-    } else {
-      REALLOCATE (vec[i][0].elements.Flt, opihi_flt, MAX (Nelem,1));
-    }
-    vec[i][0].Nelements = Nelem;
-  }
-  
-  free (vec);
-  free (col);
-  if (buffer) free (buffer);
+    switch (coltype[i]) {
+      case COLTYPE_INT:
+	ResetVector (vec[i], OPIHI_INT, Nelem);
+	break;
+      case COLTYPE_FLT:
+      case COLTYPE_TIME:
+	ResetVector (vec[i], OPIHI_FLT, Nelem);
+	break;
+      case COLTYPE_CHAR:
+	sprintf (varname, "%s:n", listname[i]);
+	set_int_variable (varname, Nelem);
+	break;
+      default:
+	break;
+    }
+  }
+  read_vectors_cleanup();
   return (TRUE);
-
 }
 
-# define ESCAPE(MSG) { \
-  gprint (GP_ERR, "%s\n", MSG); \
+# define ESCAPE(...) {		\
+  gprint (GP_ERR, __VA_ARGS__); \
   if (CCDKeyword != NULL) free (CCDKeyword); \
   gfits_free_table  (&table); \
@@ -292,12 +331,19 @@
 
   off_t Nbytes;
-  int i, j, k, N, Nextend, Ny, Binary, vecType, padIfShort;
+  int i, j, N, Nextend, Ny, Binary, vecType, padIfShort;
   char type[16], ID[80], *CCDKeyword;
   FTable table;
   Header header;
   Vector **vec;
+  int FITS_TRANSPOSE;
 
   table.buffer = NULL;
   header.buffer = NULL;
+
+  FITS_TRANSPOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-transpose"))) {
+    remove_argument (N, &argc, argv);
+    FITS_TRANSPOSE = TRUE;
+  }
 
   CCDKeyword = NULL;
@@ -328,7 +374,7 @@
   // }
 
-  if (argc < 2) ESCAPE ("USAGE: read -fits extension [-extnum] [-keyword key] name name ...");
-
-  if (f == NULL) ESCAPE ("file not found");
+  if (argc < 2) ESCAPE ("USAGE: read -fits extension [-extnum] [-keyword key] name name ...\n");
+
+  if (f == NULL) ESCAPE ("file not found\n");
   fseeko (f, 0LL, SEEK_SET);
   table.header = &header;
@@ -338,5 +384,5 @@
     // first extension is PHU, cannot be a table. 
     // Nextend counts from 0 for first extension
-    if (!gfits_load_header (f, &header)) ESCAPE ("error reading primary header for file");
+    if (!gfits_load_header (f, &header)) ESCAPE ("error reading primary header for file\n");
     Nbytes = gfits_data_size (&header);
     fseeko (f, Nbytes, SEEK_CUR);
@@ -344,5 +390,5 @@
 
     for (i = 0; i < Nextend; i++) {
-      if (!gfits_load_header (f, &header)) ESCAPE ("extension not found");
+      if (!gfits_load_header (f, &header)) ESCAPE ("extension %d not found\n", i);
       Nbytes = gfits_data_size (&header);
       /* skip the prior data buffers */
@@ -350,6 +396,6 @@
       gfits_free_header (&header);
     }
-    if (!gfits_load_header (f, &header)) ESCAPE ("error reading header for extension");
-    if (!gfits_fread_ftable_data (f, &table, padIfShort)) ESCAPE ("error reading table for extension");
+    if (!gfits_load_header (f, &header)) ESCAPE ("error reading header for extension %d\n", Nextend);
+    if (!gfits_fread_ftable_data (f, &table, padIfShort)) ESCAPE ("error reading table for extension %d\n", Nextend);
 
   } else {
@@ -382,5 +428,5 @@
 	continue;
       }
-      if (!gfits_fread_ftable_data (f, &table, padIfShort)) ESCAPE ("error reading table for extension");
+      if (!gfits_fread_ftable_data (f, &table, padIfShort)) ESCAPE ("error reading table for extension\n");
       break;
     }
@@ -391,5 +437,5 @@
   gfits_scan (&header, "XTENSION", "%s", 1, type);
   if (strcmp (type, "BINTABLE") && strcmp (type, "TABLE")) {
-    ESCAPE ("specified extension is not a table\n");
+    ESCAPE ("specified extension %s is not a table\n", type);
   }
   Binary = !strcmp (type, "BINTABLE");
@@ -418,4 +464,26 @@
 	
     if (!FITS_TRANSPOSE) {
+      // read string column into a list rather than a vector
+      if (!strcmp (type, "char")) {
+	char *fieldName = argv[i];
+	char *Ptr = data;
+	char varname[1024];  // used as a buffer for the names of string fields
+	for (j = 0; j < Ny; j++) {
+	  set_list_varname (varname, fieldName, j, FALSE);
+	  char *value = strncreate (&Ptr[j*Nval], Nval);
+	  // replace instances of $ with _
+	  char *p = strchr (value, '$');
+	  while (p) { 
+	    *p = '_';
+	    p = strchr (p, '$');
+	  }
+	  set_str_variable (varname, value);
+	  free (value);
+	}
+	sprintf (varname, "%s:n", fieldName);
+	set_int_variable (varname, Ny);
+	continue;
+      }
+
       // define the multifield vector names (Nval vectors x Ny elements)
       ALLOCATE (vec, Vector *, Nval);
@@ -429,52 +497,6 @@
       }
 
-      if (!strcmp (type, "char")) {
-	char *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[k][0].elements.Int[j] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "short")) {
-	short *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[k][0].elements.Int[j] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "int")) {
-	int *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[k][0].elements.Int[j] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "int64_t")) {
-	int64_t *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[k][0].elements.Int[j] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "float")) {
-	float *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[k][0].elements.Flt[j] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "double")) {
-	double *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[k][0].elements.Flt[j] = *Ptr;
-	  }
-	}
-      }
+      if (!VectorAssignData (vec, type, data, Ny, Nval)) ESCAPE ("bad column type %s", type);
+
     } else {
       // define the multifield vector names (Ny vectors x Nval elements)
@@ -489,52 +511,5 @@
       }
 
-      if (!strcmp (type, "char")) {
-	char *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[j][0].elements.Int[k] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "short")) {
-	short *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[j][0].elements.Int[k] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "int")) {
-	int *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[j][0].elements.Int[k] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "int64_t")) {
-	int64_t *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[j][0].elements.Int[k] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "float")) {
-	float *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[j][0].elements.Flt[k] = *Ptr;
-	  }
-	}
-      }
-      if (!strcmp (type, "double")) {
-	double *Ptr = data;
-	for (j = 0; j < Ny; j++) {
-	  for (k = 0; k < Nval; k++, Ptr++) {
-	    vec[j][0].elements.Flt[k] = *Ptr;
-	  }
-	}
-      }
+      if (!VectorAssignDataTranspose (vec, type, data, Ny, Nval)) ESCAPE ("bad column type %s", type);
     }
     free (data);
@@ -546,2 +521,18 @@
   return (TRUE);
 }
+
+void read_vectors_cleanup () {
+
+  int i;
+
+  if (col) free (col);
+  if (coltype) free (coltype);
+  if (buffer) free (buffer);
+  if (listname) {
+    for (i = 0; i < Nvec; i++) {
+      if (listname[i]) free (listname[i]);
+    }
+    free (listname);
+  }
+  if (vec) free (vec);
+}
Index: /trunk/Ohana/src/opihi/dvo/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/dvo/Makefile	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/Makefile	(revision 37049)
@@ -25,6 +25,19 @@
 $(SRC)/dvo_host_utils.$(ARCH).o		\
 $(SRC)/region_list.$(ARCH).o		\
-$(SRC)/find_matches.$(ARCH).o		\
-$(SRC)/photometry.$(ARCH).o             
+$(SRC)/photcode_ops.$(ARCH).o	  	\
+$(SRC)/find_matches.$(ARCH).o           
+
+# $(SRC)/photometry.$(ARCH).o             
+
+broken = \
+$(SRC)/calextract.$(ARCH).o      	\
+$(SRC)/calmextract.$(ARCH).o     	\
+$(SRC)/ccd.$(ARCH).o             	\
+$(SRC)/cmd.$(ARCH).o             	\
+$(SRC)/dmagaves.$(ARCH).o	  	\
+$(SRC)/dmagmeas.$(ARCH).o	  	\
+$(SRC)/dmags.$(ARCH).o		  	\
+$(SRC)/ddmags.$(ARCH).o	  	\
+$(SRC)/fitcolors.$(ARCH).o
 
 cmds = \
@@ -32,22 +45,13 @@
 $(SRC)/avmatch.$(ARCH).o	  	\
 $(SRC)/badimages.$(ARCH).o	  	\
-$(SRC)/calextract.$(ARCH).o      	\
-$(SRC)/calmextract.$(ARCH).o     	\
 $(SRC)/catdir.$(ARCH).o             	\
-$(SRC)/ccd.$(ARCH).o             	\
 $(SRC)/cmatch.$(ARCH).o	  	\
-$(SRC)/cmd.$(ARCH).o             	\
 $(SRC)/cmpload.$(ARCH).o	  	\
 $(SRC)/cmpread.$(ARCH).o	  	\
 $(SRC)/coordimage.$(ARCH).o	  	\
 $(SRC)/coordmosaic.$(ARCH).o	  	\
-$(SRC)/ddmags.$(ARCH).o	  	\
 $(SRC)/detrend.$(ARCH).o	  	\
-$(SRC)/dmagaves.$(ARCH).o	  	\
-$(SRC)/dmagmeas.$(ARCH).o	  	\
-$(SRC)/dmags.$(ARCH).o		  	\
 $(SRC)/dmt.$(ARCH).o		  	\
 $(SRC)/elixir.$(ARCH).o                \
-$(SRC)/fitcolors.$(ARCH).o             \
 $(SRC)/fitsed.$(ARCH).o                \
 $(SRC)/gcat.$(ARCH).o		  	\
Index: /trunk/Ohana/src/opihi/dvo/avextract.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/avextract.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/avextract.c	(revision 37049)
@@ -166,6 +166,5 @@
   needMeasures = FALSE;
   for (i = 0; !needMeasures && (i < Nfields); i++) {
-    if (fields[i].magMode == MAG_NONE) continue;
-    if (fields[i].photcode == NULL) continue; // assert this?
+    if (fields[i].photcode == NULL) continue; // non-measure fields do not have a photcode
     if (fields[i].photcode[0].type == PHOT_REF) needMeasures = TRUE;
     if (fields[i].photcode[0].type == PHOT_DEP) needMeasures = TRUE;
Index: /trunk/Ohana/src/opihi/dvo/avmatch.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/avmatch.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/avmatch.c	(revision 37049)
@@ -152,5 +152,4 @@
   int needMeasures = FALSE;
   for (i = 0; !needMeasures && (i < Nfields); i++) {
-    if (fields[i].magMode == MAG_NONE) continue;
     if (fields[i].photcode == NULL) continue; // assert this?
     if (fields[i].photcode[0].type == PHOT_REF) needMeasures = TRUE;
Index: /trunk/Ohana/src/opihi/dvo/fitsed.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/fitsed.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/fitsed.c	(revision 37049)
@@ -83,5 +83,5 @@
   /* interpret command-line options */
   if ((selection = SetRegionSelection (&argc, argv)) == NULL) goto escape;
-  if (!SetPhotSelections (&argc, argv, 4)) goto usage;
+  // if (!SetPhotSelections (&argc, argv, 4)) goto usage;
 
   PLOT = FALSE;
Index: /trunk/Ohana/src/opihi/dvo/gstar.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/gstar.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/gstar.c	(revision 37049)
@@ -15,6 +15,6 @@
   GSTAR_UCDIST,
   GSTAR_AVE_AP_MAG,
-  GSTAR_AVE_MAG_20,
-  GSTAR_AVE_MAG_80,
+  GSTAR_AVE_MAG_MIN,
+  GSTAR_AVE_MAG_MAX,
   GSTAR_AVE_KRON_MAG,
   GSTAR_AVE_KRON_MAG_ERR,
@@ -307,10 +307,10 @@
 	  gprint (GP_LOG, "\n");
 
-	  /* M_20 */
-	  for (j = 0; j < Nsecfilt; j++) printPhotcodeSequence (&catalog.average[k], &catalog.secfilt[Nsecfilt*k], j, GSTAR_AVE_MAG_20);
-	  gprint (GP_LOG, "\n");
-
-	  /* M_80 */
-	  for (j = 0; j < Nsecfilt; j++) printPhotcodeSequence (&catalog.average[k], &catalog.secfilt[Nsecfilt*k], j, GSTAR_AVE_MAG_80);;
+	  /* Mmin */
+	  for (j = 0; j < Nsecfilt; j++) printPhotcodeSequence (&catalog.average[k], &catalog.secfilt[Nsecfilt*k], j, GSTAR_AVE_MAG_MIN);
+	  gprint (GP_LOG, "\n");
+
+	  /* Mmax */
+	  for (j = 0; j < Nsecfilt; j++) printPhotcodeSequence (&catalog.average[k], &catalog.secfilt[Nsecfilt*k], j, GSTAR_AVE_MAG_MAX);;
 	  gprint (GP_LOG, "\n");
 
@@ -374,10 +374,13 @@
 	  int Nv = index[j];
 
-	  Mcat = PhotCat (&catalog.measure[Nv]);
+	  Mcat = PhotCat (&catalog.measure[Nv], MAG_CLASS_PSF);
 	  if (INST) {
-	    Mrel = PhotInst (&catalog.measure[Nv]);
+	    Mrel = PhotInst (&catalog.measure[Nv], MAG_CLASS_PSF);
 	  } else {
-	    Mrel = PhotRel (&catalog.measure[Nv], &catalog.average[k], &catalog.secfilt[k*Nsecfilt]);
+	    Mrel = PhotRel (&catalog.measure[Nv], &catalog.average[k], &catalog.secfilt[k*Nsecfilt], MAG_CLASS_PSF);
 	  }
+
+	  float dRoff = dvoOffsetR(&catalog.measure[Nv], &catalog.average[k]);
+	  float dDoff = dvoOffsetD(&catalog.measure[Nv], &catalog.average[k]);
 
 	  if (GetMeasures && !QUIET) {
@@ -387,6 +390,7 @@
 	    gprint (GP_LOG, "%6.3f  ", catalog.measure[Nv].dM);
 	    gprint (GP_LOG, "%20s  ",  date);
-	    gprint (GP_LOG, "%7.4f ",  catalog.measure[Nv].dR);
-	    gprint (GP_LOG, "%7.4f ",  catalog.measure[Nv].dD);
+	    
+	    gprint (GP_LOG, "%7.4f ",  dRoff);
+	    gprint (GP_LOG, "%7.4f ",  dDoff);
 	    gprint (GP_LOG, "0x%08x ", catalog.measure[Nv].photFlags);
 	    gprint (GP_LOG, "0x%08x ", catalog.measure[Nv].dbFlags);
@@ -447,6 +451,6 @@
 	    vec3[0].elements.Flt[N] = catalog.measure[Nv].airmass;
 	    vec4[0].elements.Flt[N] = catalog.measure[Nv].photcode;
-	    vec5[0].elements.Flt[N] = catalog.measure[Nv].dR;
-	    vec6[0].elements.Flt[N] = catalog.measure[Nv].dD;
+	    vec5[0].elements.Flt[N] = dRoff;
+	    vec6[0].elements.Flt[N] = dDoff;
 	    N ++;
 	    if (N == NPTS - 1) {
@@ -561,7 +565,7 @@
     case GSTAR_AVE_MAG_CHISQ: /* average mag chisq */
       if (seq == -1) {
-	print_short (NAN_S_SHORT, NAN_S_SHORT);
-      } else {
-	print_short (pow (10.0, 0.01*secfilt[seq].Xm), secfilt[seq].Xm);
+	print_double (NAN);
+      } else {
+	print_double (secfilt[seq].Mchisq);
       }
       break;
@@ -596,17 +600,17 @@
       break;
 
-    case GSTAR_AVE_MAG_20: /* average ap mags */
-      if (seq == -1) {
-	print_double (NAN);
-      } else {
-	print_short (0.001*secfilt[seq].M_20, secfilt[seq].M_20);
-      }
-      break;
-
-    case GSTAR_AVE_MAG_80: /* average ap mags */
-      if (seq == -1) {
-	print_double (NAN);
-      } else {
-	print_short (0.001*secfilt[seq].M_80, secfilt[seq].M_80);
+    case GSTAR_AVE_MAG_MIN: /* average ap mags */
+      if (seq == -1) {
+	print_double (NAN);
+      } else {
+	print_double (secfilt[seq].Mmin);
+      }
+      break;
+
+    case GSTAR_AVE_MAG_MAX: /* average ap mags */
+      if (seq == -1) {
+	print_double (NAN);
+      } else {
+	print_double (secfilt[seq].Mmax);
       }
       break;
@@ -632,5 +636,5 @@
 	print_double (NAN);
       } else {
-	print_double_exp (secfilt[seq].FluxPSF);
+	print_double_exp (secfilt[seq].FpsfStk);
       }
       break;
@@ -640,5 +644,5 @@
 	print_double (NAN);
       } else {
-	print_double_exp (secfilt[seq].dFluxPSF);
+	print_double_exp (secfilt[seq].dFpsfStk);
       }
       break;
@@ -648,5 +652,5 @@
 	print_double (NAN);
       } else {
-	print_double_exp (secfilt[seq].FluxKron);
+	print_double_exp (secfilt[seq].FkronStk);
       }
       break;
@@ -656,8 +660,8 @@
 	print_double (NAN);
       } else {
-	print_double_exp (secfilt[seq].dFluxKron);
-      }
-      break;
-
-  }
-}
+	print_double_exp (secfilt[seq].dFkronStk);
+      }
+      break;
+
+  }
+}
Index: /trunk/Ohana/src/opihi/dvo/imdata.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/imdata.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/imdata.c	(revision 37049)
@@ -3,5 +3,5 @@
 int imdata (int argc, char **argv) {
   
-  off_t i, j, k, n, I;
+  off_t i, j, k, I;
   int N, NPTS, found, mode, TimeSelect, TimeFormat;
   off_t Nregions, NREGIONS;
@@ -152,6 +152,5 @@
 	for (i = 0; i < catalog.Nmeasure; i++) {
 	  if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
-	  n = catalog.measure[i].averef;
-	  vec[0].elements.Flt[N] = catalog.average[n].R - catalog.measure[i].dR / 3600.0;
+	  vec[0].elements.Flt[N] = catalog.measure[i].R;
 	  N++;
 	  CHECK_REALLOCATE (vec[0].elements.Flt, opihi_flt, NPTS, N, 1000);
@@ -161,6 +160,5 @@
 	for (i = 0; i < catalog.Nmeasure; i++) {
 	  if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
-	  n = catalog.measure[i].averef;
-	  vec[0].elements.Flt[N] = catalog.average[n].D - catalog.measure[i].dD / 3600.0;
+	  vec[0].elements.Flt[N] = catalog.measure[i].D;
 	  N++;
 	  CHECK_REALLOCATE (vec[0].elements.Flt, opihi_flt, NPTS, N, 1000);
@@ -194,5 +192,5 @@
 	for (i = 0; i < catalog.Nmeasure; i++) {
 	  if ((catalog.measure[i].t < start) || (catalog.measure[i].t > stop)) continue;
-	  n = catalog.measure[i].averef;
+	  //n = catalog.measure[i].averef;
 	  // vec[0].elements.Flt[N] = catalog.average[n].M;
 	  N++;
Index: /trunk/Ohana/src/opihi/dvo/imextract.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/imextract.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/imextract.c	(revision 37049)
@@ -185,5 +185,5 @@
     gprint (GP_ERR, "  Mcal : photometry calibration (mags)\n");
     gprint (GP_ERR, "  dMcal : photometry calibration error (mags)\n");
-    gprint (GP_ERR, "  Xm : chisq of photometry calibration\n");
+    gprint (GP_ERR, "  Mchisq : chisq of photometry calibration\n");
     gprint (GP_ERR, "  photcode : numeric photcode value for image\n");
     gprint (GP_ERR, "  exptime : exposure duration (seconds)\n");
Index: /trunk/Ohana/src/opihi/dvo/init.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/init.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/init.c	(revision 37049)
@@ -66,10 +66,10 @@
   {1, "avmatch",     avmatch,      "extract average data values matched to RA,DEC points"},
   {1, "badimages",   badimages,    "look for images with anomalous astrometry"},
-  {1, "calextract",  calextract,   "extract photometry calibration"},
-  {1, "calmextract", calmextract,  "extract photometry calibration"},
+//  {1, "calextract",  calextract,   "extract photometry calibration"},
+//  {1, "calmextract", calmextract,  "extract photometry calibration"},
   {1, "catdir",      catdir_define,"re-define CATDIR"},
-  {1, "ccd",         ccd,          "plot color-color diagram"},
+//  {1, "ccd",         ccd,          "plot color-color diagram"},
   {1, "cmatch",      cmatch,       "match two catalogs"},
-  {1, "cmd",         cmd,          "plot cmd of stars in current region"},
+//  {1, "cmd",         cmd,          "plot cmd of stars in current region"},
   {1, "cmpload",     cmpload,      "load cmp file into ?"},
   {1, "cmpread",     cmpread,      "read data from cmp format files"},
@@ -77,12 +77,12 @@
   {1, "coordmosaic", coordmosaic,  "generate a map of the distortion"},
   {1, "psastro_model", psastro_model, "save psastro-format astrometry model"},
-  {1, "ddmags",      ddmags,       "plot magnitude differences"},
+//  {1, "ddmags",      ddmags,       "plot magnitude differences"},
   {1, "detrend",     detrend,      "extract from detrend database?"},
-  {1, "dmagaves",    dmagaves,     "foo"},
-  {1, "dmagmeas",    dmagmeas,     "foo"},
-  {1, "dmags",       dmags,        "plot differential magnitudes between filters"},
+//  {1, "dmagaves",    dmagaves,     "foo"},
+//  {1, "dmagmeas",    dmagmeas,     "foo"},
+//  {1, "dmags",       dmags,        "plot differential magnitudes between filters"},
   {1, "dmt",         dmt,          "plot mag scatter"},
   {1, "elixir",      elixir,       "talk to elixir"},
-  {1, "fitcolors",   fitcolors,    "fit chip-to-chip color terms"},
+//  {1, "fitcolors",   fitcolors,    "fit chip-to-chip color terms"},
   {1, "fitsed",      fitsed,       "fit stellar SEDs to objects"},
   {1, "gcat",        gcat,         "get catalog at location"},
Index: /trunk/Ohana/src/opihi/dvo/lcurve.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/lcurve.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/lcurve.c	(revision 37049)
@@ -129,5 +129,5 @@
 	if (ErrorBars) dYvec.elements.Flt[N] = catalog.measure[m].dM;
 	Xvec.elements.Flt[N] = TimeValue (catalog.measure[m].t, TimeReference, TimeFormat);
-	Yvec.elements.Flt[N] = PhotCat (&catalog.measure[m]);
+	Yvec.elements.Flt[N] = PhotCat (&catalog.measure[m], MAG_CLASS_PSF);
 	/**** need to use PhotRel optionally here ****/
 	N++; 
Index: /trunk/Ohana/src/opihi/dvo/lightcurve.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/lightcurve.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/lightcurve.c	(revision 37049)
@@ -121,7 +121,7 @@
 	dmvec[0].elements.Flt[N] = catalog.measure[m].dM;
 	if (RELPHOT) {
-	  mvec[0].elements.Flt[N] = PhotCat (&catalog.measure[m]);
+	  mvec[0].elements.Flt[N] = PhotCat (&catalog.measure[m], MAG_CLASS_PSF);
 	} else {
-	  mvec[0].elements.Flt[N] = PhotRel (&catalog.measure[m], &catalog.average[k], &catalog.secfilt[k*Nsecfilt]);
+	  mvec[0].elements.Flt[N] = PhotRel (&catalog.measure[m], &catalog.average[k], &catalog.secfilt[k*Nsecfilt], MAG_CLASS_PSF);
 	}
 	N++; 
Index: /trunk/Ohana/src/opihi/dvo/photcode_ops.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/photcode_ops.c	(revision 37049)
+++ /trunk/Ohana/src/opihi/dvo/photcode_ops.c	(revision 37049)
@@ -0,0 +1,35 @@
+# include "dvoshell.h"
+
+/* (re)load photcodes from photcode table */
+int InitPhotcodes () {
+
+  double ZERO_POINT;
+  char MasterPhotcodeFile[256];
+  char CatdirPhotcodeFile[256];
+  char *catdir;
+
+  if (VarConfig ("ZERO_PT", "%lf", &ZERO_POINT) == (char *) NULL) {
+    gprint (GP_ERR, "ZERO_PT undefined in config\n");
+    return (FALSE);
+  }
+  SetZeroPoint (ZERO_POINT);
+
+  catdir = GetCATDIR();
+  if (catdir == NULL) {
+    CatdirPhotcodeFile[0] = 0;
+  } else {
+    sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", catdir);
+  }
+
+  if (VarConfig ("PHOTCODE_FILE", "%s", MasterPhotcodeFile) == (char *) NULL) {
+    gprint (GP_ERR, "PHOTCODE_FILE undefined in config\n");
+    return (FALSE);
+  }
+
+  // XXX now that DVO does not allow write access, we can drop the MasterPhotcodeFile
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, FALSE)) {
+    gprint (GP_ERR, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
+    return (FALSE);
+  }
+  return (TRUE);
+}
Index: /trunk/Ohana/src/opihi/dvo/photometry.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/photometry.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/photometry.c	(revision 37049)
@@ -41,4 +41,5 @@
   }
 
+# if (0)
 /* selection criteria */
 /* selections based on Measure quantities */
@@ -78,5 +79,7 @@
 static time_t TimeReference;
 static int TimeFormat;
-
+# endif
+
+# if (0)
 int GetTimeSelection (time_t *tz, time_t *te) {
   *tz = tzero;
@@ -298,39 +301,7 @@
   return;
 }
-
-/* (re)load photcodes from photcode table */
-int InitPhotcodes () {
-
-  double ZERO_POINT;
-  char MasterPhotcodeFile[256];
-  char CatdirPhotcodeFile[256];
-  char *catdir;
-
-  if (VarConfig ("ZERO_PT", "%lf", &ZERO_POINT) == (char *) NULL) {
-    gprint (GP_ERR, "ZERO_PT undefined in config\n");
-    return (FALSE);
-  }
-  SetZeroPoint (ZERO_POINT);
-
-  catdir = GetCATDIR();
-  if (catdir == NULL) {
-    CatdirPhotcodeFile[0] = 0;
-  } else {
-    sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", catdir);
-  }
-
-  if (VarConfig ("PHOTCODE_FILE", "%s", MasterPhotcodeFile) == (char *) NULL) {
-    gprint (GP_ERR, "PHOTCODE_FILE undefined in config\n");
-    return (FALSE);
-  }
-
-  // XXX now that DVO does not allow write access, we can drop the MasterPhotcodeFile
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, FALSE)) {
-    gprint (GP_ERR, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
-    return (FALSE);
-  }
-  return (TRUE);
-}
-
+# endif
+
+# if (0)
 int ListPhotSelections () {
 
@@ -1121,5 +1092,7 @@
   return (list);
 }
-
+# endif
+
+# if (0)
 double GetMeasure (int param, Average *average, Measure *measure, double mag) {
 
@@ -1135,8 +1108,8 @@
       break;
     case MEAS_RA: /* OK */
-      value = average[0].R - measure[0].dR / 3600.0;
+      value = measure[0].R;
       break;
     case MEAS_DEC: /* OK */
-      value = average[0].D - measure[0].dD / 3600.0;
+      value = measure[0].D;
       break;
     case MEAS_DOPHOT: /* OK */
@@ -1156,8 +1129,8 @@
       break;
     case MEAS_RA_OFFSET: /* OK */
-      value = measure[0].dR;
+      value = dvoOffsetR(measure, average);
       break;
     case MEAS_DEC_OFFSET: /* OK */
-      value = measure[0].dD;
+      value = dvoOffsetD(measure, average);
       break;
     case MEAS_FWHM: /* OK */
@@ -1172,6 +1145,6 @@
       value = measure[0].Xccd;
 # else
-      ra  = average[0].R - measure[0].dR / 3600.0;
-      dec = average[0].D - measure[0].dD / 3600.0;
+      ra  = measure[0].R;
+      dec = measure[0].D;
       image = MatchImageDVO (measure[0].t, measure[0].photcode, measure[0].imageID);
       if (image == NULL) break;
@@ -1185,6 +1158,6 @@
       value = measure[0].Yccd;
 # else
-      ra  = average[0].R - measure[0].dR / 3600.0;
-      dec = average[0].D - measure[0].dD / 3600.0;
+      ra  = measure[0].R;
+      dec = measure[0].D;
       image = MatchImageDVO (measure[0].t, measure[0].photcode, measure[0].imageID);
       if (image == NULL) break;
@@ -1195,6 +1168,6 @@
 # if 0
     case MEAS_XMOSAIC: /* OK */
-      ra  = average[0].R - measure[0].dR / 3600.0;
-      dec = average[0].D - measure[0].dD / 3600.0;
+      ra  = measure[0].R;
+      dec = measure[0].D;
       mosaic = MatchMosaic (measure[0].t, measure[0].photcode); // XXX not used anymore
       if (mosaic == NULL) break;
@@ -1203,6 +1176,6 @@
       break;
     case MEAS_YMOSAIC: /* OK */
-      ra  = average[0].R - measure[0].dR / 3600.0;
-      dec = average[0].D - measure[0].dD / 3600.0;
+      ra  = measure[0].R;
+      dec = measure[0].D;
       mosaic = MatchMosaic (measure[0].t, measure[0].photcode); // XXX not used anymore
       if (mosaic == NULL) break;
@@ -1214,4 +1187,5 @@
   return (value);
 }
+# endif
 
 /** the mosaic entries do not use the registered mosaic found 
Index: /trunk/Ohana/src/opihi/dvo/pmeasure.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/pmeasure.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/pmeasure.c	(revision 37049)
@@ -203,15 +203,15 @@
 	if (TimeSelect && (catalog.measure[m+k].t > tzero + trange)) continue;
 	if ((PhotcodeClip != -1) && (catalog.measure[m+k].photcode != PhotcodeClip)) continue;
-	mag = PhotCat (&catalog.measure[m+k]);
+	mag = PhotCat (&catalog.measure[m+k], MAG_CLASS_PSF);
 	Zvec[Npts] = MIN (1.0, MAX (0.01, (mag - Mz) / Mr));
 	if (LimExclude && (Zvec[Npts] > 0.99)) continue;
 	if (Zvec[Npts] < 0.011) continue;
-	R = catalog.average[i].R - catalog.measure[m+k].dR/3600.0;
-	D = catalog.average[i].D - catalog.measure[m+k].dD/3600.0;
+	R = catalog.measure[m+k].R;
+	D = catalog.measure[m+k].D;
 	// XXX drop this check
 	if ((R < Rmin) || (R > Rmax) || (D < -90.0) || (D > 90.0)) {
 	  char *date;
 	  date = ohana_sec_to_date (catalog.measure[m+k].t);
-	  gprint (GP_LOG, "out: %f, %f : %s : (%f, %f) + (%f, %f)\n", R, D, date, catalog.average[i].R, catalog.average[i].D, catalog.measure[m+k].dR/3600.0, catalog.measure[m+k].dD/3600.0);
+	  gprint (GP_LOG, "out: %f, %f : %s : (%f, %f) + (%f, %f)\n", R, D, date, catalog.average[i].R, catalog.average[i].D, catalog.measure[m+k].R, catalog.measure[m+k].D);
 	  free (date);
 	}
Index: /trunk/Ohana/src/opihi/dvo/subpix.c
===================================================================
--- /trunk/Ohana/src/opihi/dvo/subpix.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/dvo/subpix.c	(revision 37049)
@@ -138,5 +138,5 @@
     for (j = 0; j < Nmeasure; j++) {
       if (measure[j].t == Timage) { 
-	Mabs = PhotCat (&measure[j]);
+	Mabs = PhotCat (&measure[j], MAG_CLASS_PSF);
 	RD_to_XY (&X, &Y, Ra, Dec, &image[I].coords);
 	t = TimeValue (measure[j].t, TimeReference, TimeFormat);
Index: /trunk/Ohana/src/opihi/include/dvomath.h
===================================================================
--- /trunk/Ohana/src/opihi/include/dvomath.h	(revision 37048)
+++ /trunk/Ohana/src/opihi/include/dvomath.h	(revision 37049)
@@ -170,4 +170,7 @@
 Vector      **ReadVectorTableFITS   PROTO((char *filename, char *extname, int *Nvec));
 
+int           VectorAssignData          PROTO((Vector **vec, char *type, void *data, int Nrows, int Nval));
+int           VectorAssignDataTranspose PROTO((Vector **vec, char *type, void *data, int Nrows, int Nval));
+
 /* buffer handling */
 Buffer       *InitBuffer            PROTO((void));
Index: /trunk/Ohana/src/opihi/include/dvoshell.h
===================================================================
--- /trunk/Ohana/src/opihi/include/dvoshell.h	(revision 37048)
+++ /trunk/Ohana/src/opihi/include/dvoshell.h	(revision 37049)
@@ -90,13 +90,4 @@
 int           wordhash              PROTO((char *word));
 
-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      dbExtractMeasures      PROTO((Average *average, SecFilt *secfilt, Measure *measure, dbField *field));
-dbValue      dbExtractImages        PROTO((Image *image, off_t Nimage, off_t N, dbField *field));
-
 int          HostTableLaunchJobs    PROTO((SkyList *sky, HostTable *table, char *basecmd, char *options, int VERBOSE));
 int          HostTableParallelOps   PROTO((SkyList *sky, int argc, char **argv, char *ResultFile, int ReadVectors, int Nelements, int VERBOSE));
Index: /trunk/Ohana/src/opihi/include/shell.h
===================================================================
--- /trunk/Ohana/src/opihi/include/shell.h	(revision 37048)
+++ /trunk/Ohana/src/opihi/include/shell.h	(revision 37049)
@@ -166,4 +166,6 @@
 // wrap readline in ohana mem functions:
 char         *opihi_readline            PROTO((char *prompt));
+
+int set_list_varname (char *line, char *base, int N, int excelStyle);
 
 /* gprint functions */
Index: /trunk/Ohana/src/opihi/lib.shell/VectorIO.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/VectorIO.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/lib.shell/VectorIO.c	(revision 37049)
@@ -134,5 +134,5 @@
   FTable ftable;
 
-  int i, j, k;
+  int i, j;
   FILE *f = NULL;
 
@@ -202,20 +202,9 @@
     assert (status);
 
-# define ASSIGN_DATA(TYPE,OPTYPE) \
-    /* assign the data to the actual vector */ \
-    if (!strcmp (type, #TYPE)) { \
-      TYPE *Ptr = data;	    \
-      for (k = 0; k < Nrows; k++) { \
-	for (j = 0; j < Nval; j++, Ptr++) { \
-	  vec[Nvec + j][0].elements.OPTYPE[k] = *Ptr; \
-	} } }
-
-    // assign the data to the actual vector
-    ASSIGN_DATA(char,    Int);
-    ASSIGN_DATA(short,   Int);
-    ASSIGN_DATA(int,     Int);
-    ASSIGN_DATA(int64_t, Int);
-    ASSIGN_DATA(float,   Flt);
-    ASSIGN_DATA(double,  Flt);
+    if (!VectorAssignData(&vec[Nvec], type, data, Nrows, Nval)) {
+      // free unneeded things
+      gprint (GP_ERR, "trouble parsing data block type %s\n", type);
+      return (NULL);
+    }
 
     free (data);
@@ -241,2 +230,52 @@
 //  return (FALSE);
 }
+
+# define ASSIGN_DATA(TYPE,DTYPE,OPTYPE)	       \
+    /* assign the data to the actual vector */ \
+    if (!strcmp (type, #TYPE)) { \
+      DTYPE *Ptr = data;		    \
+      for (k = 0; k < Nrows; k++) { \
+	for (j = 0; j < Nval; j++, Ptr++) { \
+	  vec[j][0].elements.OPTYPE[k] = *Ptr; \
+	  } } return TRUE; }
+
+int VectorAssignData (Vector **vec, char *type, void *data, int Nrows, int Nval) {
+
+  int j, k;
+
+  // assign the data to the actual vector
+  ASSIGN_DATA(byte,    char,    Int);
+  ASSIGN_DATA(char,    char,    Int);
+  ASSIGN_DATA(short,   short,   Int);
+  ASSIGN_DATA(int,     int,     Int);
+  ASSIGN_DATA(int64_t, int64_t, Int);
+  ASSIGN_DATA(float,   float,   Flt);
+  ASSIGN_DATA(double,  double,  Flt);
+
+  return FALSE;
+}
+
+# define ASSIGN_DATA_TRANSPOSE(TYPE,DTYPE,OPTYPE)	\
+    /* assign the data to the actual vector */ \
+    if (!strcmp (type, #TYPE)) { \
+      DTYPE *Ptr = data;		    \
+      for (k = 0; k < Nrows; k++) { \
+	for (j = 0; j < Nval; j++, Ptr++) { \
+	  vec[k][0].elements.OPTYPE[j] = *Ptr; \
+	  } } return TRUE; }
+
+int VectorAssignDataTranspose (Vector **vec, char *type, void *data, int Nrows, int Nval) {
+
+  int j, k;
+
+  // assign the data to the actual vector
+  ASSIGN_DATA_TRANSPOSE(byte,    char,    Int);
+  ASSIGN_DATA_TRANSPOSE(char,    char,    Int);
+  ASSIGN_DATA_TRANSPOSE(short,   short,   Int);
+  ASSIGN_DATA_TRANSPOSE(int,     int,     Int);
+  ASSIGN_DATA_TRANSPOSE(int64_t, int64_t, Int);
+  ASSIGN_DATA_TRANSPOSE(float,   float,   Flt);
+  ASSIGN_DATA_TRANSPOSE(double,  double,  Flt);
+
+  return FALSE;
+}
Index: /trunk/Ohana/src/opihi/lib.shell/string.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/string.c	(revision 37048)
+++ /trunk/Ohana/src/opihi/lib.shell/string.c	(revision 37049)
@@ -322,2 +322,31 @@
 }
 
+int set_list_varname (char *line, char *base, int N, int excelStyle) {
+
+  int i;
+    
+  // A-Z correspond to 0 - 25
+
+  if (excelStyle) {
+    float f = log(26.0);
+    float g = (N == 0) ? 0.0 : log(1.0*N);
+    int Ndigit = (int) (g / f) + 1;
+    if (Ndigit > 10) {
+      sprintf (line, "%s:ZZZZZZZZZZ", base);
+      return FALSE;
+    }
+    char name[12];
+    memset (name, 0, 12);
+    for (i = 0; i < Ndigit; i++) {
+      float Npow = Ndigit - i - 1;
+      float g = pow(26.0, Npow);
+      int V = (int) (N / g);
+      name[i] = (Npow == 0.0) ? 'A' + V : 'A' + V - 1;
+      N -= V * g;
+    }
+    sprintf (line, "%s:%s", base, name);
+  } else {
+    sprintf (line, "%s:%d", base, N);
+  }
+  return TRUE;
+}
