From 9b2f4955aee1fcee3702bcd832dbaf7fca7243ad Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Tue, 6 Sep 2011 13:11:30 +0200 Subject: [PATCH] New functions yaz_sort_spec_to_{cql,type7} 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 | 47 +++++++++++++++- src/sortspec.c | 136 +++++++++++++++++++++++++++++++++++++++------ test/Makefile.am | 21 ++++--- test/test_sortspec.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 320 insertions(+), 27 deletions(-) create mode 100644 test/test_sortspec.c diff --git a/include/yaz/sortspec.h b/include/yaz/sortspec.h index 2b166d9..eb2ccdd 100644 --- a/include/yaz/sortspec.h +++ b/include/yaz/sortspec.h @@ -33,11 +33,54 @@ #define SORTSPEC_H #include -#include +#include +#include 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 diff --git a/src/sortspec.c b/src/sortspec.c index c733aad..76e0f2f 100644 --- a/src/sortspec.c +++ b/src/sortspec.c @@ -14,11 +14,12 @@ #include #include -#include +#include #include #include +#include -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 *) @@ -26,16 +27,16 @@ Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg) 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; - 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; @@ -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; - 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 *) - 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 *) - odr_malloc (out, sizeof(*sk->u.sortAttributes->list)); + odr_malloc(out, sizeof(*sk->u.sortAttributes->list)); 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) { @@ -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; - el->attributeType = odr_intdup (out, atoi (sort_string)); + el->attributeType = odr_intdup(out, atoi(sort_string)); 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++; - sort_string_sep = strchr (sort_string, '='); + sort_string_sep = strchr(sort_string, '='); } } 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); } - 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 (); @@ -130,6 +131,109 @@ Z_SortKeySpecList *yaz_sort_spec (ODR out, const char *arg) 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 diff --git a/test/Makefile.am b/test/Makefile.am index 3dcb5d3..cc857ef 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,15 +1,17 @@ ## 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 @@ -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_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 diff --git a/test/test_sortspec.c b/test/test_sortspec.c new file mode 100644 index 0000000..1af0f1f --- /dev/null +++ b/test/test_sortspec.c @@ -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 +#endif + +#include +#include +#include +#include +#include + +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 + */ + -- 1.7.10.4