Reformat
[yaz-moved-to-github.git] / src / sortspec.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2011 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
17 #include <yaz/z-core.h>
18 #include <yaz/sortspec.h>
19 #include <yaz/oid_db.h>
20 #include <yaz/wrbuf.h>
21
22 Z_SortKeySpecList *yaz_sort_spec(ODR out, const char *arg)
23 {
24     char sort_string_buf[64], sort_flags[64];
25     Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
26         odr_malloc(out, sizeof(*sksl));
27     int off;
28     
29     sksl->num_specs = 0;
30     sksl->specs = (Z_SortKeySpec **)odr_malloc(out, sizeof(sksl->specs) * 20);
31     
32     while ((sscanf(arg, "%63s %63s%n", sort_string_buf,
33                    sort_flags, &off)) == 2  && off > 1)
34     {
35         int i;
36         char *sort_string_sep;
37         char *sort_string = sort_string_buf;
38         Z_SortKeySpec *sks = (Z_SortKeySpec *) odr_malloc(out, sizeof(*sks));
39         Z_SortKey *sk = (Z_SortKey *) odr_malloc(out, sizeof(*sk));
40         
41         arg += off;
42         sksl->specs[sksl->num_specs++] = sks;
43         sks->sortElement = (Z_SortElement *)
44             odr_malloc(out, sizeof(*sks->sortElement));
45         sks->sortElement->which = Z_SortElement_generic;
46         sks->sortElement->u.generic = sk;
47         
48         if ((sort_string_sep = strchr(sort_string, '=')))
49         {
50             int i = 0;
51             sk->which = Z_SortKey_sortAttributes;
52             sk->u.sortAttributes = (Z_SortAttributes *)
53                 odr_malloc(out, sizeof(*sk->u.sortAttributes));
54             sk->u.sortAttributes->id = odr_oiddup(out, yaz_oid_attset_bib_1);
55             sk->u.sortAttributes->list = (Z_AttributeList *)
56                 odr_malloc(out, sizeof(*sk->u.sortAttributes->list));
57             sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
58                 odr_malloc(out, 10 * 
59                             sizeof(*sk->u.sortAttributes->list->attributes));
60             while (i < 10 && sort_string && sort_string_sep)
61             {
62                 Z_AttributeElement *el = (Z_AttributeElement *)
63                     odr_malloc(out, sizeof(*el));
64                 sk->u.sortAttributes->list->attributes[i] = el;
65                 el->attributeSet = 0;
66                 el->attributeType = odr_intdup(out, atoi(sort_string));
67                 el->which = Z_AttributeValue_numeric;
68                 el->value.numeric =
69                     odr_intdup(out, odr_atoi(sort_string_sep + 1));
70                 i++;
71                 sort_string = strchr(sort_string, ',');
72                 if (sort_string)
73                 {
74                     sort_string++;
75                     sort_string_sep = strchr(sort_string, '=');
76                 }
77             }
78             sk->u.sortAttributes->list->num_attributes = i;
79         }
80         else
81         {
82             sk->which = Z_SortKey_sortField;
83             sk->u.sortField = odr_strdup (out, sort_string);
84         }
85         sks->sortRelation = odr_intdup(out, Z_SortKeySpec_ascending);
86         sks->caseSensitivity = odr_intdup(out, Z_SortKeySpec_caseInsensitive);
87
88         sks->which = Z_SortKeySpec_null;
89         sks->u.null = odr_nullval ();
90         
91         for (i = 0; sort_flags[i]; i++)
92         {
93             switch (sort_flags[i])
94             {
95             case 'd':
96             case 'D':
97             case '>':
98                 *sks->sortRelation = Z_SortKeySpec_descending;
99                 break;
100             case 'a':
101             case 'A':
102             case '<':
103                 *sks->sortRelation = Z_SortKeySpec_ascending;
104                 break;
105             case 'i':
106             case 'I':
107                 *sks->caseSensitivity = Z_SortKeySpec_caseInsensitive;
108                 break;
109             case 'S':
110             case 's':
111                 *sks->caseSensitivity = Z_SortKeySpec_caseSensitive;
112                 break;
113             case '!':
114                 sks->which = Z_SortKeySpec_abort;
115                 sks->u.abort = odr_nullval();
116                 break;
117             case '=':
118                 sks->which = Z_SortKeySpec_missingValueData;
119                 sks->u.missingValueData = (Odr_oct*)
120                     odr_malloc(out, sizeof(Odr_oct));
121                 i++;
122                 sks->u.missingValueData->len = strlen(sort_flags+i);
123                 sks->u.missingValueData->size = sks->u.missingValueData->len;
124                 sks->u.missingValueData->buf = (unsigned char*)
125                                           odr_strdup(out, sort_flags+i);
126                 i += strlen(sort_flags+i);
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         }
185     }
186     return 0;
187 }
188
189 int yaz_sort_spec_to_type7(Z_SortKeySpecList *sksl, WRBUF pqf)
190 {
191     int i;
192     for (i = 0; i < sksl->num_specs; i++)
193     {
194         Z_SortKeySpec *sks = sksl->specs[i];
195         Z_SortKey *sk;
196
197         if (sks->sortElement->which != Z_SortElement_generic)
198             return -1;
199
200         sk = sks->sortElement->u.generic;
201
202         wrbuf_insert(pqf, 0, "@or ", 4);
203
204         if (sk->which == Z_SortKey_sortAttributes)
205         {
206             int j;
207             for (j = 0; j < sk->u.sortAttributes->list->num_attributes; j++)
208             {
209                 Z_AttributeElement *el =
210                     sk->u.sortAttributes->list->attributes[j];
211                 if (el->which != Z_AttributeValue_numeric)
212                     return -1;
213                 wrbuf_printf(pqf, " @attr " ODR_INT_PRINTF "=" ODR_INT_PRINTF,
214                              *el->attributeType, *el->value.numeric);
215             }
216         }
217         else if (sk->which == Z_SortKey_sortField)
218         {
219             wrbuf_puts(pqf, " @attr 1=");
220             wrbuf_puts(pqf, sk->u.sortField);
221         }
222         switch (*sks->sortRelation)
223         {
224         case Z_SortKeySpec_ascending:
225             wrbuf_puts(pqf, " @attr 7=1 ");
226             break;
227         case Z_SortKeySpec_descending:
228             wrbuf_puts(pqf, " @attr 7=2 ");
229             break;
230         }
231         wrbuf_printf(pqf, "%d", i);
232     }
233     return 0;
234 }
235
236 int yaz_sort_spec_to_srw_sortkeys(Z_SortKeySpecList *sksl, WRBUF w)
237 {
238     int i;
239     for (i = 0; i < sksl->num_specs; i++)
240     {
241         Z_SortKeySpec *sks = sksl->specs[i];
242         Z_SortKey *sk;
243
244         if (sks->sortElement->which != Z_SortElement_generic)
245             return -1;
246
247         sk = sks->sortElement->u.generic;
248
249         if (i)
250             wrbuf_puts(w, " ");
251
252         if (sk->which == Z_SortKey_sortAttributes)
253             return -1;
254         else if (sk->which == Z_SortKey_sortField)
255         {
256             wrbuf_puts(w, sk->u.sortField);
257         }
258         wrbuf_puts(w, ",,"); /* path is absent */
259         switch (*sks->sortRelation)
260         {
261         case Z_SortKeySpec_ascending:
262             wrbuf_puts(w, "1");
263             break;
264         case Z_SortKeySpec_descending:
265             wrbuf_puts(w, "0");
266             break;
267         }
268         wrbuf_puts(w, ",");
269         switch (*sks->caseSensitivity)
270         {
271         case Z_SortKeySpec_caseSensitive:
272             wrbuf_puts(w, "1");
273             break;
274         case Z_SortKeySpec_caseInsensitive:
275             wrbuf_puts(w, "0");
276             break;
277         }
278         wrbuf_puts(w, ",");
279         switch (sks->which)
280         {
281         case Z_SortKeySpec_null:
282             wrbuf_puts(w, "highValue");
283             break;
284         case Z_SortKeySpec_abort:
285             wrbuf_puts(w, "abort");
286             break;
287         case Z_SortKeySpec_missingValueData:
288             wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
289                         sks->u.missingValueData->len);
290         }
291     }
292     return 0;
293 }
294
295 int yaz_srw_sortkeys_to_sort_spec(const char *srw_sortkeys, WRBUF w)
296 {
297     /* sru sortkey layout: path,schema,ascending,caseSensitive,missingValue */
298     /* see cql_sortby_to_sortkeys of YAZ. */
299     char **sortspec;
300     int num_sortspec = 0;
301     int i;
302     NMEM nmem = nmem_create();
303     
304     if (srw_sortkeys)
305         nmem_strsplit_blank(nmem, srw_sortkeys, &sortspec, &num_sortspec);
306     if (num_sortspec > 0)
307     {
308         for (i = 0; i < num_sortspec; i++)
309         {
310             char **arg;
311             int num_arg;
312             int ascending = 1;
313             int case_sensitive = 0;
314             const char *missing = 0;
315             nmem_strsplitx(nmem, ",", sortspec[i], &arg, &num_arg, 0);
316             
317             if (num_arg > 2 && arg[2][0])
318                 ascending = atoi(arg[2]);
319             if (num_arg > 3 && arg[3][0])
320                 case_sensitive = atoi(arg[3]);
321             if (num_arg > 4 && arg[4][0])
322                 missing = arg[4];
323
324             if (i)
325                 wrbuf_puts(w, " ");
326
327             wrbuf_puts(w, arg[0]); /* field */
328             wrbuf_puts(w, " ");
329
330             wrbuf_puts(w, ascending ? "a" : "d");
331             wrbuf_puts(w, case_sensitive ? "s" : "i");
332             if (missing)
333             {
334                 if (!strcmp(missing, "omit"))
335                     ;
336                 else if (!strcmp(missing, "abort"))
337                     wrbuf_puts(w, "!");
338                 else if (!strcmp(missing, "lowValue"))
339                     ;
340                 else if (!strcmp(missing, "highValue"))
341                     ;
342                 else
343                 {
344                     wrbuf_puts(w, "=");
345                     wrbuf_puts(w, missing);
346                 }
347             }
348         }
349     }
350     nmem_destroy(nmem);
351     return 0;
352 }
353
354 /*
355  * Local variables:
356  * c-basic-offset: 4
357  * c-file-style: "Stroustrup"
358  * indent-tabs-mode: nil
359  * End:
360  * vim: shiftwidth=4 tabstop=8 expandtab
361  */
362