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