Index: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/avextract.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/avextract.c	(revision 13439)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/avextract.c	(revision 13440)
@@ -24,31 +24,43 @@
   Nsecfilt = GetPhotcodeNsecfilt ();
 
+  // command-line is of the form: avextract field,field, field [where (field op value)...]
+
+  // parse the fields to be extracted and returned
+  narg = argc;
+  fields = ParseCmdlineFields (argc, argv, DVO_TABLE_AVERAGE, &last, &Nfields);
+  if (fields == NULL) return (FALSE);
+
+  // require 'where' before boolean math
+  if ((last != argc) && (strcasecmp(argv[last], "where") || (last >= argc - 2))) {
+    gprint (GP_ERR, "syntax error\n");
+    free (fields);
+    return (FALSE);
+  }
+
+  // parse the remainder of the line as a boolean math expression
+  cstack = isolate_elements (argv-last, &argv[last+1], &Ncstack);
+  
+  // construct the db Boolean math stack
+  dbStack = db_convert_to_RPN (Ncstack, cstack, &NdbStack);
+
+  Nreturn = Nfields; 
+  db_check_stack (dbStack, NdbStack, DVO_TABLE_AVERAGE, fields, &Nfields);
+
   /* interpret command-line options */
   SetSelectionParam (0);
   if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;
-  if (!SetPhotSelections (&argc, argv, 1)) goto usage;
-
-  /* interpret required command-line arguments: mextract (value) */
-  if (argc != 2) { goto usage; }
-  param = GetAverageParam (argv[1]);
-  if (param == AVE_ZERO) {
-    if (!GetPhotcodeInfo (argv[1], &code, &mode)) {
-      GetAverageParamHelp ();
-      goto escape;
-    }
-    param = AVE_MAG;
-    for (p = argv[1]; *p != 0; p++) { 
-      if (*p == '.') *p = ':';
-    }
-  } 
-  if (!TestPhotSelections (&code, &mode, param)) goto escape;
 
   /* load region corresponding to selection above */
   if ((skylist = SelectRegions (RegionName, RegionList)) == NULL) goto escape;
 
-  /* create storage vector */
-  N = 0;
+  /* create output storage vectors */
+  ALLOCATE (return, float, Nreturn);
+  ALLOCATE (vec, Vector, Nreturn);
+  for (i = 0; i < Nreturn; i++) {
+    if ((vec[i] = SelectVector (fields[i].name, ANYVECTOR, TRUE)) == NULL) goto escape;
+  }
+
+  Npts = 0;
   NPTS = 1;
-  if ((vec = SelectVector (argv[1], ANYVECTOR, TRUE)) == NULL) goto escape;
 
   // XXX need to add interrupt test to this loop
@@ -70,10 +82,10 @@
       // extract the relevant values
       for (n = 0; n < Nfields; n++) {
-	value[n] = ExtractAveragesNew (&catalog.average[j], &catalog.secfilt[j*Nsecfilt], &catalog.measure[m], field[n]);
+	values[n] = ExtractAveragesNew (&catalog.average[j], &catalog.secfilt[j*Nsecfilt], &catalog.measure[m], fields[n]);
       }
       // test the conditional statement
