Reformat a bit
[yaz-moved-to-github.git] / src / cqltransform.c
index d350242..3163775 100644 (file)
@@ -1,8 +1,7 @@
 /* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2008 Index Data
+ * Copyright (C) 1995-2011 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 <yaz/cql.h>
+#include <yaz/rpn2cql.h>
 #include <yaz/xmalloc.h>
 #include <yaz/diagsrw.h>
 #include <yaz/tokenizer.h>
 #include <yaz/wrbuf.h>
+#include <yaz/z-core.h>
+#include <yaz/matchstr.h>
+#include <yaz/oid_db.h>
+#include <yaz/log.h>
 
 struct cql_prop_entry {
     char *pattern;
     char *value;
+    Z_AttributeList attr_list;
     struct cql_prop_entry *next;
 };
 
@@ -39,6 +46,7 @@ struct cql_transform_t_ {
     int error;
     char *addinfo;
     WRBUF w;
+    NMEM nmem;
 };
 
 
@@ -50,14 +58,163 @@ cql_transform_t cql_transform_create(void)
     ct->error = 0;
     ct->addinfo = 0;
     ct->entry = 0;
+    ct->nmem = nmem_create();
     return ct;
 }
 
+static int cql_transform_parse_tok_line(cql_transform_t ct,
+                                        const char *pattern,
+                                        yaz_tok_parse_t tp)
+{
+    int ae_num = 0;
+    Z_AttributeElement *ae[20];
+    int ret = 0; /* 0=OK, != 0 FAIL */
+    int t;
+    t = yaz_tok_move(tp);
+    
+    while (t == YAZ_TOK_STRING && ae_num < 20)
+    {
+        WRBUF type_str = wrbuf_alloc();
+        WRBUF set_str = 0;
+        Z_AttributeElement *elem = 0;
+        const char *value_str = 0;
+        /* attset type=value  OR  type=value */
+        
+        elem = (Z_AttributeElement *) nmem_malloc(ct->nmem, sizeof(*elem));
+        elem->attributeSet = 0;
+        ae[ae_num] = elem;
+        wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
+        wrbuf_puts(type_str, yaz_tok_parse_string(tp));
+        t = yaz_tok_move(tp);
+        if (t == YAZ_TOK_EOF)
+        {
+            wrbuf_destroy(type_str);
+            if (set_str)
+                wrbuf_destroy(set_str);                
+            break;
+        }
+        if (t == YAZ_TOK_STRING)  
+        {  
+            wrbuf_puts(ct->w, " ");
+            wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
+            set_str = type_str;
+            
+            elem->attributeSet =
+                yaz_string_to_oid_nmem(yaz_oid_std(), CLASS_ATTSET,
+                                       wrbuf_cstr(set_str), ct->nmem);
+            
+            type_str = wrbuf_alloc();
+            wrbuf_puts(type_str, yaz_tok_parse_string(tp));
+            t = yaz_tok_move(tp);
+        }
+        elem->attributeType = nmem_intdup(ct->nmem, 0);
+        if (sscanf(wrbuf_cstr(type_str), ODR_INT_PRINTF, elem->attributeType)
+            != 1)
+        {
+            wrbuf_destroy(type_str);
+            if (set_str)
+                wrbuf_destroy(set_str);                
+            yaz_log(YLOG_WARN, "Expected numeric attribute type");
+            ret = -1;
+            break;
+        }
+
+        wrbuf_destroy(type_str);
+        if (set_str)
+            wrbuf_destroy(set_str);                
+        
+        if (t != '=')
+        {
+            yaz_log(YLOG_WARN, "Expected = after after attribute type");
+            ret = -1;
+            break;
+        }
+        t = yaz_tok_move(tp);
+        if (t != YAZ_TOK_STRING) /* value */
+        {
+            yaz_log(YLOG_WARN, "Missing attribute value");
+            ret = -1;
+            break;
+        }
+        value_str = yaz_tok_parse_string(tp);
+        if (yaz_isdigit(*value_str))
+        {
+            elem->which = Z_AttributeValue_numeric;
+            elem->value.numeric =
+                nmem_intdup(ct->nmem, atoi(value_str));
+        }
+        else
+        {
+            Z_ComplexAttribute *ca = (Z_ComplexAttribute *)
+                nmem_malloc(ct->nmem, sizeof(*ca));
+            elem->which = Z_AttributeValue_complex;
+            elem->value.complex = ca;
+            ca->num_list = 1;
+            ca->list = (Z_StringOrNumeric **)
+                nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric *));
+            ca->list[0] = (Z_StringOrNumeric *)
+                nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric));
+            ca->list[0]->which = Z_StringOrNumeric_string;
+            ca->list[0]->u.string = nmem_strdup(ct->nmem, value_str);
+            ca->num_semanticAction = 0;
+            ca->semanticAction = 0;
+        }
+        wrbuf_puts(ct->w, "=");
+        wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
+        t = yaz_tok_move(tp);
+        wrbuf_puts(ct->w, " ");
+        ae_num++;
+    }
+    if (ret == 0) /* OK? */
+    {
+        struct cql_prop_entry **pp = &ct->entry;
+        while (*pp)
+            pp = &(*pp)->next;
+        *pp = (struct cql_prop_entry *) xmalloc(sizeof(**pp));
+        (*pp)->pattern = xstrdup(pattern);
+        (*pp)->value = xstrdup(wrbuf_cstr(ct->w));
+
+        (*pp)->attr_list.num_attributes = ae_num;
+        if (ae_num == 0)
+            (*pp)->attr_list.attributes = 0;
+        else
+        {
+            (*pp)->attr_list.attributes = (Z_AttributeElement **)
+                nmem_malloc(ct->nmem,
+                            ae_num * sizeof(Z_AttributeElement *));
+            memcpy((*pp)->attr_list.attributes, ae, 
+                   ae_num * sizeof(Z_AttributeElement *));
+        }
+        (*pp)->next = 0;
+
+        if (0)
+        {
+            ODR pr = odr_createmem(ODR_PRINT);
+            Z_AttributeList *alp = &(*pp)->attr_list;
+            odr_setprint(pr, yaz_log_file());
+            z_AttributeList(pr, &alp, 0, 0);
+            odr_setprint(pr, 0);
+            odr_destroy(pr);
+        }
+    }
+    return ret;
+}
+
+int cql_transform_define_pattern(cql_transform_t ct, const char *pattern,
+                                 const char *value)
+{
+    int r;
+    yaz_tok_parse_t tp = yaz_tok_parse_buf(ct->tok_cfg, value);
+    yaz_tok_cfg_single_tokens(ct->tok_cfg, "=");
+    r = cql_transform_parse_tok_line(ct, pattern, tp);
+    yaz_tok_parse_destroy(tp);
+    return r;
+}
+    
 cql_transform_t cql_transform_open_FILE(FILE *f)
 {
     cql_transform_t ct = cql_transform_create();
     char line[1024];
-    struct cql_prop_entry **pp = &ct->entry;
 
     yaz_tok_cfg_single_tokens(ct->tok_cfg, "=");
 
@@ -77,43 +234,13 @@ cql_transform_t cql_transform_open_FILE(FILE *f)
                 cql_transform_close(ct);
                 return 0;
             }
