New functions yaz_sort_spec_to_{cql,type7}
authorAdam Dickmeiss <adam@indexdata.dk>
Tue, 6 Sep 2011 11:11:30 +0000 (13:11 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Tue, 6 Sep 2011 11:11:30 +0000 (13:11 +0200)
These two new functions convert a Z39.50 SortKeySpecList to CQL
SORTBY and Type-1/RPN with type-7 sorting. Tests in test_sortspec.c.

include/yaz/sortspec.h
src/sortspec.c
test/Makefile.am
test/test_sortspec.c [new file with mode: 0644]

index 2b166d9..eb2ccdd 100644 (file)
 #define SORTSPEC_H
 
 #include <yaz/yconfig.h>
 #define SORTSPEC_H
 
 #include <yaz/yconfig.h>
-#include <yaz/proto.h>
+#include <yaz/wrbuf.h>
+#include <yaz/z-core.h>
 
 YAZ_BEGIN_CDECL
 
 
 YAZ_BEGIN_CDECL
 
-YAZ_EXPORT Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg);
+/** \brief parse sort spec string
+    \param odr memory for result
+    \param arg sort spec string
+    \returns Z39.50 SortKeySpecList or NULL on error
+    
+    The sort spec list is of the form:
+    (field flags)+ 
+    where field is either a string or one or more attribute pairs
+    key=value (there must be no blanks in either field of flags).
+    flags is a character list:
+    dD>    : descending
+    aA<    : ascending   (default)
+    iI     : ignoreccase / case-insensitive (default)
+    sS     : respectcase / case-sensitive
+    !      : abort of key is omitted in result
+    =value : missing value
+    
+    Examples:
+
+      title a
+
+      1=4 ia 1=1003 sd
+*/
+YAZ_EXPORT Z_SortKeySpecList *yaz_sort_spec(ODR odr, const char *arg);
+
+/* \brief converts SortKeySpecList to CQL sortby string
+   \param sksl SortKeySpecList
+   \param w resulting CQL SORTBY string (of string to be appended)
+   \retval 0 successful
+   \retval -1 failure
+*/
+YAZ_EXPORT int yaz_sort_spec_to_cql(Z_SortKeySpecList *sksl, WRBUF w);
+
+/* \brief adds PQF type-7 sorting to existing PQF from SortKeySpecList
+   \param sksl SortKeySpecList
+   \param w original PQF (without the Type-7)
+   \retval 0 successful
+   \retval -1 failure
+
+   If successful, the pqf WRBUF holds the new PQF including the Type-7
+   part.
+*/
+YAZ_EXPORT int yaz_sort_spec_to_type7(Z_SortKeySpecList *sksl, WRBUF pqf);
 
 YAZ_END_CDECL
 
 
 YAZ_END_CDECL
 
index c733aad..76e0f2f 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 
 #include <string.h>
 #include <stdlib.h>
 
-#include <yaz/proto.h>
+#include <yaz/z-core.h>
 #include <yaz/sortspec.h>
 #include <yaz/oid_db.h>
 #include <yaz/sortspec.h>
 #include <yaz/oid_db.h>
