Bump year
[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                 sks->u.missingValueData->size = sks->u.missingValueData->len;
125                 sks->u.missingValueData->buf = (unsigned char*)
126                                           odr_strdup(out, sort_flags+i);
127                 i += strlen(sort_flags+i) - 1;
128                 break;
129             }
130         }
131     }
132     if (!sksl->num_specs)
133         return 0;
134     return sksl;
135 }
136
137 int yaz_sort_spec_to_cql(Z_SortKeySpecList *sksl, WRBUF w)
138 {
139     int i;
140     for (i = 0; i < sksl->num_specs; i++)
141     {
142         Z_SortKeySpec *sks = sksl->specs[i];
143         Z_SortKey *sk;
144
145         if (sks->sortElement->which != Z_SortElement_generic)
146             return -1;
147
148         sk = sks->sortElement->u.generic;
149         if (i)
150             wrbuf_puts(w, " ");
151         else
152             wrbuf_puts(w, " SORTBY ");
153         if (sk->which == Z_SortKey_sortAttributes)
154             return -1;
155         else if (sk->which == Z_SortKey_sortField)
156             wrbuf_puts(w, sk->u.sortField);
157         switch (*sks->sortRelation)
158         {
159         case Z_SortKeySpec_ascending:
160             wrbuf_puts(w, "/ascending");
161             break;
162         case Z_SortKeySpec_descending:
163             wrbuf_puts(w, "/descending");
164             break;
165         }
166         switch (*sks->caseSensitivity)
167         {
168         case Z_SortKeySpec_caseSensitive:
169             wrbuf_puts(w, "/respectCase");
170             break;
171         case Z_SortKeySpec_caseInsensitive:
172             wrbuf_puts(w, "/ignoreCase");
173             break;
174         }
175         switch (sks->which)
176         {
177         case Z_SortKeySpec_null:
178             break;
179         case Z_SortKeySpec_abort:
180             wrbuf_puts(w, "/missingFail");
181             break;
182         case Z_SortKeySpec_missingValueData:
183             wrbuf_puts(w, "/missingValue=");
184             wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
185                         sks->u.missingValueData->len);
186             break;
187         }
188     }
189     return 0;
190 }
191
192 int yaz_sort_spec_to_type7(Z_SortKeySpecList *sksl, WRBUF pqf)
193 {
194     int i;
195     for (i = 0; i < sksl->num_specs; i++)
196     {
197         Z_SortKeySpec *sks = sksl->specs[i];
198         Z_SortKey *sk;
199
200         if (sks->sortElement->which != Z_SortElement_generic)
201             return -1;
202
203         sk = sks->sortElement->u.generic;
204
205         wrbuf_insert(pqf, 0, "@or ", 4);
206
207         if (sk->which == Z_SortKey_sortAttributes)
208         {
209             int j;
210             for (j = 0; j < sk->u.sortAttributes->list->num_attributes; j++)
211             {
212                 Z_AttributeElement *el =
213                     sk->u.sortAttributes->list->attributes[j];
214                 if (el->which != Z_AttributeValue_numeric)
215                     return -1;
216                 wrbuf_printf(pqf, " @attr " ODR_INT_PRINTF "=" ODR_INT_PRINTF,
217                              *el->attributeType, *el->value.numeric);
218             }
219         }
220         else if (sk->which == Z_SortKey_sortField)
221         {
222             wrbuf_puts(pqf, " @attr 1=");
223             wrbuf_puts(pqf, sk->u.sortField);
224         }
225         switch (*sks->sortRelation)
226         {
227         case Z_SortKeySpec_ascending:
228             wrbuf_puts(pqf, " @attr 7=1 ");
229             break;
230         case Z_SortKeySpec_descending:
231             wrbuf_puts(pqf, " @attr 7=2 ");
232             break;
233         }
234         wrbuf_printf(pqf, "%d", i);
235     }
236     return 0;
237 }
238
239 int yaz_sort_spec_to_srw_sortkeys(Z_SortKeySpecList *sksl, WRBUF w)
240 {
241     int i;
242     for (i = 0; i < sksl->num_specs; i++)
243     {
244         Z_SortKeySpec *sks = sksl->specs[i];
245         Z_SortKey *sk;
246
247         if (sks->sortElement->which != Z_SortElement_generic)
248             return -1;
249
250         sk = sks->sortElement->u.generic;
251
252         if (i)
253             wrbuf_puts(w, " ");
254
255         if (sk->which == Z_SortKey_sortAttributes)
256             return -1;
257         else if (sk->which == Z_SortKey_sortField)
258         {
259             wrbuf_puts(w, sk->u.sortField);
260         }
261         wrbuf_puts(w, ",,"); /* path is absent */
262         switch (*sks->sortRelation)
263         {
264         case Z_SortKeySpec_ascending:
265             wrbuf_puts(w, "1");
266             break;
267         case Z_SortKeySpec_descending:
268             wrbuf_puts(w, "0");
269             break;
270         }
271         wrbuf_puts(w, ",");
272         switch (*sks->caseSensitivity)
273         {
274         case Z_SortKeySpec_caseSensitive:
275             wrbuf_puts(w, "1");
276             break;
277         case Z_SortKeySpec_caseInsensitive:
278             wrbuf_puts(w, "0");
279             break;
280         }
281         wrbuf_puts(w, ",");
282         switch (sks->which)
283         {
284         case Z_SortKeySpec_null:
285             wrbuf_puts(w, "highValue");
286             break;
287         case Z_SortKeySpec_abort:
288             wrbuf_puts(w, "abort");
289             break;
290         case Z_SortKeySpec_missingValueData:
291             wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
292                         sks->u.missingValueData->len);
293             break;
294         }
295     }
296     return 0;
297 }
298
299 int yaz_sort_spec_to_solr_sortkeys(Z_SortKeySpecList *sksl, WRBUF w)
300 {
301     int i;
302     for (i = 0; i < sksl->num_specs; i++)
303     {
304         Z_SortKeySpec *sks = sksl->specs[i];
305         Z_SortKey *sk;
306
307         if (sks->sortElement->which != Z_SortElement_generic)
308             return -1;
309
310         sk = sks->sortElement->u.generic;
311
312         if (i)
313             wrbuf_puts(w, ",");
314
315         if (sk->which == Z_SortKey_sortAttributes)
316             return -1;
317         else if (sk->which == Z_SortKey_sortField)
318         {
319             wrbuf_puts(w, sk->u.sortField);
320         }
321         switch (*sks->sortRelation)
322         {
323         case Z_SortKeySpec_ascending:
324             wrbuf_puts(w, " asc");
325             break;
326         case Z_SortKeySpec_descending:
327             wrbuf_puts(w, " desc");
328             break;
329         }
330     }
331     return 0;
332 }
333
334
335 int yaz_srw_sortkeys_to_sort_spec(const char *srw_sortkeys, WRBUF w)
336 {
337     /* sru sortkey layout: path,schema,ascending,caseSensitive,missingValue */
338     /* see cql_sortby_to_sortkeys of YAZ. */
339     char **sortspec;
340     int num_sortspec = 0;
341     int i;
342     NMEM nmem = nmem_create();
343
344     if (srw_sortkeys)
345         nmem_strsplit_blank(nmem, srw_sortkeys, &sortspec, &num_sortspec);
346     for (i = 0; i < num_sortspec; i++)
347     {
348         char **arg;
349         int num_arg;
350         int ascending = 1;
351         int case_sensitive = 0;
352         const char *missing = 0;
353         nmem_strsplitx(nmem, ",", sortspec[i], &arg, &num_arg, 0);
354
355         if (num_arg > 2 && arg[2][0])
356             ascending = atoi(arg[2]);
357         if (num_arg > 3 && arg[3][0])
358             case_sensitive = atoi(arg[3]);
359         if (num_arg > 4 && arg[4][0])
360             missing = arg[4];
361
362         if (i)
363             wrbuf_puts(w, " ");
364
365         wrbuf_puts(w, arg[0]); /* field */
366         wrbuf_puts(w, " ");
367
368         wrbuf_puts(w, ascending ? "a" : "d");
369         wrbuf_puts(w, case_sensitive ? "s" : "i");
370         if (missing)
371         {
372             if (!strcmp(missing, "omit")) {
373                 ;
374             }
375             else if (!strcmp(missing, "abort"))
376                 wrbuf_puts(w, "!");
377             else if (!strcmp(missing, "lowValue")) {
378                 ;
379             }
380             else if (!strcmp(missing, "highValue")) {
381                 ;
382             }
383             else
384             {
385                 wrbuf_puts(w, "=");
386                 wrbuf_puts(w, missing);
387             }
388         }
389     }
390     nmem_destroy(nmem);
391     return 0;
392 }
393
394 int yaz_solr_sortkeys_to_sort_spec(const char *solr_sortkeys, WRBUF w)
395 {
396     /* Solr sortkey layout: field order[, field order] */
397     /* see cql_sortby_to_sortkeys of YAZ. */
398     char **sortspec;
399     int num_sortspec = 0;
400     int i;
401     NMEM nmem = nmem_create();
402
403     if (solr_sortkeys)
404         nmem_strsplit(nmem, ",", solr_sortkeys, &sortspec, &num_sortspec);
405     for (i = 0; i < num_sortspec; i++)
406     {
407         char **arg;
408         int num_arg;
409         char order = 'a';
410         int case_sensitive = 0;
411         nmem_strsplitx(nmem, " ", sortspec[i], &arg, &num_arg, 0);
412
413         if (num_arg != 2)
414             return -1;
415
416         if (!yaz_matchstr(arg[1], "asc"))
417                 order = 'a';
418         else if (!yaz_matchstr(arg[1], "desc"))
419             order = 'd';
420         else
421             return -1;
422
423         if (i)
424             wrbuf_puts(w, " ");
425
426         wrbuf_puts(w, arg[0]); /* field */
427         wrbuf_puts(w, " ");
428
429         wrbuf_putc(w, order);
430         // Always in-sensitive
431         wrbuf_puts(w, case_sensitive ? "s" : "i");
432     }
433     nmem_destroy(nmem);
434     return 0;
435 }
436
437
438 /*
439  * Local variables:
440  * c-basic-offset: 4
441  * c-file-style: "Stroustrup"
442  * indent-tabs-mode: nil
443  * End:
444  * vim: shiftwidth=4 tabstop=8 expandtab
445  */
446