-            t = yaz_tok_move(tp);
-
-            while (t == YAZ_TOK_STRING)
+            if (cql_transform_parse_tok_line(ct, pattern, tp))
             {
-                /* attset type=value  OR  type=value */
-                wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
-                t = yaz_tok_move(tp);
-                if (t == YAZ_TOK_EOF)
-                    break;
-                if (t == YAZ_TOK_STRING)  
-                {  
-                    wrbuf_puts(ct->w, " ");
-                    wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
-                    t = yaz_tok_move(tp);
-                }
-                if (t != '=')
-                {
-                    yaz_tok_parse_destroy(tp);
-                    cql_transform_close(ct);
-                    return 0;
-                }
-                t = yaz_tok_move(tp);
-                if (t != YAZ_TOK_STRING) /* value */
-                {
-                    yaz_tok_parse_destroy(tp);
-                    cql_transform_close(ct);
-                    return 0;
-                }
-                wrbuf_puts(ct->w, "=");
-                wrbuf_puts(ct->w, yaz_tok_parse_string(tp));
-                t = yaz_tok_move(tp);
-                wrbuf_puts(ct->w, " ");
+                yaz_tok_parse_destroy(tp);
+                cql_transform_close(ct);
+                return 0;
             }
-            *pp = (struct cql_prop_entry *) xmalloc(sizeof(**pp));
-            (*pp)->pattern = pattern;
-            (*pp)->value = xstrdup(wrbuf_cstr(ct->w));
-            pp = &(*pp)->next;
+            xfree(pattern);
         }
         else if (t != YAZ_TOK_EOF)
         {
@@ -123,7 +250,6 @@ cql_transform_t cql_transform_open_FILE(FILE *f)
         }
         yaz_tok_parse_destroy(tp);
     }
-    *pp = 0;
     return ct;
 }
 
@@ -144,6 +270,7 @@ void cql_transform_close(cql_transform_t ct)
     xfree(ct->addinfo);
     yaz_tok_cfg_destroy(ct->tok_cfg);
     wrbuf_destroy(ct->w);
+    nmem_destroy(ct->nmem);
     xfree(ct);
 }
 
@@ -158,6 +285,78 @@ cql_transform_t cql_transform_open_fname(const char *fname)
     return ct;
 }
 
