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