Index: /trunk/psLib/src/types/psMetadataItemCompare.c
===================================================================
--- /trunk/psLib/src/types/psMetadataItemCompare.c	(revision 19777)
+++ /trunk/psLib/src/types/psMetadataItemCompare.c	(revision 19778)
@@ -4,4 +4,5 @@
 
 #include <stdio.h>
+#include <ctype.h>
 #include <string.h>
 #include <strings.h>
@@ -14,49 +15,126 @@
 #include "psMetadataItemCompare.h"
 
+typedef enum {
+    PS_MD_OP_EQ,
+    PS_MD_OP_LT,
+    PS_MD_OP_LE,
+    PS_MD_OP_GT,
+    PS_MD_OP_GE,
+    PS_MD_OP_NE
+} psMetadataItemCompareOp;
+
+/* determine boolean operator specified in comment: @OP: X@ (default is ==) */
+psMetadataItemCompareOp p_psMetadataItemCompareGetOp (const psMetadataItem *item) {
+
+    if (!item->comment) return PS_MD_OP_EQ;
+
+    char *p1 = strstr (item->comment, "@OP:");
+    if (!p1) return PS_MD_OP_EQ;
+    p1 += 4; // point to first char after @OP:
+    while (isblank(p1[0])) p1++;
+
+    char *p2 = strchr (p1, '@');
+    if (!p2) return PS_MD_OP_EQ;
+
+    // the string starting at p1 and p2 must contain one of the following:
+    // == or = PS_MD_OP_EQ,
+    // < PS_MD_OP_LT,
+    // <= PS_MD_OP_LE,
+    // > PS_MD_OP_GT,
+    // >= PS_MD_OP_GE,
+    // ! PS_MD_OP_NE
+    
+    // XXX a bit crude: does not catch the case of invalid chars after boolean op
+    if (!strncmp (p1, "==", 2)) return PS_MD_OP_EQ;
+    if (!strncmp (p1, "=",  1)) return PS_MD_OP_EQ;
+    if (!strncmp (p1, "<=", 2)) return PS_MD_OP_LE;
+    if (!strncmp (p1, "<",  1)) return PS_MD_OP_LT;
+    if (!strncmp (p1, ">=", 2)) return PS_MD_OP_GE;
+    if (!strncmp (p1, ">",  1)) return PS_MD_OP_GT;
+
+    return PS_MD_OP_EQ;
+}
+
+// XXX better value for tolerance?
+# define EQ_TOL 1e-6
+
+# define COMPARE_CASE(TEMPLATENAME, TEMPLATETYPE, COMPARENAME, COMPARETYPENAME) \
+  case PS_TYPE_##COMPARETYPENAME: {					 \
+      TEMPLATETYPE valueC = (TEMPLATETYPE)compare->data.COMPARENAME;	 \
+      TEMPLATETYPE valueT = (TEMPLATETYPE)template->data.TEMPLATENAME;			  \
+      /* XXX check the validiy of the type casting? */                 \
+      if (valueC != compare->data.COMPARENAME) {			 \
+	  return false;						 \
+      }								 \
+      /* does template specify a boolean operation in comment? */ \
+      psMetadataItemCompareOp op = p_psMetadataItemCompareGetOp (template);  \
+      switch (op) { \
+	case PS_MD_OP_EQ: \
+	  if ((template->type == PS_TYPE_F32) || (template->type == PS_TYPE_F64)) { \
+	      result = fabs(valueT - valueC) < EQ_TOL; \
+	  } else { \
+	      result = valueT == valueC; \
+	  } \
+	  break; \
+	case PS_MD_OP_LT: \
+	  result = valueC < valueT; \
+	  break; \
+	case PS_MD_OP_LE: \
+	  result = valueC <= valueT; \
+	  break; \
+	case PS_MD_OP_GT: \
+	  result = valueC > valueT; \
+	  break; \
+	case PS_MD_OP_GE: \
+	  result = valueC >= valueT; \
+	  break; \
+	case PS_MD_OP_NE: \
+	  result = valueC != valueT; \
+	  break; \
+	default: \
+	  psAbort ("all cases should have been handled..."); \
+      } \
+      return (result); \
+    }
+
+#define TEMPLATE_CASE(TYPENAME, NAME, TYPE)				\
+    case PS_TYPE_##TYPENAME:						\
+    switch(compare->type) {						\
+        COMPARE_CASE(NAME, TYPE, B  , BOOL);				\
+        COMPARE_CASE(NAME, TYPE, U8 , U8 );				\
+        COMPARE_CASE(NAME, TYPE, U16, U16);				\
+        COMPARE_CASE(NAME, TYPE, U32, U32);				\
+        COMPARE_CASE(NAME, TYPE, S8 , S8 );				\
+        COMPARE_CASE(NAME, TYPE, S16, S16);				\
+        COMPARE_CASE(NAME, TYPE, S32, S32);				\
+        COMPARE_CASE(NAME, TYPE, F32, F32);				\
+        COMPARE_CASE(NAME, TYPE, F64, F64);				\
+      default:								\
+        psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Don't know how to compare types %x and %x\n", \
+                compare->type, template->type);				\
+        return false;							\
+    }
+
+
 bool psMetadataItemCompare(const psMetadataItem *compare, // Item to compare to the template
                            const psMetadataItem *template) // The template
 {
 
-    // First order checks
+    // First order checks:
+
+    // both items must exist
     if (! compare || ! template) {
         return false;
     }
-    if (strcmp(compare->name, template->name)
-            != 0) {
+
+    // the names of both items must match
+    if (strcmp(compare->name, template->name)) {
         return false;
     }
 
-
-    #define COMPARE_CASE(TEMPLATENAME, TEMPLATETYPE, COMPARENAME, COMPARETYPENAME) \
-case PS_TYPE_##COMPARETYPENAME: { \
-        TEMPLATETYPE value = (TEMPLATETYPE)compare->data.COMPARENAME; \
-        if (value != compare->data.COMPARENAME) { \
-            return false; \
-        } \
-        return (template->data.TEMPLATENAME == value) ? true : false; \
-    }
-
-    #define TEMPLATE_CASE(TYPENAME, NAME, TYPE) \
-case PS_TYPE_##TYPENAME: \
-    switch(compare->type) { \
-        COMPARE_CASE(NAME, TYPE, B  , BOOL); \
-        COMPARE_CASE(NAME, TYPE, U8 , U8 ); \
-        COMPARE_CASE(NAME, TYPE, U16, U16); \
-        COMPARE_CASE(NAME, TYPE, U32, U32); \
-        COMPARE_CASE(NAME, TYPE, S8 , S8 ); \
-        COMPARE_CASE(NAME, TYPE, S16, S16); \
-        COMPARE_CASE(NAME, TYPE, S32, S32); \
-        COMPARE_CASE(NAME, TYPE, F32, F32); \
-        COMPARE_CASE(NAME, TYPE, F64, F64); \
-    default: \
-        psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Don't know how to compare types %x and %x\n", \
-                compare->type, template->type); \
-        return false; \
-    }
-
+    bool result = false;
 
     switch (template->type) {
-        TEMPLATE_CASE(BOOL, B,   bool)
-        ;
+        TEMPLATE_CASE(BOOL, B,   bool) ;
         TEMPLATE_CASE(U8,   U8,  psU8 );
         TEMPLATE_CASE(U16,  U16, psU16);
@@ -67,4 +145,5 @@
         TEMPLATE_CASE(F32,  F32, psF32);
         TEMPLATE_CASE(F64,  F64, psF64);
+
     case PS_DATA_STRING:
 
