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