CCL: fix use of "term" field in sub queries
[yaz-moved-to-github.git] / src / cqltransform.c
index 55c3366..dc878b7 100644 (file)
@@ -1,8 +1,7 @@
 /* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2010 Index Data
+ * Copyright (C) 1995-2012 Index Data
  * See the file LICENSE for details.
  */
-
 /**
  * \file cqltransform.c
  * \brief Implements CQL transform (CQL to RPN conversion).
  * index
  * relationModifier
  */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 #include <yaz/rpn2cql.h>
 #include <yaz/xmalloc.h>
 #include <yaz/diagsrw.h>
@@ -136,7 +137,7 @@ static int cql_transform_parse_tok_line(cql_transform_t ct,
             break;
         }
         value_str = yaz_tok_parse_string(tp);
-        if (isdigit(*value_str))
+        if (yaz_isdigit(*value_str))
         {
             elem->which = Z_AttributeValue_numeric;
             elem->value.numeric =
@@ -616,7 +617,7 @@ static void emit_term(cql_transform_t ct,
     int i;
     const char *ns = cn->u.st.index_uri;
     int process_term = !has_modifier(cn, "regexp");
-    char *z3958_mem = 0;
+    int z3958_mode = 0;
 
     assert(cn->which == CQL_NODE_ST);
 
@@ -684,34 +685,12 @@ static void emit_term(cql_transform_t ct,
         }
         else if (first_wc)
         {
-            /* We have one or more wildcard characters, but not in a
-             * way that can be dealt with using only the standard
-             * left-, right- and both-truncation attributes.  We need
-             * to translate the pattern into a Z39.58-type pattern,
-             * which has been supported in BIB-1 since 1996.  If
-             * there's no configuration element for "truncation.z3958"
-             * we indicate this as error 28 "Masking character not
-             * supported".
-             */
-            int i;
+            z3958_mode = 1;
             cql_pr_attr(ct, "truncation", "z3958", 0,
                         pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP);
-            z3958_mem = (char *) xmalloc(length+1);
-            for (i = 0; i < length; i++)
-            {
-                if (i > 0 && term[i-1] == '\\')
-                    z3958_mem[i] = term[i];
-                else if (term[i] == '*')
-                    z3958_mem[i] = '?';
-                else if (term[i] == '?')
-                    z3958_mem[i] = '#';
-                else
-                    z3958_mem[i] = term[i];
-            }
-            z3958_mem[length] = '\0';
-            term = z3958_mem;
         }
-        else {
+        else
+        {
             /* No masking characters.  Use "truncation.none" if given. */
             cql_pr_attr(ct, "truncation", "none", 0,
                         pr, client_data, 0);
@@ -732,20 +711,47 @@ static void emit_term(cql_transform_t ct,
         }
     }
 
+    /* produce only \-sequences if:
+       1) the output is a Z39.58-trunc reserved character
+       2) the output is a PQF reserved character (\\, \")
+    */
     (*pr)("\"", client_data);
-    for (i = 0; i<length; i++)
+    for (i = 0; i < length; i++)
     {
-        /* pr(int) each character */
-        /* we do not need to deal with \-sequences because the
-           CQL and PQF terms have same \-format, bug #1988 */
-        char buf[2];
-
-        buf[0] = term[i];
-        buf[1] = '\0';
-        (*pr)(buf, client_data);
+        char x[3]; /* temp buffer */
+        if (i > 0 && term[i-1] == '\\')
+        {
+            if (term[i] == '\"' || term[i] == '\\')
+                pr("\\", client_data);
+            if (z3958_mode && strchr("#?", term[i]))
+                pr("\\\\", client_data); /* double \\ to survive PQF parse */
+            x[0] = term[i];
+            x[1] = '\0';
+            pr(x, client_data);
+        }
+        else if (z3958_mode && term[i] == '*')
+        {
+            pr("?", client_data);
+            /* avoid ?n sequences output (n=[0-9]) because that has
+               different semantics than just a single ? in Z39.58
+            */
+            if (i < length - 1 && yaz_isdigit(term[i+1]))
+                pr("\\\\", client_data); /* double \\ to survive PQF parse */
+        }
+        else if (z3958_mode && term[i] == '?')
+            pr("#", client_data);
+        else if (term[i] != '\\')
+        {
+            if (term[i] == '\"')
+                pr("\\", client_data);
+            if (z3958_mode && strchr("#?", term[i]))
+                pr("\\\\", client_data); /* double \\ to survive PQF parse */
+            x[0] = term[i];
+            x[1] = '\0';
+            pr(x, client_data);
+        }
     }
     (*pr)("\" ", client_data);
-    xfree(z3958_mem);
 }
 
 static void emit_terms(cql_transform_t ct,
@@ -875,7 +881,9 @@ void cql_transform_r(cql_transform_t ct,
         cql_transform_r(ct, cn->u.boolean.left, pr, client_data);
         cql_transform_r(ct, cn->u.boolean.right, pr, client_data);
         break;
-
+    case CQL_NODE_SORT:
+        cql_transform_r(ct, cn->u.sort.search, pr, client_data);
+        break;
     default:
         fprintf(stderr, "Fatal: impossible CQL node-type %d\n", cn->which);
         abort();
@@ -911,7 +919,8 @@ int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f)
     return cql_transform(ct, cn, cql_fputs, f);
 }
 
-int cql_transform_buf(cql_transform_t ct, struct cql_node *cn, char *out, int max)
+int cql_transform_buf(cql_transform_t ct, struct cql_node *cn,
+                      char *out, int max)
 {
     struct cql_buf_write_info info;
     int r;