+#include <yaz/wrbuf.h>
 
 
-Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg)
+Z_SortKeySpecList *yaz_sort_spec(ODR out, const char *arg)
 {
     char sort_string_buf[64], sort_flags[64];
     Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
 {
     char sort_string_buf[64], sort_flags[64];
     Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
@@ -26,16 +27,16 @@ Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg)
     int off;
     
     sksl->num_specs = 0;
     int off;
     
     sksl->num_specs = 0;
-    sksl->specs = (Z_SortKeySpec **)odr_malloc (out, sizeof(sksl->specs) * 20);
+    sksl->specs = (Z_SortKeySpec **)odr_malloc(out, sizeof(sksl->specs) * 20);
     
     
-    while ((sscanf (arg, "%63s %63s%n", sort_string_buf,
-                    sort_flags, &off)) == 2  && off > 1)
+    while ((sscanf(arg, "%63s %63s%n", sort_string_buf,
+                   sort_flags, &off)) == 2  && off > 1)
     {
         int i;
         char *sort_string_sep;
         char *sort_string = sort_string_buf;
     {
         int i;
         char *sort_string_sep;
         char *sort_string = sort_string_buf;
-        Z_SortKeySpec *sks = (Z_SortKeySpec *)odr_malloc (out, sizeof(*sks));
-        Z_SortKey *sk = (Z_SortKey *)odr_malloc (out, sizeof(*sk));
+        Z_SortKeySpec *sks = (Z_SortKeySpec *) odr_malloc(out, sizeof(*sks));
+        Z_SortKey *sk = (Z_SortKey *) odr_malloc(out, sizeof(*sk));
         
         arg += off;
         sksl->specs[sksl->num_specs++] = sks;
         
         arg += off;
         sksl->specs[sksl->num_specs++] = sks;
@@ -44,17 +45,17 @@ Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg)
         sks->sortElement->which = Z_SortElement_generic;
         sks->sortElement->u.generic = sk;
         
         sks->sortElement->which = Z_SortElement_generic;
         sks->sortElement->u.generic = sk;
         
-        if ((sort_string_sep = strchr (sort_string, '=')))
+        if ((sort_string_sep = strchr(sort_string, '=')))
         {
             int i = 0;
             sk->which = Z_SortKey_sortAttributes;
             sk->u.sortAttributes = (Z_SortAttributes *)
         {
             int i = 0;
             sk->which = Z_SortKey_sortAttributes;
             sk->u.sortAttributes = (Z_SortAttributes *)
-                odr_malloc (out, sizeof(*sk->u.sortAttributes));
+                odr_malloc(out, sizeof(*sk->u.sortAttributes));
             sk->u.sortAttributes->id = odr_oiddup(out, yaz_oid_attset_bib_1);
             sk->u.sortAttributes->list = (Z_AttributeList *)
             sk->u.sortAttributes->id = odr_oiddup(out, yaz_oid_attset_bib_1);
             sk->u.sortAttributes->list = (Z_AttributeList *)
-                odr_malloc (out, sizeof(*sk->u.sortAttributes->list));
+                odr_malloc(out, sizeof(*sk->u.sortAttributes->list));
             sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
             sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
-                odr_malloc (out, 10 * 
+                odr_malloc(out, 10 * 
                             sizeof(*sk->u.sortAttributes->list->attributes));
             while (i < 10 && sort_string && sort_string_sep)
             {
                             sizeof(*sk->u.sortAttributes->list->attributes));
             while (i < 10 && sort_string && sort_string_sep)
             {
@@ -62,16 +63,16 @@ Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg)
                     odr_malloc (out, sizeof(*el));
                 sk->u.sortAttributes->list->attributes[i] = el;
                 el->attributeSet = 0;
                     odr_malloc (out, sizeof(*el));
                 sk->u.sortAttributes->list->attributes[i] = el;
                 el->attributeSet = 0;
-                el->attributeType = odr_intdup (out, atoi (sort_string));
+                el->attributeType = odr_intdup(out, atoi(sort_string));
                 el->which = Z_AttributeValue_numeric;
                 el->value.numeric =
                 el->which = Z_AttributeValue_numeric;
                 el->value.numeric =
-                    odr_intdup (out, atoi (sort_string_sep + 1));
+                    odr_intdup(out, odr_atoi(sort_string_sep + 1));
                 i++;
                 sort_string = strchr(sort_string, ',');
                 if (sort_string)
                 {
                     sort_string++;
                 i++;
                 sort_string = strchr(sort_string, ',');
                 if (sort_string)
                 {
                     sort_string++;
-                    sort_string_sep = strchr (sort_string, '=');
+                    sort_string_sep = strchr(sort_string, '=');
                 }
             }
             sk->u.sortAttributes->list->num_attributes = i;
                 }
             }
             sk->u.sortAttributes->list->num_attributes = i;
@@ -81,8 +82,8 @@ Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg)
             sk->which = Z_SortKey_sortField;
             sk->u.sortField = odr_strdup (out, sort_string);
         }
             sk->which = Z_SortKey_sortField;
             sk->u.sortField = odr_strdup (out, sort_string);
         }
