Trunc 104 is Z39.58
[yaz-moved-to-github.git] / src / rpn2cql.c
index 8dc40f5..aef1cfd 100644 (file)
@@ -18,6 +18,7 @@
 #include <yaz/diagbib1.h>
 #include <yaz/z-core.h>
 #include <yaz/wrbuf.h>
+#include <yaz/logrpn.h> /* For yaz_prox_unit_name() */
 
 static void wrbuf_vputs(const char *buf, void *client_data)
 {
@@ -219,20 +220,43 @@ static int rpn2cql_simple(cql_transform_t ct,
             int must_quote = 0;
             Odr_int trunc = lookup_truncation(apt->attributes);
 
-            if (trunc > 3 && trunc != 100)
+            if (trunc > 3 && trunc != 100 && trunc != 102)
             {
                 cql_transform_set_error(
                     ct, YAZ_BIB1_UNSUPP_TRUNCATION_ATTRIBUTE, 0);
                 ret = -1;
             }
             for (i = 0 ; i < lterm; i++)
-                if (sterm[i] == ' ')
+                if (strchr(" ()=></", sterm[i]))
                     must_quote = 1;
             if (must_quote)
                 wrbuf_puts(w, "\"");
             if (trunc == 2 || trunc == 3)
                 wrbuf_puts(w, "*");
-            wrbuf_write(w, sterm, lterm);
+            for (i = 0; i < lterm; i++)
+            {
+                if (sterm[i] == '\\' && i < lterm - 1)
+                {
+                    i++;
+                    if (strchr("*?\"\\", sterm[i]))
+                        wrbuf_putc(w, '\\');
+                    wrbuf_putc(w, sterm[i]);
+                }
+                else if (trunc == 102 && sterm[i] == '.' && sterm[i+1] == '*')
+                {
+                    wrbuf_putc(w, '*');
+                    i++;
+                }
+                else if (trunc == 102 && sterm[i] == '.')
+                    wrbuf_putc(w, '?');
+                else if (strchr("*?\"", sterm[i]))
+                {
+                    wrbuf_putc(w, '\\');
+                    wrbuf_putc(w, sterm[i]);
+                }
+                else
+                    wrbuf_putc(w, sterm[i]);
+            }
             if (trunc == 1 || trunc == 3)
                 wrbuf_puts(w, "*");
             if (must_quote)
@@ -275,9 +299,40 @@ static int rpn2cql_structure(cql_transform_t ct,
         case  Z_Operator_and_not:
             pr(" not ", client_data);
             break;
-        case  Z_Operator_prox:
-            cql_transform_set_error(ct, YAZ_BIB1_UNSUPP_SEARCH, 0);
-            return -1;
+        case  Z_Operator_prox: {
+            pr(" prox", client_data);
+            Z_ProximityOperator *prox = op->u.prox;
+            /* No way to express Odr_bool *exclusion -- ignore it */
+            if (prox->distance) {
+                char buf[21]; /* Enough for any 64-bit int */
+                char *op2name[6] = { "<", "<=", "=", ">=", ">","<>" };
+                pr("/distance", client_data);
+                if (!prox->relationType ||
+                    *prox->relationType < Z_ProximityOperator_Prox_lessThan ||
+                    *prox->relationType > Z_ProximityOperator_Prox_notEqual) {
+                    cql_transform_set_error(ct, YAZ_BIB1_UNSUPP_SEARCH,
+                        "unrecognised proximity relationType");
+                    return -1;
+                }
+                pr(op2name[*prox->relationType-1], client_data);
+                sprintf(buf, "%ld", (long) *prox->distance);
+                pr(buf, client_data);
+            }
+            if (prox->ordered) {
+                if (*prox->ordered) {
+                    pr("/ordered", client_data);
+                } else {
+                    pr("/unordered", client_data);
+                }
+            }
+            if (prox->which != Z_ProximityOperator_known ||
+                *prox->u.known != Z_ProxUnit_word) {
+                    pr("/unit=", client_data);
+                    pr(yaz_prox_unit_name(prox), client_data);
+            }
+            pr(" ", client_data);
+            break;
+        }
         }
         r = rpn2cql_structure(ct, pr, client_data, q->u.complex->s2, 1, w);
         if (nested)