Remove shlibs:Depends from yaz
[yaz-moved-to-github.git] / zutil / srw.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.14 2003-04-24 13:05:04 adam Exp $
6  */
7
8 #include <yaz/srw.h>
9
10 #if HAVE_XML2
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
13
14 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
15 {
16     if (val)
17     {
18         xmlDocPtr doc = xmlParseMemory(val,len);
19         if (doc)
20         {
21             xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
22             xmlNodePtr t = xmlDocGetRootElement(doc);
23             xmlAddChild(c, xmlCopyNode(t,1));
24             xmlFreeDoc(doc);
25         }
26     }
27 }
28
29 static void add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
30                              int len)
31 {
32     if (val)
33     {
34         xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
35         xmlNodePtr t = xmlNewTextLen(val, len);
36         xmlAddChild(c, t);
37     }
38 }
39
40 static void add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
41 {
42     if (val)
43         xmlNewChild(ptr, 0, elem, val);
44 }
45
46 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
47 {
48     if (val)
49     {
50         char str[30];
51         sprintf(str, "%d", *val);
52         xmlNewChild(ptr, 0, elem, str);
53     }
54 }
55
56 static int match_element(xmlNodePtr ptr, const char *elem)
57 {
58     if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
59         return 1;
60     return 0;
61 }
62
63 #define CHECK_TYPE 0
64
65 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
66                               char **val, int *len)
67 {
68 #if CHECK_TYPE
69     struct _xmlAttr *attr;
70 #endif
71     if (!match_element(ptr, elem))
72         return 0;
73 #if CHECK_TYPE
74     for (attr = ptr->properties; attr; attr = attr->next)
75         if (!strcmp(attr->name, "type") &&
76             attr->children && attr->children->type == XML_TEXT_NODE)
77         {
78             const char *t = strchr(attr->children->content, ':');
79             if (t)
80                 t = t + 1;
81             else
82                 t = attr->children->content;
83             if (!strcmp(t, "string"))
84                 break;
85         }
86     if (!attr)
87         return 0;
88 #endif
89     ptr = ptr->children;
90     if (!ptr || ptr->type != XML_TEXT_NODE)
91         return 0;
92     *val = odr_strdup(o, ptr->content);
93     if (len)
94         *len = strlen(ptr->content);
95     return 1;
96 }
97
98
99 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
100                             char **val)
101 {
102     return match_xsd_string_n(ptr, elem, o, val, 0);
103 }
104
105 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
106                            char **val, int *len)
107 {
108     xmlBufferPtr buf;
109
110     if (!match_element(ptr, elem))
111         return 0;
112     printf ("match_xsd_XML_n: %s\n", elem);
113     ptr = ptr->children;
114     if (!ptr)
115     {
116         printf ("match_xsd_XML: no TEXT node\n");
117         return 0;
118     }
119     buf = xmlBufferCreate();
120
121     xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
122
123     *val = odr_malloc(o, buf->use+1);
124     memcpy (*val, buf->content, buf->use);
125     (*val)[buf->use] = '\0';
126
127     if (len)
128         *len = buf->use;
129
130     xmlBufferFree(buf);
131
132     printf ("match_XML_string: OK content=%s\n",  *val);
133     return 1;
134 }
135
136                      
137 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
138 {
139 #if CHECK_TYPE
140     struct _xmlAttr *attr;
141 #endif
142     if (!match_element(ptr, elem))
143         return 0;
144 #if CHECK_TYPE
145     for (attr = ptr->properties; attr; attr = attr->next)
146         if (!strcmp(attr->name, "type") &&
147             attr->children && attr->children->type == XML_TEXT_NODE)
148         {
149             const char *t = strchr(attr->children->content, ':');
150             if (t)
151                 t = t + 1;
152             else
153                 t = attr->children->content;
154             if (!strcmp(t, "integer"))
155                 break;
156         }
157     if (!attr)
158         return 0;
159 #endif
160     ptr = ptr->children;
161     if (!ptr || ptr->type != XML_TEXT_NODE)
162         return 0;
163     *val = odr_intdup(o, atoi(ptr->content));
164     return 1;
165 }
166
167 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
168                            int *num, void *client_data, const char *ns)
169 {
170     if (o->direction == ODR_DECODE)
171     {
172         int i;
173         xmlNodePtr ptr;
174         *num = 0;
175         for (ptr = pptr->children; ptr; ptr = ptr->next)
176         {
177             if (ptr->type == XML_ELEMENT_NODE &&
178                 !strcmp(ptr->name, "record"))
179                 (*num)++;
180         }
181         if (!*num)
182             return 1;
183         *recs = odr_malloc(o, *num * sizeof(**recs));
184         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
185         {
186             if (ptr->type == XML_ELEMENT_NODE &&
187                 !strcmp(ptr->name, "record"))
188             {
189                 xmlNodePtr rptr;
190                 (*recs)[i].recordSchema = 0;
191                 (*recs)[i].recordPacking = Z_SRW_recordPacking_string;
192                 (*recs)[i].recordData_buf = 0;
193                 (*recs)[i].recordData_len = 0;
194                 (*recs)[i].recordPosition = 0;
195                 for (rptr = ptr->children; rptr; rptr = rptr->next)
196                 {
197                     if (match_xsd_string(rptr, "recordSchema", o, 
198                                          &(*recs)[i].recordSchema))
199                         ;
200                     else if (match_xsd_string_n(rptr, "recordData", o, 
201                                                 &(*recs)[i].recordData_buf,
202                                                 &(*recs)[i].recordData_len))
203                         ;
204                     else if (match_xsd_XML_n(rptr, "recordXML", o, 
205                                              &(*recs)[i].recordData_buf,
206                                              &(*recs)[i].recordData_len))
207                         (*recs)[i].recordPacking = Z_SRW_recordPacking_XML;
208                     else if (match_xsd_integer(rptr, "recordPosition", o, 
209                                                &(*recs)[i].recordPosition))
210                         ;
211                 }
212             }
213         }
214     }
215     else if (o->direction == ODR_ENCODE)
216     {
217         int i;
218         for (i = 0; i < *num; i++)
219         {
220             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
221             add_xsd_string(rptr, "recordSchema", (*recs)[i].recordSchema);
222             switch((*recs)[i].recordPacking)
223             {
224             case Z_SRW_recordPacking_string:
225                 add_xsd_string_n(rptr, "recordData", (*recs)[i].recordData_buf,
226                                  (*recs)[i].recordData_len);
227                 break;
228             case Z_SRW_recordPacking_XML:
229                 add_XML_n(rptr, "recordXML", (*recs)[i].recordData_buf,
230                           (*recs)[i].recordData_len);
231                 break;
232             }
233             add_xsd_integer(rptr, "recordPosition", (*recs)[i].recordPosition);
234         }
235     }
236     return 0;
237 }
238
239 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
240                                int *num, void *client_data, const char *ns)
241 {
242     if (o->direction == ODR_DECODE)
243     {
244         int i;
245         xmlNodePtr ptr;
246         *num = 0;
247         for (ptr = pptr->children; ptr; ptr = ptr->next)
248         {
249             if (ptr->type == XML_ELEMENT_NODE &&
250                 !strcmp(ptr->name, "diagnostic"))
251                 (*num)++;
252         }
253         if (!*num)
254             return 1;
255         *recs = odr_malloc(o, *num * sizeof(**recs));
256         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
257         {
258             if (ptr->type == XML_ELEMENT_NODE &&
259                 !strcmp(ptr->name, "diagnostic"))
260             {
261                 xmlNodePtr rptr;
262                 (*recs)[i].code = 0;
263                 (*recs)[i].details = 0;
264                 for (rptr = ptr->children; rptr; rptr = rptr->next)
265                 {
266                     if (match_xsd_integer(rptr, "code", o, 
267                                                &(*recs)[i].code))
268                         ;
269                     else if (match_xsd_string(rptr, "details", o, 
270                                               &(*recs)[i].details))
271                         ;
272                 }
273                 i++;
274             }
275         }
276     }
277     else if (o->direction == ODR_ENCODE)
278     {
279         int i;
280         for (i = 0; i < *num; i++)
281         {
282             xmlNodePtr rptr = xmlNewChild(pptr, 0, "diagnostic", 0);
283             add_xsd_integer(rptr, "code", (*recs)[i].code);
284             add_xsd_string(rptr, "details", (*recs)[i].details);
285         }
286     }
287     return 0;
288 }
289
290
291 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
292                   void *client_data, const char *ns)
293 {
294     xmlNodePtr pptr = vptr;
295     if (o->direction == ODR_DECODE)
296     {
297         xmlNodePtr method = pptr->children;
298
299         while (method && method->type == XML_TEXT_NODE)
300             method = method->next;
301         
302         if (!method || method->type != XML_ELEMENT_NODE)
303             return -1;
304         if (!strcmp(method->name, "searchRetrieveRequest"))
305         {
306             Z_SRW_PDU **p = handler_data;
307             xmlNodePtr ptr = method->children;
308             Z_SRW_searchRetrieveRequest *req;
309
310             *p = odr_malloc(o, sizeof(**p));
311             (*p)->which = Z_SRW_searchRetrieve_request;
312             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
313             req->query_type = Z_SRW_query_type_cql;
314             req->query.cql = 0;
315             req->sort_type = Z_SRW_sort_type_none;
316             req->sort.none = 0;
317             req->startRecord = 0;
318             req->maximumRecords = 0;
319             req->recordSchema = 0;
320             req->recordPacking = 0;
321             req->database = 0;
322
323             for (; ptr; ptr = ptr->next)
324             {
325                 if (match_xsd_string(ptr, "query", o, 
326                                      &req->query.cql))
327                     req->query_type = Z_SRW_query_type_cql;
328                 else if (match_xsd_string(ptr, "pQuery", o, 
329                                      &req->query.pqf))
330                     req->query_type = Z_SRW_query_type_pqf;
331                 else if (match_xsd_string(ptr, "xQuery", o, 
332                                      &req->query.xcql))
333                     req->query_type = Z_SRW_query_type_xcql;
334                 else if (match_xsd_string(ptr, "sortKeys", o, 
335                                           &req->sort.sortKeys))
336                     req->sort_type = Z_SRW_sort_type_sort;
337                 else if (match_xsd_string(ptr, "recordSchema", o, 
338                                           &req->recordSchema))
339                     ;
340                 else if (match_xsd_string(ptr, "recordPacking", o,
341                                           &req->recordPacking))
342                     ;
343                 else if (match_xsd_integer(ptr, "startRecord", o,
344                                            &req->startRecord))
345                     ;
346                 else if (match_xsd_integer(ptr, "maximumRecords", o,
347                                            &req->maximumRecords))
348                     ;
349                 else if (match_xsd_string(ptr, "database", o,
350                                            &req->database))
351                     ;
352                 /* missing is xQuery, xSortKeys .. */
353             }
354         }
355         else if (!strcmp(method->name, "searchRetrieveResponse"))
356         {
357             Z_SRW_PDU **p = handler_data;
358             xmlNodePtr ptr = method->children;
359             Z_SRW_searchRetrieveResponse *res;
360
361             *p = odr_malloc(o, sizeof(**p));
362             (*p)->which = Z_SRW_searchRetrieve_response;
363             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
364
365             res->numberOfRecords = 0;
366             res->resultSetId = 0;
367             res->resultSetIdleTime = 0;
368             res->records = 0;
369             res->num_records = 0;
370             res->diagnostics = 0;
371             res->num_diagnostics = 0;
372             res->nextRecordPosition = 0;
373
374             for (; ptr; ptr = ptr->next)
375             {
376                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
377                                       &res->numberOfRecords))
378                     ;
379                 else if (match_xsd_string(ptr, "resultSetId", o, 
380                                           &res->resultSetId))
381                     ;
382                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
383                                            &res->resultSetIdleTime))
384                     ;
385                 else if (match_element(ptr, "records"))
386                     yaz_srw_records(o, ptr, &res->records,
387                                     &res->num_records, client_data,
388                                     ns);
389                 else if (match_element(ptr, "diagnostics"))
390                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
391                                         &res->num_diagnostics,
392                                         client_data, ns);
393                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
394                                            &res->nextRecordPosition))
395                     ;
396             }
397         }
398         else if (!strcmp(method->name, "explainRequest"))
399         {
400             Z_SRW_PDU **p = handler_data;
401             Z_SRW_explainRequest *req;
402             
403             *p = odr_malloc(o, sizeof(**p));
404             (*p)->which = Z_SRW_explain_request;
405             req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
406             req->dummy = 0;
407         }
408         else if (!strcmp(method->name, "explainResponse"))
409         {
410             Z_SRW_PDU **p = handler_data;
411             Z_SRW_explainResponse *res;
412             xmlNodePtr ptr = method->children;
413
414             *p = odr_malloc(o, sizeof(**p));
415             (*p)->which = Z_SRW_explain_response;
416             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
417             res->explainData_buf = 0;
418             res->explainData_len = 0;
419             res->explainPacking = Z_SRW_recordPacking_string;
420             for (; ptr; ptr = ptr->next)
421             {
422                 match_xsd_string_n(ptr, "Explain", o, 
423                                    &res->explainData_buf,
424                                    &res->explainData_len);
425             }
426         }
427         else
428             return -1;
429
430     }
431     else if (o->direction == ODR_ENCODE)
432     {
433         Z_SRW_PDU **p = handler_data;
434         if ((*p)->which == Z_SRW_searchRetrieve_request)
435         {
436             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
437             xmlNodePtr ptr = xmlNewChild(pptr, 0,
438                                          "searchRetrieveRequest", 0);
439             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
440
441             xmlSetNs(ptr, ns_srw);
442
443             switch(req->query_type)
444             {
445             case Z_SRW_query_type_cql:
446                 add_xsd_string(ptr, "query", req->query.cql);
447                 break;
448             case Z_SRW_query_type_xcql:
449                 add_xsd_string(ptr, "xQuery", req->query.xcql);
450                 break;
451             case Z_SRW_query_type_pqf:
452                 add_xsd_string(ptr, "pQuery", req->query.pqf);
453                 break;
454             }
455             switch(req->sort_type)
456             {
457             case Z_SRW_sort_type_none:
458                 break;
459             case Z_SRW_sort_type_sort:
460                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
461                 break;
462             case Z_SRW_sort_type_xSort:
463                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
464                 break;
465             }
466             add_xsd_integer(ptr, "startRecord", req->startRecord);
467             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
468             add_xsd_string(ptr, "recordSchema", req->recordSchema);
469             add_xsd_string(ptr, "recordPacking", req->recordPacking);
470             add_xsd_string(ptr, "database", req->database);
471         }
472         else if ((*p)->which == Z_SRW_searchRetrieve_response)
473         {
474             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
475             xmlNodePtr ptr = xmlNewChild(pptr, 0,
476                                          "searchRetrieveResponse", 0);
477             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
478
479             xmlSetNs(ptr, ns_srw);
480             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
481             add_xsd_string(ptr, "resultSetId", res->resultSetId);
482             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
483             if (res->num_records)
484             {
485                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
486                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
487                                 client_data, ns);
488             }
489             if (res->num_diagnostics)
490             {
491                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
492                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
493                                     &res->num_diagnostics, client_data, ns);
494             }
495             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
496         }
497         else if ((*p)->which == Z_SRW_explain_request)
498         {
499             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
500             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
501
502             xmlSetNs(ptr, ns_srw);
503         }
504         else if ((*p)->which == Z_SRW_explain_response)
505         {
506             Z_SRW_explainResponse *res = (*p)->u.explain_response;
507             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
508             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
509
510             xmlSetNs(ptr, ns_srw);
511
512             add_xsd_string_n(ptr, "Explain", res->explainData_buf,
513                              res->explainData_len);
514         }
515         else
516             return -1;
517
518     }
519     return 0;
520 }
521
522 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
523 {
524     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
525     sr->which = which;
526     switch(which)
527     {
528     case Z_SRW_searchRetrieve_request:
529         sr->u.request = (Z_SRW_searchRetrieveRequest *)
530             odr_malloc(o, sizeof(*sr->u.request));
531         sr->u.request->query_type = Z_SRW_query_type_cql;
532         sr->u.request->query.cql = 0;
533         sr->u.request->sort_type = Z_SRW_sort_type_none;
534         sr->u.request->sort.none = 0;
535         sr->u.request->startRecord = 0;
536         sr->u.request->maximumRecords = 0;
537         sr->u.request->recordSchema = 0;
538         sr->u.request->recordPacking = 0;
539         sr->u.request->database = 0;
540         break;
541     case Z_SRW_searchRetrieve_response:
542         sr->u.response = (Z_SRW_searchRetrieveResponse *)
543             odr_malloc(o, sizeof(*sr->u.response));
544         sr->u.response->numberOfRecords = 0;
545         sr->u.response->resultSetId = 0;
546         sr->u.response->resultSetIdleTime = 0;
547         sr->u.response->records = 0;
548         sr->u.response->num_records = 0;
549         sr->u.response->diagnostics = 0;
550         sr->u.response->num_diagnostics = 0;
551         sr->u.response->nextRecordPosition = 0;
552         break;
553     case Z_SRW_explain_request:
554         sr->u.explain_request = (Z_SRW_explainRequest *)
555             odr_malloc(o, sizeof(*sr->u.explain_request));
556         sr->u.explain_request->dummy = 0;
557         break;
558     case Z_SRW_explain_response:
559         sr->u.explain_response = (Z_SRW_explainResponse *)
560             odr_malloc(o, sizeof(*sr->u.explain_response));
561         sr->u.explain_response->explainPacking = 0; 
562         sr->u.explain_response->explainData_buf = 0;
563         sr->u.explain_response->explainData_len = 0;
564     }
565     return sr;
566 }
567
568 #endif
569
570
571 static struct {
572     int code;
573     const char *msg;
574 } yaz_srw_codes [] = {
575 {1, "Permanent system error"}, 
576 {2, "System temporarily unavailable"}, 
577 {3, "Authentication error"}, 
578 /* Diagnostics Relating to CQL */
579 {10, "Illegal query"}, 
580 {11, "Unsupported query type (XCQL vs CQL)"}, 
581 {12, "Too many characters in query"}, 
582 {13, "Unbalanced or illegal use of parentheses"}, 
583 {14, "Unbalanced or illegal use of quotes"}, 
584 {15, "Illegal or unsupported index set"}, 
585 {16, "Illegal or unsupported index"}, 
586 {17, "Illegal or unsupported combination of index and index set"}, 
587 {18, "Illegal or unsupported combination of indexes"}, 
588 {19, "Illegal or unsupported relation"}, 
589 {20, "Illegal or unsupported relation modifier"}, 
590 {21, "Illegal or unsupported combination of relation modifers"}, 
591 {22, "Illegal or unsupported combination of relation and index"}, 
592 {23, "Too many characters in term"}, 
593 {24, "Illegal combination of relation and term"}, 
594 {25, "Special characters not quoted in term"}, 
595 {26, "Non special character escaped in term"}, 
596 {27, "Empty term unsupported"}, 
597 {28, "Masking character not supported"}, 
598 {29, "Masked words too short"}, 
599 {30, "Too many masking characters in term"}, 
600 {31, "Anchoring character not supported"}, 
601 {32, "Anchoring character in illegal or unsupported position"}, 
602 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
603 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
604 {35, "Terms only exclusion (stop) words"}, 
605 {36, "Term in invalid format for index or relation"}, 
606 {37, "Illegal or unsupported boolean operator"}, 
607 {38, "Too many boolean operators in query"}, 
608 {39, "Proximity not supported"}, 
609 {40, "Illegal or unsupported proximity relation"}, 
610 {41, "Illegal or unsupported proximity distance"}, 
611 {42, "Illegal or unsupported proximity unit"}, 
612 {43, "Illegal or unsupported proximity ordering"}, 
613 {44, "Illegal or unsupported combination of proximity modifiers"}, 
614 {45, "Index set name (prefix) assigned to multiple identifiers"}, 
615 /* Diagnostics Relating to Result Sets */
616 {50, "Result sets not supported"}, 
617 {51, "Result set does not exist"}, 
618 {52, "Result set temporarily unavailable"}, 
619 {53, "Result sets only supported for retrieval"}, 
620 {54, "Retrieval may only occur from an existing result set"}, 
621 {55, "Combination of result sets with search terms not supported"}, 
622 {56, "Only combination of single result set with search terms supported"}, 
623 {57, "Result set created but no records available"}, 
624 {58, "Result set created with unpredictable partial results available"}, 
625 {59, "Result set created with valid partial results available"}, 
626 /* Diagnostics Relating to Records */
627 {60, "Too many records retrieved"}, 
628 {61, "First record position out of range"}, 
629 {62, "Negative number of records requested"}, 
630 {63, "System error in retrieving records"}, 
631 {64, "Record temporarily unavailable"}, 
632 {65, "Record does not exist"}, 
633 {66, "Unknown schema for retrieval"}, 
634 {67, "Record not available in this schema"}, 
635 {68, "Not authorised to send record"}, 
636 {69, "Not authorised to send record in this schema"}, 
637 {70, "Record too large to send"}, 
638 /* Diagnostics Relating to Sorting */
639 {80, "Sort not supported"}, 
640 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
641 {82, "Illegal or unsupported sort sequence"}, 
642 {83, "Too many records"}, 
643 {84, "Too many sort keys"}, 
644 {85, "Duplicate sort keys"}, 
645 {86, "Incompatible record formats"}, 
646 {87, "Unsupported schema for sort"}, 
647 {88, "Unsupported tag path for sort"}, 
648 {89, "Tag path illegal or unsupported for schema"}, 
649 {90, "Illegal or unsupported direction value"}, 
650 {91, "Illegal or unsupported case value"}, 
651 {92, "Illegal or unsupported missing value action"}, 
652 /* Diagnostics Relating to Explain */
653 {100, "Explain not supported"}, 
654 {101, "Explain request type not supported (SOAP vs GET)"}, 
655 {102, "Explain record temporarily unavailable"},
656 {0, 0}
657 };
658
659 const char *yaz_diag_srw_str (int code)
660 {
661     int i;
662     for (i = 0; yaz_srw_codes[i].code; i++)
663         if (yaz_srw_codes[i].code == code)
664             return yaz_srw_codes[i].msg;
665     return 0;
666 }
667
668
669 /* bib1:srw */
670 static int srw_bib1_map[] = {
671     1, 1,
672     2, 2,
673     3, 11,
674     4, 35,
675     5, 12,
676     6, 38,
677     7, 30,
678     8, 32,
679     9, 29,
680     10, 10,
681     11, 12,
682     11, 23,
683     12, 60,
684     13, 61,
685     13, 62,
686     14, 63,
687     14, 64,
688     14, 65,
689     15, 68,
690     15, 69,
691     16, 70,
692     17, 70,
693     18, 50,
694     19, 55,
695     20, 56, 
696     21, 52,
697     22, 50,
698     23, 1,  /* bad map */
699     24, 63, /* bad map */
700     25, 63, /* bad map */
701     26, 63, /* bad map */
702     27, 51,
703     28, 52,
704     29, 52,
705     30, 51,
706     31, 57,
707     32, 58,
708     33, 59,
709     100, 1, /* bad map */
710     101, 3,
711     102, 3,
712     103, 3,
713     104, 3,
714     105, 3, 
715     106, 66,
716     107, 11,
717     108, 10,
718     108, 13,
719     108, 14,
720     108, 25,
721     108, 26,
722     108, 27,
723     108, 45,
724         
725     109, 1,
726     110, 37,
727     111, 1,
728     112, 58,
729     113, 10,
730     114, 16,
731     115, 16,
732     116, 16,
733     117, 19,
734     118, 22,
735     119, 32,
736     119, 31,
737     120, 28,
738     121, 15,
739     122, 32,
740     123, 22,
741     123, 17,
742     123, 18,
743     124, 24,
744     125, 36,
745     126, 36, 
746     127, 36,
747     128, 51,
748     129, 39,
749     130, 43,
750     131, 40,
751     132, 42,
752     201, 44,
753     201, 33,
754     201, 34,
755     202, 41,
756     203, 43,
757     205, 1,  /* bad map */
758     206, 1,  /* bad map */
759     207, 89,
760     208, 1,  /* bad map */
761     209, 80,
762     210, 80,
763     210, 81,
764     211, 84,
765     212, 85,
766     213, 92,
767     214, 90,
768     215, 91,
769     216, 92,
770     217, 63,
771     218, 1,  /* bad map */
772     219, 1,  /* bad map */
773     220, 1,  /* bad map */
774     221, 1,  /* bad map */
775     222, 1,  /* bad map */
776     223, 1,  /* bad map */
777     224, 1,  /* bad map */
778     225, 1,  /* bad map */
779     226, 1,  /* bad map */
780     227, 66,
781     228, 1,  /* bad map */
782     229, 36,
783     230, 83,
784     231, 89,
785     232, 1,
786     233, 1, /* bad map */
787     234, 1, /* bad map */
788     235, 2,
789     236, 3, 
790     237, 82,
791     238, 67,
792     239, 66,
793     240, 1, /* bad map */
794     241, 1, /* bad map */
795     242, 70,
796     243, 1, /* bad map */
797     244, 66,
798     245, 10,
799     246, 10,
800     247, 10,
801     1001, 1, /* bad map */
802     1002, 1, /* bad map */
803     1003, 1, /* bad map */
804     1004, 1, /* bad map */
805     1005, 1, /* bad map */
806     1006, 1, /* bad map */
807     1007, 100,
808     1008, 1, 
809     1009, 1,
810     1010, 3,
811     1011, 3,
812     1012, 3,
813     1013, 3,
814     1014, 3,
815     1015, 3,
816     1015, 3,
817     1016, 3,
818     1017, 3,
819     1018, 2,
820     1019, 2,
821     1020, 2,
822     1021, 3,
823     1022, 3,
824     1023, 3,
825     1024, 16,
826     1025, 3,
827     1026, 64,
828     1027, 1,
829     1028, 65,
830     1029, 1,
831     1040, 1,
832     /* 1041-1065 */
833     1066, 66,
834     1066, 67,
835     0
836 };
837
838 int yaz_diag_bib1_to_srw (int code)
839 {
840     const int *p = srw_bib1_map;
841     while (*p)
842     {
843         if (code == p[0])
844             return p[1];
845         p += 2;
846     }
847     return 1;
848 }
849
850 int yaz_diag_srw_to_bib1(int code)
851 {
852     const int *p = srw_bib1_map;
853     while (*p)
854     {
855         if (code == p[1])
856             return p[0];
857         p += 2;
858     }
859     return 1;
860 }