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