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
yaz_sort_spec(ODR out,const char * arg)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
yaz_sort_spec_to_cql(Z_SortKeySpecList * sksl,WRBUF w)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
yaz_sort_spec_to_type7(Z_SortKeySpecList * sksl,WRBUF pqf)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
yaz_sort_spec_to_srw_sortkeys(Z_SortKeySpecList * sksl,WRBUF w)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
yaz_sort_spec_to_solr_sortkeys(Z_SortKeySpecList * sksl,WRBUF w)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
yaz_srw_sortkeys_to_sort_spec(const char * srw_sortkeys,WRBUF w)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
yaz_solr_sortkeys_to_sort_spec(const char * solr_sortkeys,WRBUF w)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
445