-        sks->sortRelation = odr_intdup (out, Z_SortKeySpec_ascending);
-        sks->caseSensitivity = odr_intdup (out, Z_SortKeySpec_caseSensitive);
+        sks->sortRelation = odr_intdup(out, Z_SortKeySpec_ascending);
+        sks->caseSensitivity = odr_intdup(out, Z_SortKeySpec_caseInsensitive);
 
         sks->which = Z_SortKeySpec_null;
         sks->u.null = odr_nullval ();
 
         sks->which = Z_SortKeySpec_null;
         sks->u.null = odr_nullval ();
@@ -130,6 +131,109 @@ Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg)
         return 0;
     return sksl;
 }
         return 0;
     return sksl;
 }
+
+int yaz_sort_spec_to_cql(Z_SortKeySpecList *sksl, WRBUF w)
+{
+    int i;
+    for (i = 0; i < sksl->num_specs; i++)
+    {
+        Z_SortKeySpec *sks = sksl->specs[i];
+        Z_SortKey *sk;
+
+        if (sks->sortElement->which != Z_SortElement_generic)
+            return -1;
+
+        sk = sks->sortElement->u.generic;
+        if (i)
+            wrbuf_puts(w, " ");
+        else
+            wrbuf_puts(w, " SORTBY ");
+        if (sk->which == Z_SortKey_sortAttributes)
+            return -1;
+        else if (sk->which == Z_SortKey_sortField)
+            wrbuf_puts(w, sk->u.sortField);
+        switch (*sks->sortRelation)
+        {
+        case Z_SortKeySpec_ascending:
+            wrbuf_puts(w, "/ascending");
+            break;
+        case Z_SortKeySpec_descending:
+            wrbuf_puts(w, "/descending");
+            break;
+        }
+        switch (*sks->caseSensitivity)
+        {
+        case Z_SortKeySpec_caseSensitive:
+            wrbuf_puts(w, "/respectCase");
+            break;
+        case Z_SortKeySpec_caseInsensitive:
+            wrbuf_puts(w, "/ignoreCase");
+            break;
+        }
+        switch (sks->which)
+        {
+        case Z_SortKeySpec_null:
+            break;
+        case Z_SortKeySpec_abort:
+            wrbuf_puts(w, "/missingFail");
+            break;
+        case Z_SortKeySpec_missingValueData:
+            wrbuf_puts(w, "/missingValue=");
+            wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
+                        sks->u.missingValueData->len);
+        }
+    }
+    return 0;
+}
+
+int yaz_sort_spec_to_type7(Z_SortKeySpecList *sksl, WRBUF pqf)
+{
+    int i;
+    for (i = 0; i < sksl->num_specs; i++)
+    {
+        Z_SortKeySpec *sks = sksl->specs[i];
+        Z_SortKey *sk;
+
+        if (sks->sortElement->which != Z_SortElement_generic)
+            return -1;
+
+        sk = sks->sortElement->u.generic;
+
+        wrbuf_insert(pqf, 0, "@or ", 4);
+
+        if (sk->which == Z_SortKey_sortAttributes)
+        {
+            int j;
+            for (j = 0; j < sk->u.sortAttributes->list->num_attributes; j++)
+            {
+                Z_AttributeElement *el =
+                    sk->u.sortAttributes->list->attributes[j];
+                if (el->which != Z_AttributeValue_numeric)
+                    return -1;
+                wrbuf_printf(pqf, " @attr " ODR_INT_PRINTF "=" ODR_INT_PRINTF,
+                             *el->attributeType, *el->value.numeric);
+            }
+        }
+        else if (sk->which == Z_SortKey_sortField)
+        {
+            wrbuf_puts(pqf, " @attr 1=");
+            wrbuf_puts(pqf, sk->u.sortField);
+        }
+        switch (*sks->sortRelation)
+        {
+        case Z_SortKeySpec_ascending:
+            wrbuf_puts(pqf, " @attr 7=1 ");
+            break;
+        case Z_SortKeySpec_descending:
+            wrbuf_puts(pqf, " @attr 7=2 ");
+            break;
+        }
+        wrbuf_printf(pqf, "%d", i);
+    }
+    return 0;
+}
+
+
 /*
  * Local variables:
  * c-basic-offset: 4
 /*
  * Local variables:
  * c-basic-offset: 4
index 3dcb5d3..cc857ef 100644 (file)
@@ -1,15 +1,17 @@
 ## This file is part of the YAZ toolkit.
 ## Copyright (C) 1995-2011 Index Data
 
 ## This file is part of the YAZ toolkit.
 ## Copyright (C) 1995-2011 Index Data
 
-check_PROGRAMS = test_cql2ccl \
- test_xmalloc test_iconv test_nmem test_matchstr test_wrbuf \
- test_odr test_ccl test_log test_mutex \
- test_soap1 test_soap2 test_solr test_odrstack test_log_thread \
- test_xmlquery test_pquery \
- test_comstack test_filepath test_record_conv test_retrieval test_tpath \
- test_timing test_query_charset test_oid test_icu test_match_glob \
- test_rpn2cql test_rpn2solr test_json test_xml_include test_file_glob \
- test_shared_ptr test_libstemmer
+check_PROGRAMS = test_ccl test_comstack test_cql2ccl \
+ test_filepath test_file_glob \
+ test_iconv test_icu test_json \
+ test_libstemmer test_log test_log_thread \
+ test_match_glob test_matchstr test_mutex \
+ test_nmem test_odr test_odrstack test_oid  \
+ test_pquery test_query_charset \
+ test_record_conv test_rpn2cql test_rpn2solr test_retrieval \
+ test_shared_ptr test_soap1 test_soap2 test_solr test_sortspec \
+ test_timing test_tpath test_wrbuf \
+ test_xmalloc test_xml_include test_xmlquery
 
 check_SCRIPTS = test_marc.sh test_marccol.sh test_cql2xcql.sh \
        test_cql2pqf.sh test_icu.sh
 
 check_SCRIPTS = test_marc.sh test_marccol.sh test_cql2xcql.sh \
        test_cql2pqf.sh test_icu.sh
@@ -72,6 +74,7 @@ test_mutex_SOURCES = test_mutex.c
 test_soap1_SOURCES = test_soap1.c
 test_soap2_SOURCES = test_soap2.c
 test_solr_SOURCES = test_solr.c
 test_soap1_SOURCES = test_soap1.c
 test_soap2_SOURCES = test_soap2.c
 test_solr_SOURCES = test_solr.c
+test_sortspec_SOURCES = test_sortspec.c
 test_log_thread_SOURCES = test_log_thread.c
 test_xmlquery_SOURCES = test_xmlquery.c
 test_pquery_SOURCES = test_pquery.c
 test_log_thread_SOURCES = test_log_thread.c
 test_xmlquery_SOURCES = test_xmlquery.c
 test_pquery_SOURCES = test_pquery.c
diff --git a/test/test_sortspec.c b/test/test_sortspec.c
new file mode 100644 (file)
index 0000000..1af0f1f
--- /dev/null
@@ -0,0 +1,143 @@
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2011 Index Data
+ * See the file LICENSE for details.
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <yaz/wrbuf.h>
+#include <yaz/sortspec.h>
+#include <yaz/log.h>
+#include <yaz/test.h>
+
+static int cql(const char *arg, const char *expected_result)
+{
+    ODR odr = odr_createmem(ODR_ENCODE);
+    Z_SortKeySpecList *sort_spec = yaz_sort_spec(odr, arg);
+    int ret = 0;
+
+    if (!sort_spec)
+    {
+        yaz_log(YLOG_WARN, "yaz_sort_spec : parse error: %s", arg);
+    }
+    else
+    {
+        WRBUF w = wrbuf_alloc();
+        int r = yaz_sort_spec_to_cql(sort_spec, w);
+
+        if (!expected_result && r)
+            ret = 1;
+        else if (expected_result && r == 0)
+        {
+            if (strcmp(wrbuf_cstr(w), expected_result) == 0)
+                ret = 1;
+            else
+            {
+                yaz_log(YLOG_WARN, "sort: diff: %s", arg);
+                yaz_log(YLOG_WARN, " expected %s", expected_result);
+                yaz_log(YLOG_WARN, " got      %s", wrbuf_cstr(w));
+            }
+        }
+        else if (r)
+        {
+            yaz_log(YLOG_WARN, "sort: diff %s", arg);
+            yaz_log(YLOG_WARN, " expected %s", expected_result);
+            yaz_log(YLOG_WARN, " got error %d", r);
+        }
+        else if (r == 0)
+        {
+            yaz_log(YLOG_WARN, "sort: diff %s", arg);
+            yaz_log(YLOG_WARN, " expected error");
+            yaz_log(YLOG_WARN, " got %s", wrbuf_cstr(w));
+        }
+        wrbuf_destroy(w);
+    }
+    odr_destroy(odr);
+    return ret;
+}
+
+static int type7(const char *arg, const char *expected_result)
+{
+    ODR odr = odr_createmem(ODR_ENCODE);
+    Z_SortKeySpecList *sort_spec = yaz_sort_spec(odr, arg);
+    int ret = 0;
+
+    if (!sort_spec)
+    {
+        yaz_log(YLOG_WARN, "yaz_sort_spec : parse error: %s", arg);
+    }
+    else
+    {
+        WRBUF w = wrbuf_alloc();
+        int r;
+
+        wrbuf_puts(w, "q");
+        r = yaz_sort_spec_to_type7(sort_spec, w);
+
+        if (!expected_result && r)
+            ret = 1;
+        else if (expected_result && r == 0)
+        {
+            if (strcmp(wrbuf_cstr(w), expected_result) == 0)
+                ret = 1;
+            else
+            {
+                yaz_log(YLOG_WARN, "sort: diff: %s", arg);
+                yaz_log(YLOG_WARN, " expected %s", expected_result);
+                yaz_log(YLOG_WARN, " got      %s", wrbuf_cstr(w));
+            }
+        }
+        else if (r)
+        {
+            yaz_log(YLOG_WARN, "sort: diff %s", arg);
+            yaz_log(YLOG_WARN, " expected %s", expected_result);
+            yaz_log(YLOG_WARN, " got error %d", r);
+        }
+        else if (r == 0)
+        {
+            yaz_log(YLOG_WARN, "sort: diff %s", arg);
+            yaz_log(YLOG_WARN, " expected error");
+            yaz_log(YLOG_WARN, " got %s", wrbuf_cstr(w));
+        }
+        wrbuf_destroy(w);
+    }
+    odr_destroy(odr);
+    return ret;
+}
+
+static void tst(void)
+{
+    YAZ_CHECK(cql("title a",
+                  " SORTBY title/ascending/ignoreCase"));
+    YAZ_CHECK(cql("title a date ds",
+                  " SORTBY title/ascending/ignoreCase"
+                  " date/descending/respectCase"));
+    YAZ_CHECK(cql("1=4,2=3 a", 0));
+
+    YAZ_CHECK(type7("title a",
+                  "@or q @attr 1=title @attr 7=1 0"));
+    YAZ_CHECK(type7("title a date ds",
+                    "@or @or q @attr 1=title @attr 7=1 0"
+                    " @attr 1=date @attr 7=2 1"));
+    YAZ_CHECK(type7("1=4,2=3 a",
+                  "@or q @attr 1=4 @attr 2=3 @attr 7=1 0"));
+}
+
+int main(int argc, char **argv)
+{
+    YAZ_CHECK_INIT(argc, argv);
+    YAZ_CHECK_LOG();
+    tst();
+    YAZ_CHECK_TERM;
+}
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+