No unsigned char's in public API (except for iconv)
[yaz-moved-to-github.git] / src / sortspec.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file sortspec.c
7  * \brief Implements SortSpec parsing.
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <yaz/matchstr.h>
17
18 #include <yaz/z-core.h>
19 #include <yaz/sortspec.h>
20 #include <yaz/oid_db.h>
21 #include <yaz/wrbuf.h>
22
23 Z_SortKeySpecList *yaz_sort_spec(ODR out, const char *arg)
24 {
25     char sort_string_buf[64], sort_flags[64];
26     Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
27         odr_malloc(out, sizeof(*sksl));
28     int off;
29
30     sksl->num_specs = 0;
31     sksl->specs = (Z_SortKeySpec **)odr_malloc(out, sizeof(sksl->specs) * 20);
32
33     while ((sscanf(arg, "%63s %63s%n", sort_string_buf,
34                    sort_flags, &off)) == 2  && off > 1)
35     {
36         int i;
37         char *sort_string_sep;
38         char *sort_string = sort_string_buf;
39         Z_SortKeySpec *sks = (Z_SortKeySpec *) odr_malloc(out, sizeof(*sks));
40         Z_SortKey *sk = (Z_SortKey *) odr_malloc(out, sizeof(*sk));
41
42         arg += off;
43         sksl->specs[sksl->num_specs++] = sks;
44         sks->sortElement = (Z_SortElement *)
45             odr_malloc(out, sizeof(*sks->sortElement));
46         sks->sortElement->which = Z_SortElement_generic;
47         sks->sortElement->u.generic = sk;
48
49         if ((sort_string_sep = strchr(sort_string, '=')))
50         {
51             int i = 0;
52             sk->which = Z_SortKey_sortAttributes;
53             sk->u.sortAttributes = (Z_SortAttributes *)
54                 odr_malloc(out, sizeof(*sk->u.sortAttributes));
55             sk->u.sortAttributes->id = odr_oiddup(out, yaz_oid_attset_bib_1);
56             sk->u.sortAttributes->list = (Z_AttributeList *)
57                 odr_malloc(out, sizeof(*sk->u.sortAttributes->list));
58             sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
59                 odr_malloc(out, 10 *
60                             sizeof(*sk->u.sortAttributes->list->attributes));
61             while (i < 10 && sort_string && sort_string_sep)
62             {
63                 Z_AttributeElement *el = (Z_AttributeElement *)
64                     odr_malloc(out, sizeof(*el));
65                 sk->u.sortAttributes->list->attributes[i] = el;
66                 el->attributeSet = 0;
67                 el->attributeType = odr_intdup(out, atoi(sort_string));
68                 el->which = Z_AttributeValue_numeric;
69                 el->value.numeric =
70                     odr_intdup(out, odr_atoi(sort_string_sep + 1));
71                 i++;
72                 sort_string = strchr(sort_string, ',');
73                 if (sort_string)
74                 {
75                     sort_string++;
76                     sort_string_sep = strchr(sort_string, '=');
77                 }
78             }
79             sk->u.sortAttributes->list->num_attributes = i;
80         }
81         else
82         {
83             sk->which = Z_SortKey_sortField;
84             sk->u.sortField = odr_strdup (out, sort_string);
85         }
86         sks->sortRelation = odr_intdup(out, Z_SortKeySpec_ascending);
87         sks->caseSensitivity = odr_intdup(out, Z_SortKeySpec_caseInsensitive);
88
89         sks->which = Z_SortKeySpec_null;
90         sks->u.null = odr_nullval ();
91
92         for (i = 0; sort_flags[i]; i++)
93         {
94             switch (sort_flags[i])
95             {
96             case 'd':
97             case 'D':
98             case '>':
99                 *sks->sortRelation = Z_SortKeySpec_descending;
100                 break;
101             case 'a':
102             case 'A':
103             case '<':
104                 *sks->sortRelation = Z_SortKeySpec_ascending;
105                 break;
106             case 'i':
107             case 'I':
108                 *sks->caseSensitivity = Z_SortKeySpec_caseInsensitive;
109                 break;
110             case 'S':
111             case 's':
112                 *sks->caseSensitivity = Z_SortKeySpec_caseSensitive;
113                 break;
114             case '!':
115                 sks->which = Z_SortKeySpec_abort;
116                 sks->u.abort = odr_nullval();
117                 break;
118             case '=':
119                 sks->which = Z_SortKeySpec_missingValueData;
120                 sks->u.missingValueData = (Odr_oct*)
121                     odr_malloc(out, sizeof(Odr_oct));
122                 i++;
123                 sks->u.missingValueData->len = strlen(sort_flags+i);
124 #if OCT_SIZE
125                 sks->u.missingValueData->size = sks->u.missingValueData->len;
126 #endif
127                 sks->u.missingValueData->buf = odr_strdup(out, sort_flags+i);
128                 i += strlen(sort_flags+i) - 1;
129                 break;
130             }
131         }
132     }
133     if (!sksl->num_specs)
134         return 0;
135     return sksl;
136 }
137
138 int yaz_sort_spec_to_cql(Z_SortKeySpecList *sksl, WRBUF w)
139 {
140     int i;
141     for (i = 0; i < sksl->num_specs; i++)
142     {
143         Z_SortKeySpec *sks = sksl->specs[i];
144         Z_SortKey *sk;
145
146         if (sks->sortElement->which != Z_SortElement_generic)
147             return -1;
148
149         sk = sks->sortElement->u.generic;
150         if (i)
151             wrbuf_puts(w, " ");
152         else
153             wrbuf_puts(w, " SORTBY ");
154         if (sk->which == Z_SortKey_sortAttributes)
155             return -1;
156         else if (sk->which == Z_SortKey_sortField)
157             wrbuf_puts(w, sk->u.sortField);
158         switch (*sks->sortRelation)
159         {
160         case Z_SortKeySpec_ascending:
161             wrbuf_puts(w, "/ascending");
162             break;
163         case Z_SortKeySpec_descending:
164             wrbuf_puts(w, "/descending");
165             break;
166         }
167         switch (*sks->caseSensitivity)
168         {
169         case Z_SortKeySpec_caseSensitive:
170             wrbuf_puts(w, "/respectCase");
171             break;
172         case Z_SortKeySpec_caseInsensitive:
173             wrbuf_puts(w, "/ignoreCase");
174             break;
175         }
176         switch (sks->which)
177         {
178         case Z_SortKeySpec_null:
179             break;
180         case Z_SortKeySpec_abort:
181             wrbuf_puts(w, "/missingFail");
182             break;
183         case Z_SortKeySpec_missingValueData:
184             wrbuf_puts(w, "/missingValue=");
185             wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
186                         sks->u.missingValueData->len);
187             break;
188         }
189     }
190     return 0;
191 }
192
193 int yaz_sort_spec_to_type7(Z_SortKeySpecList *sksl, WRBUF pqf)
194 {
195     int i;
196     for (i = 0; i < sksl->num_specs; i++)
197     {
198         Z_SortKeySpec *sks = sksl->specs[i];
199         Z_SortKey *sk;
200
201         if (sks->sortElement->which != Z_SortElement_generic)
202             return -1;
203
204         sk = sks->sortElement->u.generic;
205
206         wrbuf_insert(pqf, 0, "@or ", 4);
207
208         if (sk->which == Z_SortKey_sortAttributes)
209         {
210             int j;
211             for (j = 0; j < sk->u.sortAttributes->list->num_attributes; j++)
212             {
213                 Z_AttributeElement *el =
214                     sk->u.sortAttributes->list->attributes[j];
215                 if (el->which != Z_AttributeValue_numeric)
216                     return -1;
217                 wrbuf_printf(pqf, " @attr " ODR_INT_PRINTF "=" ODR_INT_PRINTF,
218                              *el->attributeType, *el->value.numeric);
219             }
220         }
221         else if (sk->which == Z_SortKey_sortField)
222         {
223             wrbuf_puts(pqf, " @attr 1=");
224             wrbuf_puts(pqf, sk->u.sortField);
225         }
226         switch (*sks->sortRelation)
227         {
228         case Z_SortKeySpec_ascending:
229             wrbuf_puts(pqf, " @attr 7=1 ");
230             break;
231         case Z_SortKeySpec_descending:
232             wrbuf_puts(pqf, " @attr 7=2 ");
233             break;
234         }
235         wrbuf_printf(pqf, "%d", i);
236     }
237     return 0;
238 }
239
240 int yaz_sort_spec_to_srw_sortkeys(Z_SortKeySpecList *sksl, WRBUF w)
241 {
242     int i;
243     for (i = 0; i < sksl->num_specs; i++)
244     {
245         Z_SortKeySpec *sks = sksl->specs[i];
246         Z_SortKey *sk;
247
248         if (sks->sortElement->which != Z_SortElement_generic)
249             return -1;
250
251         sk = sks->sortElement->u.generic;
252
253         if (i)
254             wrbuf_puts(w, " ");
255
256         if (sk->which == Z_SortKey_sortAttributes)
257             return -1;
258         else if (sk->which == Z_SortKey_sortField)
259         {
260             wrbuf_puts(w, sk->u.sortField);
261         }
262         wrbuf_puts(w, ",,"); /* path is absent */
263         switch (*sks->sortRelation)
264         {
265         case Z_SortKeySpec_ascending:
266             wrbuf_puts(w, "1");
267             break;
268         case Z_SortKeySpec_descending:
269             wrbuf_puts(w, "0");
270             break;
271         }
272         wrbuf_puts(w, ",");
273         switch (*sks->caseSensitivity)
274         {
275         case Z_SortKeySpec_caseSensitive:
276             wrbuf_puts(w, "1");
277             break;
278         case Z_SortKeySpec_caseInsensitive:
279             wrbuf_puts(w, "0");
280             break;
281         }
282         wrbuf_puts(w, ",");
283         switch (sks->which)
284         {
285         case Z_SortKeySpec_null:
286             wrbuf_puts(w, "highValue");
287             break;
288         case Z_SortKeySpec_abort:
289             wrbuf_puts(w, "abort");
290             break;
291         case Z_SortKeySpec_missingValueData:
292             wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
293                         sks->u.missingValueData->len);
294             break;
295         }
296     }
297     return 0;
298 }
299
300 int yaz_sort_spec_to_solr_sortkeys(Z_SortKeySpecList *sksl, WRBUF w)
301 {
302     int i;
303     for (i = 0; i < sksl->num_specs; i++)
304     {
305         Z_SortKeySpec *sks = sksl->specs[i];
306         Z_SortKey *sk;
307
308         if (sks->sortElement->which != Z_SortElement_generic)
309             return -1;
310
311         sk = sks->sortElement->u.generic;
312
313         if (i)
314             wrbuf_puts(w, ",");
315
316         if (sk->which == Z_SortKey_sortAttributes)
317             return -1;
318         else if (sk->which == Z_SortKey_sortField)
319         {
320             wrbuf_puts(w, sk->u.sortField);
321         }
322         switch (*sks->sortRelation)
323         {
324         case Z_SortKeySpec_ascending:
325             wrbuf_puts(w, " asc");
326             break;
327         case Z_SortKeySpec_descending:
328             wrbuf_puts(w, " desc");
329             break;
330         }
331     }
332     return 0;
333 }
334
335
336 int yaz_srw_sortkeys_to_sort_spec(const char *srw_sortkeys, WRBUF w)
337 {
338     /* sru sortkey layout: path,schema,ascending,caseSensitive,missingValue */
339     /* see cql_sortby_to_sortkeys of YAZ. */
340     char **sortspec;
341     int num_sortspec = 0;
342     int i;
343     NMEM nmem = nmem_create();
344
345     if (srw_sortkeys)
346         nmem_strsplit_blank(nmem, srw_sortkeys, &sortspec, &num_sortspec);
347     for (i = 0; i < num_sortspec; i++)
348     {
349         char **arg;
350         int num_arg;
351         int ascending = 1;
352         int case_sensitive = 0;
353         const char *missing = 0;
354         nmem_strsplitx(nmem, ",", sortspec[i], &arg, &num_arg, 0);
355
356         if (num_arg > 2 && arg[2][0])
357             ascending = atoi(arg[2]);
358         if (num_arg > 3 && arg[3][0])
359             case_sensitive = atoi(arg[3]);
360         if (num_arg > 4 && arg[4][0])
361             missing = arg[4];
362
363         if (i)
364             wrbuf_puts(w, " ");
365
366         wrbuf_puts(w, arg[0]); /* field */
367         wrbuf_puts(w, " ");
368
369         wrbuf_puts(w, ascending ? "a" : "d");
370         wrbuf_puts(w, case_sensitive ? "s" : "i");
371         if (missing)
372         {
373             if (!strcmp(missing, "omit")) {
374                 ;
375             }
376             else if (!strcmp(missing, "abort"))
377                 wrbuf_puts(w, "!");
378             else if (!strcmp(missing, "lowValue")) {
379                 ;
380             }
381             else if (!strcmp(missing, "highValue")) {
382                 ;
383             }
384             else
385             {
386                 wrbuf_puts(w, "=");
387                 wrbuf_puts(w, missing);
388             }
389         }
390     }
391     nmem_destroy(nmem);
392     return 0;
393 }
394
395 int yaz_solr_sortkeys_to_sort_spec(const char *solr_sortkeys, WRBUF w)
396 {
397     /* Solr sortkey layout: field order[, field order] */
398     /* see cql_sortby_to_sortkeys of YAZ. */
399     char **sortspec;
400     int num_sortspec = 0;
401     int i;
402     NMEM nmem = nmem_create();
403
404     if (solr_sortkeys)
405         nmem_strsplit(nmem, ",", solr_sortkeys, &sortspec, &num_sortspec);
406     for (i = 0; i < num_sortspec; i++)
407     {
408         char **arg;
409         int num_arg;
410         char order = 'a';
411         int case_sensitive = 0;
412         nmem_strsplitx(nmem, " ", sortspec[i], &arg, &num_arg, 0);
413
414         if (num_arg != 2)
415             return -1;
416
417         if (!yaz_matchstr(arg[1], "asc"))
418                 order = 'a';
419         else if (!yaz_matchstr(arg[1], "desc"))
420             order = 'd';
421         else
422             return -1;
423
424         if (i)
425             wrbuf_puts(w, " ");
426
427         wrbuf_puts(w, arg[0]); /* field */
428         wrbuf_puts(w, " ");
429
430         wrbuf_putc(w, order);
431         // Always in-sensitive
432         wrbuf_puts(w, case_sensitive ? "s" : "i");
433     }
434     nmem_destroy(nmem);
435     return 0;
436 }
437
438
439 /*
440  * Local variables:
441  * c-basic-offset: 4
442  * c-file-style: "Stroustrup"
443  * indent-tabs-mode: nil
444  * End:
445  * vim: shiftwidth=4 tabstop=8 expandtab
446  */
447