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