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