+#if 0
+struct Z_AttributeElement {
+       Z_AttributeSetId *attributeSet; /* OPT */
+       int *attributeType;
+       int which;
+       union {
+               int *numeric;
+               Z_ComplexAttribute *complex;
+#define Z_AttributeValue_numeric 1
+#define Z_AttributeValue_complex 2
+       } value;
+};
+#endif
+
+static int compare_attr(Z_AttributeElement *a, Z_AttributeElement *b)
+{
+    ODR odr_a = odr_createmem(ODR_ENCODE);
+    ODR odr_b = odr_createmem(ODR_ENCODE);
+    int len_a, len_b;
+    char *buf_a, *buf_b;
+    int ret;
+
+    z_AttributeElement(odr_a, &a, 0, 0);
+    z_AttributeElement(odr_b, &b, 0, 0);
+    
+    buf_a = odr_getbuf(odr_a, &len_a, 0);
+    buf_b = odr_getbuf(odr_b, &len_b, 0);
+
+    ret = yaz_memcmp(buf_a, buf_b, len_a, len_b);
+
+    odr_destroy(odr_a);
+    odr_destroy(odr_b);
+    return ret;
+}
+
+const char *cql_lookup_reverse(cql_transform_t ct, 
+                               const char *category,
+                               Z_AttributeList *attributes)
+{
+    struct cql_prop_entry *e;
+    size_t clen = strlen(category);
+    for (e = ct->entry; e; e = e->next)
+    {
+        if (!strncmp(e->pattern, category, clen))
+        {
+            /* category matches.. See if attributes in pattern value
+               are all listed in actual attributes */
+            int i;
+            for (i = 0; i < e->attr_list.num_attributes; i++)
+            {
+                /* entry attribute */
+                Z_AttributeElement *e_ae = e->attr_list.attributes[i];
+                int j;
+                for (j = 0; j < attributes->num_attributes; j++)
+                {
+                    /* actual attribute */
+                    Z_AttributeElement *a_ae = attributes->attributes[j];
+                    int r = compare_attr(e_ae, a_ae);
+                    if (r == 0)
+                        break;
+                }
+                if (j == attributes->num_attributes)
+                    break; /* i was not found at all.. try next pattern */
+                    
+            }
+            if (i == e->attr_list.num_attributes)
+                return e->pattern + clen;
+        }
+    }
+    return 0;
+}
+                                      
 static const char *cql_lookup_property(cql_transform_t ct,
                                        const char *pat1, const char *pat2,
                                        const char *pat3)
@@ -237,7 +436,7 @@ int cql_pr_attr_uri(cql_transform_t ct, const char *category,
             int i;
             while (*cp1 && *cp1 != ' ')
                 cp1++;
-            if (cp1 - cp0 >= sizeof(buf))
+            if (cp1 - cp0 >= (ptrdiff_t) sizeof(buf))
                 break;
             memcpy(buf, cp0, cp1 - cp0);
             buf[cp1-cp0] = 0;
@@ -409,11 +608,11 @@ static int has_modifier(struct cql_node *cn, const char *name) {
 }
 
 
-void emit_term(cql_transform_t ct,
-               struct cql_node *cn,
-               const char *term, int length,
-               void (*pr)(const char *buf, void *client_data),
-               void *client_data)
+static void emit_term(cql_transform_t ct,
+                      struct cql_node *cn,
+                      const char *term, int length,
+                      void (*pr)(const char *buf, void *client_data),
+                      void *client_data)
 {
     int i;
     const char *ns = cn->u.st.index_uri;
@@ -535,7 +734,7 @@ void emit_term(cql_transform_t ct,
     }
 
     (*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
@@ -550,11 +749,11 @@ void emit_term(cql_transform_t ct,
     xfree(z3958_mem);
 }
 
-void emit_terms(cql_transform_t ct,
-                struct cql_node *cn,
-                void (*pr)(const char *buf, void *client_data),
-                void *client_data,
-                const char *op)
+static void emit_terms(cql_transform_t ct,
+                       struct cql_node *cn,
+                       void (*pr)(const char *buf, void *client_data),
+                       void *client_data,
+                       const char *op)
 {
     struct cql_node *ne = cn->u.st.extra_terms;
     if (ne)
@@ -578,11 +777,11 @@ void emit_terms(cql_transform_t ct,
     }
 }
 
-void emit_wordlist(cql_transform_t ct,
-                   struct cql_node *cn,
-                   void (*pr)(const char *buf, void *client_data),
-                   void *client_data,
-                   const char *op)
+static void emit_wordlist(cql_transform_t ct,
+                          struct cql_node *cn,
+                          void (*pr)(const char *buf, void *client_data),
+                          void *client_data,
+                          const char *op)
 {
     const char *cp0 = cn->u.st.term;
     const char *cp1;
@@ -677,7 +876,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();
@@ -713,7 +914,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;
@@ -753,6 +955,7 @@ void cql_transform_set_error(cql_transform_t ct, int error, const char *addinfo)
 /*
  * Local variables:
  * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
  * indent-tabs-mode: nil
  * End:
  * vim: shiftwidth=4 tabstop=8 expandtab