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