68f79125d312783970767a816d7522911fe70dd4
[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.11 2003-03-23 20:27:16 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
377             *p = odr_malloc(o, sizeof(**p));
378             (*p)->which = Z_SRW_explain_response;
379             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
380             res->explainData_buf = 0;
381             res->explainData_len = 0;
382             res->explainPacking = Z_SRW_recordPacking_string;
383             match_xsd_string_n(method, "explainResponse", o,
384                                &res->explainData_buf, &res->explainData_len);
385         }
386         else
387             return -1;
388
389     }
390     else if (o->direction == ODR_ENCODE)
391     {
392         Z_SRW_PDU **p = handler_data;
393         if ((*p)->which == Z_SRW_searchRetrieve_request)
394         {
395             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
396             xmlNodePtr ptr = xmlNewChild(pptr, 0,
397                                          "searchRetrieveRequest", 0);
398             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
399
400             xmlSetNs(ptr, ns_srw);
401
402             switch(req->query_type)
403             {
404             case Z_SRW_query_type_cql:
405                 add_xsd_string(ptr, "query", req->query.cql);
406                 break;
407             case Z_SRW_query_type_xcql:
408                 add_xsd_string(ptr, "xQuery", req->query.xcql);
409                 break;
410             case Z_SRW_query_type_pqf:
411                 add_xsd_string(ptr, "pQuery", req->query.pqf);
412                 break;
413             }
414             switch(req->sort_type)
415             {
416             case Z_SRW_sort_type_none:
417                 break;
418             case Z_SRW_sort_type_sort:
419                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
420                 break;
421             case Z_SRW_sort_type_xSort:
422                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
423                 break;
424             }
425             add_xsd_integer(ptr, "startRecord", req->startRecord);
426             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
427             add_xsd_string(ptr, "recordSchema", req->recordSchema);
428             add_xsd_string(ptr, "recordPacking", req->recordPacking);
429             add_xsd_string(ptr, "database", req->database);
430         }
431         else if ((*p)->which == Z_SRW_searchRetrieve_response)
432         {
433             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
434             xmlNodePtr ptr = xmlNewChild(pptr, 0,
435                                          "searchRetrieveResponse", 0);
436             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
437
438             xmlSetNs(ptr, ns_srw);
439             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
440             add_xsd_string(ptr, "resultSetId", res->resultSetId);
441             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
442             if (res->num_records)
443             {
444                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
445                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
446                                 client_data, ns);
447             }
448             if (res->num_diagnostics)
449             {
450                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
451                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
452                                     &res->num_diagnostics, client_data, ns);
453             }
454             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
455         }
456         else if ((*p)->which == Z_SRW_explain_request)
457         {
458             Z_SRW_explainRequest *req = (*p)->u.explain_request;
459             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
460             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
461
462             xmlSetNs(ptr, ns_srw);
463         }
464         else if ((*p)->which == Z_SRW_explain_response)
465         {
466             Z_SRW_explainResponse *res = (*p)->u.explain_response;
467             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
468             xmlNsPtr ns_srw = xmlNewNs(ptr, ns, "zs");
469
470             xmlSetNs(ptr, ns_srw);
471
472             if (res->explainData_buf)
473             {
474                 xmlNodePtr t = xmlNewTextLen(res->explainData_buf,
475                                              res->explainData_len);
476                 xmlAddChild(ptr, t);
477             }
478         }
479         else
480             return -1;
481
482     }
483     return 0;
484 }
485
486 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
487 {
488     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
489     sr->which = which;
490     switch(which)
491     {
492     case Z_SRW_searchRetrieve_request:
493         sr->u.request = (Z_SRW_searchRetrieveRequest *)
494             odr_malloc(o, sizeof(*sr->u.request));
495         sr->u.request->query_type = Z_SRW_query_type_cql;
496         sr->u.request->query.cql = 0;
497         sr->u.request->sort_type = Z_SRW_sort_type_none;
498         sr->u.request->sort.none = 0;
499         sr->u.request->startRecord = 0;
500         sr->u.request->maximumRecords = 0;
501         sr->u.request->recordSchema = 0;
502         sr->u.request->recordPacking = 0;
503         sr->u.request->database = 0;
504         break;
505     case Z_SRW_searchRetrieve_response:
506         sr->u.response = (Z_SRW_searchRetrieveResponse *)
507             odr_malloc(o, sizeof(*sr->u.response));
508         sr->u.response->numberOfRecords = 0;
509         sr->u.response->resultSetId = 0;
510         sr->u.response->resultSetIdleTime = 0;
511         sr->u.response->records = 0;
512         sr->u.response->num_records = 0;
513         sr->u.response->diagnostics = 0;
514         sr->u.response->num_diagnostics = 0;
515         sr->u.response->nextRecordPosition = 0;
516         break;
517     case Z_SRW_explain_request:
518         sr->u.explain_request = (Z_SRW_explainRequest *)
519             odr_malloc(o, sizeof(*sr->u.explain_request));
520         sr->u.explain_request->dummy = 0;
521         break;
522     case Z_SRW_explain_response:
523         sr->u.explain_response = (Z_SRW_explainResponse *)
524             odr_malloc(o, sizeof(*sr->u.explain_response));
525         sr->u.explain_response->explainPacking = 0; 
526         sr->u.explain_response->explainData_buf = 0;
527         sr->u.explain_response->explainData_len = 0;
528     }
529     return sr;
530 }
531
532 #endif
533
534
535 static struct {
536     int code;
537     const char *msg;
538 } yaz_srw_codes [] = {
539 {1, "Permanent system error"}, 
540 {2, "System temporarily unavailable"}, 
541 {3, "Authentication error"}, 
542 /* Diagnostics Relating to CQL */
543 {10, "Illegal query"}, 
544 {11, "Unsupported query type (XCQL vs CQL)"}, 
545 {12, "Too many characters in query"}, 
546 {13, "Unbalanced or illegal use of parentheses"}, 
547 {14, "Unbalanced or illegal use of quotes"}, 
548 {15, "Illegal or unsupported index set"}, 
549 {16, "Illegal or unsupported index"}, 
550 {17, "Illegal or unsupported combination of index and index set"}, 
551 {18, "Illegal or unsupported combination of indexes"}, 
552 {19, "Illegal or unsupported relation"}, 
553 {20, "Illegal or unsupported relation modifier"}, 
554 {21, "Illegal or unsupported combination of relation modifers"}, 
555 {22, "Illegal or unsupported combination of relation and index"}, 
556 {23, "Too many characters in term"}, 
557 {24, "Illegal combination of relation and term"}, 
558 {25, "Special characters not quoted in term"}, 
559 {26, "Non special character escaped in term"}, 
560 {27, "Empty term unsupported"}, 
561 {28, "Masking character not supported"}, 
562 {29, "Masked words too short"}, 
563 {30, "Too many masking characters in term"}, 
564 {31, "Anchoring character not supported"}, 
565 {32, "Anchoring character in illegal or unsupported position"}, 
566 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
567 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
568 {35, "Terms only exclusion (stop) words"}, 
569 {36, "Term in invalid format for index or relation"}, 
570 {37, "Illegal or unsupported boolean operator"}, 
571 {38, "Too many boolean operators in query"}, 
572 {39, "Proximity not supported"}, 
573 {40, "Illegal or unsupported proximity relation"}, 
574 {41, "Illegal or unsupported proximity distance"}, 
575 {42, "Illegal or unsupported proximity unit"}, 
576 {43, "Illegal or unsupported proximity ordering"}, 
577 {44, "Illegal or unsupported combination of proximity modifiers"}, 
578 {45, "Index set name (prefix) assigned to multiple identifiers"}, 
579 /* Diagnostics Relating to Result Sets */
580 {50, "Result sets not supported"}, 
581 {51, "Result set does not exist"}, 
582 {52, "Result set temporarily unavailable"}, 
583 {53, "Result sets only supported for retrieval"}, 
584 {54, "Retrieval may only occur from an existing result set"}, 
585 {55, "Combination of result sets with search terms not supported"}, 
586 {56, "Only combination of single result set with search terms supported"}, 
587 {57, "Result set created but no records available"}, 
588 {58, "Result set created with unpredictable partial results available"}, 
589 {59, "Result set created with valid partial results available"}, 
590 /* Diagnostics Relating to Records */
591 {60, "Too many records retrieved"}, 
592 {61, "First record position out of range"}, 
593 {62, "Negative number of records requested"}, 
594 {63, "System error in retrieving records"}, 
595 {64, "Record temporarily unavailable"}, 
596 {65, "Record does not exist"}, 
597 {66, "Unknown schema for retrieval"}, 
598 {67, "Record not available in this schema"}, 
599 {68, "Not authorised to send record"}, 
600 {69, "Not authorised to send record in this schema"}, 
601 {70, "Record too large to send"}, 
602 /* Diagnostics Relating to Sorting */
603 {80, "Sort not supported"}, 
604 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
605 {82, "Illegal or unsupported sort sequence"}, 
606 {83, "Too many records"}, 
607 {84, "Too many sort keys"}, 
608 {85, "Duplicate sort keys"}, 
609 {86, "Incompatible record formats"}, 
610 {87, "Unsupported schema for sort"}, 
611 {88, "Unsupported tag path for sort"}, 
612 {89, "Tag path illegal or unsupported for schema"}, 
613 {90, "Illegal or unsupported direction value"}, 
614 {91, "Illegal or unsupported case value"}, 
615 {92, "Illegal or unsupported missing value action"}, 
616 /* Diagnostics Relating to Explain */
617 {100, "Explain not supported"}, 
618 {101, "Explain request type not supported (SOAP vs GET)"}, 
619 {102, "Explain record temporarily unavailable"},
620 {0, 0}
621 };
622
623 const char *yaz_diag_srw_str (int code)
624 {
625     int i;
626     for (i = 0; yaz_srw_codes[i].code; i++)
627         if (yaz_srw_codes[i].code == code)
628             return yaz_srw_codes[i].msg;
629     return 0;
630 }
631
632
633 /* bib1:srw */
634 static int srw_bib1_map[] = {
635     1, 1,
636     2, 2,
637     3, 11,
638     4, 35,
639     5, 12,
640     6, 38,
641     7, 30,
642     8, 32,
643     9, 29,
644     10, 10,
645     11, 12,
646     11, 23,
647     12, 60,
648     13, 61,
649     13, 62,
650     14, 63,
651     14, 64,
652     14, 65,
653     15, 68,
654     15, 69,
655     16, 70,
656     17, 70,
657     18, 50,
658     19, 55,
659     20, 56, 
660     21, 52,
661     22, 50,
662     23, 1,  /* bad map */
663     24, 63, /* bad map */
664     25, 63, /* bad map */
665     26, 63, /* bad map */
666     27, 51,
667     28, 52,
668     29, 52,
669     30, 51,
670     31, 57,
671     32, 58,
672     33, 59,
673     100, 1, /* bad map */
674     101, 3,
675     102, 3,
676     103, 3,
677     104, 3,
678     105, 3, 
679     106, 66,
680     107, 11,
681     108, 10,
682     108, 13,
683     108, 14,
684     108, 25,
685     108, 26,
686     108, 27,
687     108, 45,
688         
689     109, 1,
690     110, 37,
691     111, 1,
692     112, 58,
693     113, 10,
694     114, 16,
695     115, 16,
696     116, 16,
697     117, 19,
698     118, 22,
699     119, 32,
700     119, 31,
701     120, 28,
702     121, 15,
703     122, 32,
704     123, 22,
705     123, 17,
706     123, 18,
707     124, 24,
708     125, 36,
709     126, 36, 
710     127, 36,
711     128, 51,
712     129, 39,
713     130, 43,
714     131, 40,
715     132, 42,
716     201, 44,
717     201, 33,
718     201, 34,
719     202, 41,
720     203, 43,
721     205, 1,  /* bad map */
722     206, 1,  /* bad map */
723     207, 89,
724     208, 1,  /* bad map */
725     209, 80,
726     210, 80,
727     210, 81,
728     211, 84,
729     212, 85,
730     213, 92,
731     214, 90,
732     215, 91,
733     216, 92,
734     217, 63,
735     218, 1,  /* bad map */
736     219, 1,  /* bad map */
737     220, 1,  /* bad map */
738     221, 1,  /* bad map */
739     222, 1,  /* bad map */
740     223, 1,  /* bad map */
741     224, 1,  /* bad map */
742     225, 1,  /* bad map */
743     226, 1,  /* bad map */
744     227, 66,
745     228, 1,  /* bad map */
746     229, 36,
747     230, 83,
748     231, 89,
749     232, 1,
750     233, 1, /* bad map */
751     234, 1, /* bad map */
752     235, 2,
753     236, 3, 
754     237, 82,
755     238, 67,
756     239, 66,
757     240, 1, /* bad map */
758     241, 1, /* bad map */
759     242, 70,
760     243, 1, /* bad map */
761     244, 66,
762     245, 10,
763     246, 10,
764     247, 10,
765     1001, 1, /* bad map */
766     1002, 1, /* bad map */
767     1003, 1, /* bad map */
768     1004, 1, /* bad map */
769     1005, 1, /* bad map */
770     1006, 1, /* bad map */
771     1007, 100,
772     1008, 1, 
773     1009, 1,
774     1010, 3,
775     1011, 3,
776     1012, 3,
777     1013, 3,
778     1014, 3,
779     1015, 3,
780     1015, 3,
781     1016, 3,
782     1017, 3,
783     1018, 2,
784     1019, 2,
785     1020, 2,
786     1021, 3,
787     1022, 3,
788     1023, 3,
789     1024, 16,
790     1025, 3,
791     1026, 64,
792     1027, 1,
793     1028, 65,
794     1029, 1,
795     1040, 1,
796     /* 1041-1065 */
797     1066, 66,
798     1066, 67,
799     0
800 };
801
802 int yaz_diag_bib1_to_srw (int code)
803 {
804     const int *p = srw_bib1_map;
805     while (*p)
806     {
807         if (code == p[0])
808             return p[1];
809         p += 2;
810     }
811     return 1;
812 }
813
814 int yaz_diag_srw_to_bib1(int code)
815 {
816     const int *p = srw_bib1_map;
817     while (*p)
818     {
819         if (code == p[1])
820             return p[0];
821         p += 2;
822     }
823     return 1;
824 }