-      if (!CheckBooleanCond (stack, Nstack, value, field, Nfield)) continue;
-      for (n = 0; n < Nfields; n++) {
-	vec[n].elements[N] = value[n];
+      if (!CheckBooleanCond (dbStack, NdbStack, values, fields, Nfields)) continue;
+      for (n = 0; n < Nreturn; n++) {
+	vec[n].elements[N] = values[n];
       }
       N++;
Index: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dbStackMath.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dbStackMath.c	(revision 13440)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dbStackMath.c	(revision 13440)
@@ -0,0 +1,136 @@
+# include "opihi.h"
+
+dvoStack *db_binary (dvoStack *V1, dvoStack *V2, char *op, float *fields, int Nfields) {
+
+  float M1, M2;
+  
+  if (V1->type == 'F') {
+    N = V1->field;
+    M1 = fields[N];
+  } else {
+    M1 = V1->Float;
+  }
+  
+  if (V2->type == 'F') {
+    N = V2->field;
+    M2 = fields[N];
+  } else {
+    M2 = V2->Float;
+  }
+
+  ALLOCATE (OUT, dvoStack, 1);
+  OUT->type = 'T';
+
+  // use an enum for the op...
+  switch (op[0]) { 
+  case '+': 
+    OUT->Float = M1 + M2;
+    break; 
+  case '-': 
+    OUT->Float = M1 - M2;
+    break; 
+  case '*': 
+    OUT->Float = M1 * M2;
+    break; 
+  case '/': 
+    OUT->Float = M1 / M2;
+    break; 
+  case '%': 
+    OUT->Float = (int) M1 % (int) M2;
+    break; 
+  case 0x5e: 
+    OUT->Float = pow (M1, M2);
+    break; 
+  case 'D': 
+    OUT->Float = MIN (M1, M2);
+    break; 
+  case 'U': 
+    OUT->Float = MAX (M1, M2);
+    break; 
+  case '<': 
+    OUT->Float = (M1 < M2) ? 1 : 0;
+    break; 
+  case '>': 
+    OUT->Float = (M1 > M2) ? 1 : 0;
+    break; 
+  case '&': 
+    OUT->Float = ((int)M1 & (int)M2);
+    break; 
+  case '|': 
+    OUT->Float = ((int)M1 | (int)M2);
+    break; 
+  case 'E': 
+    OUT->Float = (M1 == M2) ? 1 : 0;
+    break; 
+  case 'N': 
+    OUT->Float = (M1 != M2) ? 1 : 0;
+    break; 
+  case 'L': 
+    OUT->Float = (M1 <= M2) ? 1 : 0;
+    break; 
+  case 'G': 
+    OUT->Float = (M1 >= M2) ? 1 : 0;
+    break; 
+  case 'A': 
+    OUT->Float = (M1 && M2) ? 1 : 0;
+    break; 
+  case 'O': 
+    OUT->Float = (M1 || M2) ? 1 : 0;
+    break; 
+  default:
+    return (NULL);
+  }
+
+  return (OUT);
+}
+
+dvoStack *db_unary (dvoStack *V1, dvoStack *V2, char *op, float *fields, int Nfields) {
+
+  float M1;
+
+  if (V1->type == 'F') {
+    N = V1->field;
+    M1 = fields[N];
+  } else {
+    M1 = V1->Float;
+  }
+  
+  ALLOCATE (OUT, dvoStack, 1);
+  OUT->type = 'T';
+
+  if (!strcmp (op, "="))      {   OUT->Float = M1;                 }
+  if (!strcmp (op, "abs"))    {   OUT->Float = fabs(M1);           }
+  if (!strcmp (op, "int"))    {   OUT->Float = (float)(int)(M1);   }
+  if (!strcmp (op, "exp"))    {   OUT->Float = exp (M1);           }
+  if (!strcmp (op, "ten"))    {   OUT->Float = pow (10.0,M1);      }
+  if (!strcmp (op, "log"))    {   OUT->Float = log10 (M1);         }
+  if (!strcmp (op, "ln"))     {   OUT->Float = log (M1);           }
+  if (!strcmp (op, "sqrt"))   {   OUT->Float = sqrt (M1);          }
+  if (!strcmp (op, "erf"))    {   OUT->Float = erf (M1);           }
+			      			      
+  if (!strcmp (op, "sinh"))   {   OUT->Float = sinh (M1);          }
+  if (!strcmp (op, "cosh"))   {   OUT->Float = cosh (M1);          }
+  if (!strcmp (op, "asinh"))  {   OUT->Float = asinh (M1);         }
+  if (!strcmp (op, "acosh"))  {   OUT->Float = acosh (M1);         }
+  if (!strcmp (op, "lgamma")) {   OUT->Float = lgamma (M1);        }
+
+  if (!strcmp (op, "sin"))    {   OUT->Float = sin (M1);           }
+  if (!strcmp (op, "cos"))    {   OUT->Float = cos (M1);           }
+  if (!strcmp (op, "tan"))    {   OUT->Float = tan (M1);           }
+  if (!strcmp (op, "dsin"))   {   OUT->Float = sin (M1*RAD_DEG);   }
+  if (!strcmp (op, "dcos"))   {   OUT->Float = cos (M1*RAD_DEG);   }
+  if (!strcmp (op, "dtan"))   {   OUT->Float = tan (M1*RAD_DEG);   }
+  if (!strcmp (op, "asin"))   {   OUT->Float = asin (M1);          }
+  if (!strcmp (op, "acos"))   {   OUT->Float = acos (M1);          }
+  if (!strcmp (op, "atan"))   {   OUT->Float = atan (M1);          }
+  if (!strcmp (op, "dasin"))  {   OUT->Float = asin (M1)*DEG_RAD;  }
+  if (!strcmp (op, "dacos"))  {   OUT->Float = acos (M1)*DEG_RAD;  }
+  if (!strcmp (op, "datan"))  {   OUT->Float = atan (M1)*DEG_RAD;  }
+  if (!strcmp (op, "rnd"))    {   OUT->Float = drand48();          }
+  if (!strcmp (op, "not"))    {   OUT->Float = !(M1);              }
+  if (!strcmp (op, "--"))     {   OUT->Float = - (M1);             }
+  if (!strcmp (op, "isinf"))  {   OUT->Float = !finite(M1);        }
+  if (!strcmp (op, "isnan"))  {   OUT->Float = isnan(M1);          } 
+
+  return (TRUE);
+}
Index: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/db_check_stack.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/db_check_stack.c	(revision 13440)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/db_check_stack.c	(revision 13440)
@@ -0,0 +1,54 @@
+# include "opihi.h"
+
+int db_check_stack (dvoStack *stack, int Nstack, int table, dvoField *fields, int *Nfields) {
+
+  int i, Nx, Ny, Nv, size;
+  char *c;
+
+  NFIELDS = *Nfields + 10;
+  REALLOCATE (fields, dvoField, NFIELDS);
+
+  for (i = 0; i < Nstack; i++) {
+    if (stack[i].type == 'X') {
+
+      /** if this is a number, put it on the list of scalers and move on **/
+      stack[i].Float = strtod (stack[i].name, &c);
+      if (c == stack[i].name + strlen (stack[i].name)) {
+	stack[i].type  = 'S';
+	continue;
+      } 
+
+      // 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  = 'F';
+	continue;
+      }
+
+      // this must be a field : is it a valid name?
+      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 (!status) {
+	gprint (GP_ERR, "unknown database field %s\n", stack[i].name);
+	return (FALSE);
+      }
+      stack[i].field = *Nfields;
+      stack[i].type  = 'F';
+
+      *Nfields ++;
+      CHECK_REALLOCATE (fields, dvoField, NFIELDS, *Nfields, 10);
+    }
+  }
+  return (TRUE);
+}
+
+/* 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: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/db_convert_to_RPN.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/db_convert_to_RPN.c	(revision 13440)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/db_convert_to_RPN.c	(revision 13440)
@@ -0,0 +1,210 @@
+# include "opihi.h"
+# define DUMPSTACK 0
+
+dvoStack *convert_to_RPN (int argc, char **argv, int *nstack) {
+  
+  int type, Nx, Ny;
+  int i, j, Nstack, Nop_stack, NSTACK;
+  dvoStack *stack, *op_stack;
+
+  /* max total stack size is argc, though should be less, this is safe */
+  NSTACK = argc + 5;
+  ALLOCATE (stack, dvoStack, NSTACK);
+  ALLOCATE (op_stack, dvoStack, NSTACK);
+  for (i = 0; i < NSTACK; i++) {
+    init_stack (&stack[i]);
+    init_stack (&op_stack[i]);
+  }
+  
+  Nx = Ny = Nstack = Nop_stack = 0;
+  for (i = 0; i < argc; i++) {
+    
+    /* decide on priority of object */
+    type = 0;
+    /* unary operations */
+    if (!strcmp (argv[i], "abs"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "int"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "exp"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "ten"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "log"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "ln"))     { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "sqrt"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "erf"))    { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "sinh"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "cosh"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "asinh"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "acosh"))  { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "sin"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "cos"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "tan"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dsin"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dcos"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dtan"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "asin"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "acos"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "atan"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dasin"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "dacos"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "datan"))  { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "lgamma")) { type = 9; goto gotit; }
+
+    if (!strcmp (argv[i], "rnd"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "xramp"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "yramp"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "ramp"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "zero"))   { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "--"))     { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "not"))    { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "isinf"))  { type = 9; goto gotit; }
+    if (!strcmp (argv[i], "isnan"))  { type = 9; goto gotit; }
+
+    /* binary operations */
+    if (!strcmp (argv[i], "^"))      { type = 8; goto gotit; }
+
+    if (!strcmp (argv[i], "@"))      { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "/"))      { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "*"))      { type = 7; goto gotit; }
+    if (!strcmp (argv[i], "%"))      { type = 7; goto gotit; }
+
+    if (!strcmp (argv[i], "+"))      { type = 6; goto gotit; }
+    if (!strcmp (argv[i], "-"))      { type = 6; goto gotit; }
+	
+    if (!strcmp (argv[i], "&"))      { type = 5; goto gotit; }
+    if (!strcmp (argv[i], "|"))      { type = 5; goto gotit; }
+
+    if (!strcmp (argv[i], "<"))      { type = 4; goto gotit; }
+    if (!strcmp (argv[i], ">"))      { type = 4; goto gotit; }
+    if (!strcmp (argv[i], "=="))     { type = 4; strcpy (argv[i], "E"); goto gotit; }
+    if (!strcmp (argv[i], "!="))     { type = 4; strcpy (argv[i], "N"); goto gotit; }
+    if (!strcmp (argv[i], "<="))     { type = 4; strcpy (argv[i], "L"); goto gotit; }
+    if (!strcmp (argv[i], ">="))     { type = 4; strcpy (argv[i], "G"); goto gotit; }
+    if (!strcmp (argv[i], ">>"))     { type = 4; strcpy (argv[i], "U"); goto gotit; }
+    if (!strcmp (argv[i], "<<"))     { type = 4; strcpy (argv[i], "D"); goto gotit; }
+
+    if (!strcmp (argv[i], "&&"))     { type = 3; strcpy (argv[i], "A"); goto gotit; }
+    if (!strcmp (argv[i], "||"))     { type = 3; strcpy (argv[i], "O"); goto gotit; }
+
+    if (!strcmp (argv[i], "("))      { type = 2; goto gotit; }
+    if (!strcmp (argv[i], ")"))      { type = 1; goto gotit; }
+
+  gotit:
+    /* choose how to deal with object */
+    switch (type) {
+      case 8:  /* 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--) {
+	  strcpy (stack[Nstack].name, op_stack[j].name);
+	  stack[Nstack].type = op_stack[j].type;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	/* push operator on OP stack */
+	strcpy (op_stack[Nop_stack].name, argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case 9: /* unary OPs */
+      case 7: /* binary OPs */
+      case 6:
+      case 5: 
+      case 4: 
+      case 3: 
+	/* pop previous, higher or equal operators from OP stack to stack */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type >= type); j--) {
+	  strcpy (stack[Nstack].name, op_stack[j].name);
+	  stack[Nstack].type = op_stack[j].type;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	/* push operator on OP stack */
+	strcpy (op_stack[Nop_stack].name, argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case 2:  
+	/* push operator on OP stack */
+	strcpy (op_stack[Nop_stack].name, argv[i]);
+	op_stack[Nop_stack].type = type;
+	Nop_stack ++;
+	break;
+      case 1: 
+	/* pop rest of operators from OP stack to stack, looking for '(' */
+	for (j = Nop_stack - 1; (j >= 0) && (op_stack[j].type != 2); j--) {
+	  strcpy (stack[Nstack].name, op_stack[j].name);
+	  stack[Nstack].type = op_stack[j].type;
+	  Nstack ++;
+	  Nop_stack --;
+	}
+	if ((j == -1) || (op_stack[j].type != 2)) {
+	  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 */
+	strcpy (stack[Nstack].name, argv[i]);
+	stack[Nstack].type = 'X';
+	Nstack ++;
+	break;
+    }
+  }
+
+  /* dump remaining operators on stack, checking for ')' */
+  for (j = Nop_stack - 1; j >= 0; j--) {
+    if (op_stack[j].type == 2) {
+      push_error ("syntax error: mismatched parenthesis");
+      Nstack = 0;
+      goto cleanup;
+    }
+    strcpy (stack[Nstack].name, op_stack[j].name);
+    stack[Nstack].type = op_stack[j].type;
+    Nstack ++;
+  }
+
+cleanup: 
+  /*** free up unused stack space ***/
+  clean_stack (op_stack, NSTACK);
+  free (op_stack);
+  clean_stack (&stack[Nstack], NSTACK - Nstack);
+  REALLOCATE (stack, dvoStack, 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 line 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: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvoBooleanElements.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvoBooleanElements.c	(revision 13440)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvoBooleanElements.c	(revision 13440)
@@ -0,0 +1,158 @@
+# include "opihi.h"
+
+/* local private functions */
+void InsertValue (char c);
+void EndOfString (void);
+int IsAnOp (char *c);
+int IsTwoOp (char *c);
+
+/* local private static variables */
+int Nchar, Nout, NOUT;
+char **out;
+
+// split up the input arguments into appropriate blocks
+char **dvoBooleanElements (int Nin, char **in, int *nout) {
+  
+  int i, j, minus, negate, plus, posate, OpStat, SciNotation;
+
+  NOUT = Nin;
+  Nchar = Nout = 0;
+  ALLOCATE (out, char *, NOUT);
+  ALLOCATE (out[Nout], char, NCHARS);
+
+  for (i = 0; i < Nin; i++) {
+    for (j = 0; j < strlen(in[i]); j++) {
+      SciNotation = FALSE;
+      /* identify 'negate' or 'minus' ops */
+      negate = minus = FALSE;
+      if (in[i][j] == '-') { 
+	minus = TRUE;  
+	/* if - is first thing on line, must be a negator */
+	if ((Nout == 0) && (Nchar == 0)) {  
+	  minus = FALSE;
+	  negate = TRUE;
+	  goto skip1;
+	}
+	/* check previous entry on line */
+	if (Nchar) {
+	  OpStat = IsAnOp (out[Nout]);
+	  if (out[Nout][0] == ')') OpStat = FALSE;
+	} else {
+	  OpStat = IsAnOp (out[Nout-1]);
+	  if (out[Nout-1][0] == ')') OpStat = FALSE;
+	}
+	/* if - follows an operator, must be negator */
+	if (OpStat) {
+	  minus = FALSE;
+	  negate = TRUE;
+	  goto skip1;
+	}
+	/* if - follows 'e' is part of 1e-5 */
+	if (j == 0) goto skip1;
+	if ((in[i][j-1] == 'e') || (in[i][j-1] == 'E')) {
+	  SciNotation = TRUE;
+	  negate = minus = FALSE;
+	}
+      }
+    skip1:
+      /* idenfity 'posate' or 'plus' ops */
+      posate = plus = FALSE;
+      if (in[i][j] == '+') { 
+	plus = TRUE;  
+	/* if + is first thing on line, must be a posator */
+	if ((Nout == 0) && (Nchar == 0)) {  
+	  plus = FALSE;
+	  posate = TRUE;
+	  goto skip2;
+	}
+	/* check previous entry on line */
+	if (Nchar) {
+	  OpStat = IsAnOp (out[Nout]);
+	  if (out[Nout][0] == ')') OpStat = FALSE;
+	} else {
+	  OpStat = IsAnOp (out[Nout-1]);
+	  if (out[Nout-1][0] == ')') OpStat = FALSE;
+	}
+	/* if + follows an operator, must be posator */
+	if (OpStat) {
+	  plus = FALSE;
+	  posate = TRUE;
+	  goto skip2;
+	}
+	/* if + follows 'e' is part of 1e+5 */
+	if (j == 0) goto skip2;
+	if ((in[i][j-1] == 'e') || (in[i][j-1] == 'E')) {
+	  SciNotation = TRUE;
+	  posate = plus = FALSE;
+	}
+      }
+    skip2:
+      /* operators */
+      if (negate || minus || posate || plus || (IsAnOp (&in[i][j]) && !SciNotation)) {
+	if (posate) continue;
+	EndOfString ();
+	/* copy operator to out[Nout] */
+	InsertValue (in[i][j]);
+	if (negate) InsertValue ('-');
+
+	if (IsTwoOp (&in[i][j])) {
+	  InsertValue (in[i][j+1]);
+	  j++;
+	} 
+	EndOfString ();
+	continue;
+      }
+      /* quoted string */
+      if (in[i][j] == '"') {
+	InsertValue (in[i][j]);
+	j++;
+	while ((j < strlen(in[i])) && (in[i][j] != '"')) {
+	  InsertValue (in[i][j]);
+	  j++;
+	}
+	if (in[i][j] != '"') continue;
+	/* 
+	  gprint (GP_ERR, "mismatched quotes\n");
+	  return (FALSE);
+	}
+	*/
+	InsertValue (in[i][j]);
+	EndOfString ();
+	continue;
+      }
+      /* not an operator, not a quoted string */
+      if (!OHANA_WHITESPACE (in[i][j])) {
+	InsertValue (in[i][j]);
+      } else {
+	EndOfString ();
+      }
+    }
+    EndOfString ();
+  }
+
+  /* one extra entry is allocated, free here */
+  free (out[Nout]);
+  *nout = Nout;
+  return (out);
+
+}
+
+void InsertValue (char c) {
+  out[Nout][Nchar] = c;
+  Nchar ++;
+  out[Nout][Nchar] = 0;
+}
+
+void EndOfString () {
+  if (Nchar > 0) {
+    out[Nout][Nchar] = 0;
+    Nout ++;
+    Nchar = 0;
+    
+    if (Nout >= NOUT - 1) {
+      NOUT += 10; 
+      REALLOCATE (out, char *, NOUT); 
+    } 
+    ALLOCATE (out[Nout], char, NCHARS); 
+  }
+}
Index: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvoEvaluateStack.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvoEvaluateStack.c	(revision 13440)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvoEvaluateStack.c	(revision 13440)
@@ -0,0 +1,65 @@
+# include "opihi.h"
+
+int CheckBooleanCondition (dvoStack dbStack, int NdbStack, float *values, dvoFields *fields, int Nfields) {
+  
+  int i, j, Nstack;
+  dvoStack **stack, *output;
+
+  Nstack = NdbStack;
+  ALLOCATE (stack, dvoStack *, NdbStack);
+  for (i = 0; i < NdbStack; i++) {
+    stack[i] = &dbStack[i];
+  }
+
+  for (i = 0; i < Nstack; i++) {
+
+    /***** binary operators *****/
+    if ((stack[i].type >= 3) && (stack[i].type <= 8)) {
+
+      // pre-test that op and entries match
+      output = db_binary (stack[i-2], stack[i-1], stack[i].name, fields, Nfields); 
+
+      // free temporary stack items, drop external items
+      clear_stack (stack[i-2]);
+      clear_stack (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].type == 9) {
+
+      // pre-test that op and entries match
+      output = db_unary (&stack[i-1], stack[i].name, fields, Nfields); 
+
+      // free temporary stack items, drop external items
+      clear_stack (stack[i-2]);
+      clear_stack (stack[i-1]);
+
+      for (j = i + 1; j < Nstack; j++) {
+	stack[j-1] = stack[j];
+      }
+
+      Nstack -= 1;
+      i -= 1;
+      continue;
+    } 
+  }
+
+  // pre-test that op and entries match
+  return (TRUE);
+}
+
+/* delete name and data */
+void clear_stack (dvoStack *stack) {
+
+  if (stack->type != 'T') return;
+  free (stack);
+}
Index: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvodb.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvodb.c	(revision 13439)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvodb.c	(revision 13440)
@@ -8,15 +8,35 @@
 */
 
+enum {DVO_TABLE_AVERAGE, DVO_TABLE_MEASURE};
+
 // a single db field 
 typedef struct {
-  int fieldNumber;
+  char *name;
+  int extract;
+  int table;
+  int ID;
   int magMode;
   PhotCode *photcode;
 } dvoField;
 
-ParseFields (int argc, char **argv) {
+// db boolean operations
+typedef struct {
+  char   *name;
+  char    type;
+  int     field;
+  float   Float;
+} dvoStack;
+
+dvoField *ParseCmdlineFields (int argc, char **argv, int table, int *last, int *nfields) {
+
+  int i, Nfields, NFIELDS, 
+
+  *nfields = 0;
+  Nfields = 0;
+  NFIELDS = 10;
+  ALLOCATE (fields, dvoField, NFIELDS);
 
   // examine each argv[i] entry until we reach a where 
-  for (i = 0; (i < argc) && strcasecmp (argv[i], "where"); i++) {
+  for (i = 1; (i < argc) && strcasecmp (argv[i], "where"); i++) {
     // split the word by ","
     p = argv[i];
@@ -32,7 +52,26 @@
       // identify field for word
       // need to know which type of fields to look for...
-      ParseAverageField ();
+      // 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 (!status) {
+	gprint (GP_ERR, "unknown database field %s\n", field);
+	free (field);
+	free (fields);
+	return (NULL);
+      }
       free (field);
+
+      Nfields ++;
+      CHECK_REALLOCATE (fields, dvoField, NFIELDS, Nfields, 10);
     }
   }
 
+  *last = i;
+  *nfields = Nfields;
+  return (fields);
+}
Index: /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvofields.c
===================================================================
--- /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvofields.c	(revision 13439)
+++ /branches/kapa-mods-2007-05/Ohana/src/opihi/dvo/dvofields.c	(revision 13440)
@@ -1,8 +1,2 @@
-
-# define ESCAPE(F,M) { \
-  field->fieldNumber = (F); \
-  field->magMode = (M); \
-  field->photcode = NULL; \
-  return (TRUE);
 
 int GetMagMode (char *string) {
@@ -20,7 +14,37 @@
 }
 
+PhotCode *ParsePhotcodeField (char *field, int *mode, int default) {
+
+  char *tmpstring, *p;
+  PhotCode *code;
+
+  *mode = default;
+
+  p = strchr (field, ':');
+  if (p != NULL) {
+    *mode = GetMagMode (p + 1);
+    if (*mode == MAG_NONE) return (NULL);
+    tmpstring = strncreate (field, p - field);
+  } else {
+    tmpstring = strcreate (field);
+  }
+  code = GetPhotcodebyName (tmpstring);
+  free (tmpstring);
+
+  return (code);
+}
+
+# define ESCAPE(F,M) { \
+  field->ID = (F); \
+  field->magMode = (M); \
+  field->photcode = NULL; \
+  return (TRUE);
+
 int ParseMeasureField (dvoField *field, char *fieldName) {
 
   PhotCode *code;
+
+  field->table = DVO_TABLE_MEASURE;
+  field->name  = strcreate (fieldName);
 
   if (!strcasecmp (fieldName, "RA"))       ESCAPE (MEAS_RA,   	  MAG_NONE);
@@ -45,24 +69,14 @@
 
   // check for code:mode in photcode name 
-  mode = MAG_REL;
-  p = strchr (fieldName, ':');
-  if (p != NULL) {
-    mode = GetMagMode (p + 1);
-    if (mode == MAG_NONE) return (FALSE);
-    tmpstring = strncreate (fieldName, p - fieldName);
-  } else {
-    tmpstring = strcreate (fieldName);
-  }
-  code = GetPhotcodebyName (tmpstring);
-  free (tmpstring);
-
+  code = ParsePhotcodeField (&mode, MAG_REL);
   if (code == NULL) return (FALSE);
 
   if (mode == MAG_ERR) {
-    field->fieldNumber = MEAS_dMAG;
+    field->ID = MEAS_dMAG;
   } else {
-    field->fieldNumber = MEAS_MAG;
+    field->ID = MEAS_MAG;
   }    
   
+  field->magMode = mode;
   field->photcode = code;
   return (TRUE);
@@ -72,4 +86,6 @@
 
   PhotCode *code;
+
+  field->table = DVO_TABLE_AVERAGE;
 
   if (!strcasecmp (fieldName, "RA"))    ESCAPE (AVE_RA,        MAG_NONE);
@@ -98,25 +114,15 @@
 
   // check for code:mode in photcode name 
-  mode = MAG_AVE;
-  p = strchr (fieldName, ':');
-  if (p != NULL) {
-    mode = GetMagMode (p + 1);
-    if (mode == MAG_NONE) return (FALSE);
-    tmpstring = strncreate (fieldName, p - fieldName);
-  } else {
-    tmpstring = strcreate (fieldName);
-  }
-  code = GetPhotcodebyName (tmpstring);
-  free (tmpstring);
-
+  code = ParsePhotcodeField (&mode, MAG_AVE);
   if (code == NULL) return (FALSE);
 
   // need to distinguish phot, sys errors and scatter
   if (mode == MAG_ERR) {
-    field->fieldNumber = MEAS_dMAG;
+    field->ID = MEAS_dMAG;
   } else {
-    field->fieldNumber = MEAS_MAG;
+    field->ID = MEAS_MAG;
   }    
   
+  field->magMode = mode;
   field->photcode = code;
   return (TRUE);
