Bump year
[yaz-moved-to-github.git] / src / srwutil.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: srwutil.c,v 1.23 2005-01-15 19:47:14 adam Exp $
6  */
7 /**
8  * \file srwutil.c
9  * \brief Implements SRW/SRU utilities.
10  */
11
12 #include <yaz/srw.h>
13 #include <yaz/yaz-iconv.h>
14
15 static int hex_digit (int ch)
16 {
17     if (ch >= '0' && ch <= '9')
18         return ch - '0';
19     else if (ch >= 'a' && ch <= 'f')
20         return ch - 'a'+10;
21     else if (ch >= 'A' && ch <= 'F')
22         return ch - 'A'+10;
23     return 0;
24 }
25
26 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
27 {
28     int no = 2;
29     const char *cp;
30     *name = 0;
31     if (*path != '?')
32         return no;
33     path++;
34     cp = path;
35     while ((cp = strchr(cp, '&')))
36     {
37         cp++;
38         no++;
39     }
40     *name = odr_malloc(o, no * sizeof(char**));
41     *val = odr_malloc(o, no * sizeof(char**));
42
43     for (no = 0; *path; no++)
44     {
45         const char *p1 = strchr(path, '=');
46         size_t i = 0;
47         char *ret;
48         if (!p1)
49             break;
50
51         (*name)[no] = odr_malloc(o, (p1-path)+1);
52         memcpy((*name)[no], path, p1-path);
53         (*name)[no][p1-path] = '\0';
54
55         path = p1 + 1;
56         p1 = strchr(path, '&');
57         if (!p1)
58             p1 = strlen(path) + path;
59         (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
60         while (*path && *path != '&')
61         {
62             if (*path == '+')
63             {
64                 ret[i++] = ' ';
65                 path++;
66             }
67             else if (*path == '%' && path[1] && path[2])
68             {
69                 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
70                 path = path + 3;
71             }
72             else
73                 ret[i++] = *path++;
74         }
75         ret[i] = '\0';
76
77         if (*path)
78             path++;
79     }
80     (*name)[no] = 0;
81     (*val)[no] = 0;
82     return no;
83 }
84
85 char *yaz_uri_val(const char *path, const char *name, ODR o)
86 {
87     size_t nlen = strlen(name);
88     if (*path != '?')
89         return 0;
90     path++;
91     while (path && *path)
92     {
93         const char *p1 = strchr(path, '=');
94         if (!p1)
95             break;
96         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
97         {
98             size_t i = 0;
99             char *ret;
100             
101             path = p1 + 1;
102             p1 = strchr(path, '&');
103             if (!p1)
104                 p1 = strlen(path) + path;
105             ret = (char *) odr_malloc(o, p1 - path + 1);
106             while (*path && *path != '&')
107             {
108                 if (*path == '+')
109                 {
110                     ret[i++] = ' ';
111                     path++;
112                 }
113                 else if (*path == '%' && path[1] && path[2])
114                 {
115                     ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
116                     path = path + 3;
117                 }
118                 else
119                     ret[i++] = *path++;
120             }
121             ret[i] = '\0';
122             return ret;
123         }
124         path = strchr(p1, '&');
125         if (path)
126             path++;
127     }
128     return 0;
129 }
130
131 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
132 {
133     const char *v = yaz_uri_val(path, name, o);
134     if (v)
135         *intp = odr_intdup(o, atoi(v));
136 }
137
138 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d, 
139                            int code, const char *details)
140 {
141     d->uri = (char *) odr_malloc(o, 50);
142     sprintf(d->uri, "info:srw/diagnostic/1/%d", code);
143     d->message = 0;
144     if (details)
145         d->details = odr_strdup(o, details);
146     else
147         d->details = 0;
148 }
149
150 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
151                             int *num, int code, const char *addinfo)
152 {
153     Z_SRW_diagnostic *d_new;
154     d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
155     if (*num)
156         memcpy (d_new, *d, *num *sizeof(**d));
157     *d = d_new;
158
159     yaz_mk_std_diagnostic(o, *d + *num, code, addinfo);
160     (*num)++;
161 }
162
163 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
164                    Z_SOAP **soap_package, ODR decode, char **charset)
165 {
166     if (!strcmp(hreq->method, "POST"))
167     {
168         const char *content_type = z_HTTP_header_lookup(hreq->headers,
169                                                         "Content-Type");
170         if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
171         {
172             char *db = "Default";
173             const char *p0 = hreq->path, *p1;
174             int ret = -1;
175             const char *charset_p = 0;
176             
177             static Z_SOAP_Handler soap_handlers[3] = {
178 #if HAVE_XML2
179                 {"http://www.loc.gov/zing/srw/", 0,
180                  (Z_SOAP_fun) yaz_srw_codec},
181                 {"http://www.loc.gov/zing/srw/v1.0/", 0,
182                  (Z_SOAP_fun) yaz_srw_codec},
183 #endif
184                 {0, 0, 0}
185             };
186             
187             if (*p0 == '/')
188                 p0++;
189             p1 = strchr(p0, '?');
190             if (!p1)
191                 p1 = p0 + strlen(p0);
192             if (p1 != p0)
193             {
194                 db = (char*) odr_malloc(decode, p1 - p0 + 1);
195                 memcpy (db, p0, p1 - p0);
196                 db[p1 - p0] = '\0';
197             }
198
199             if (charset && (charset_p = strstr(content_type, "; charset=")))
200             {
201                 int i = 0;
202                 charset_p += 10;
203                 while (i < 20 && charset_p[i] &&
204                        !strchr("; \n\r", charset_p[i]))
205                     i++;
206                 *charset = (char*) odr_malloc(decode, i+1);
207                 memcpy(*charset, charset_p, i);
208                 (*charset)[i] = '\0';
209             }
210             ret = z_soap_codec(decode, soap_package, 
211                                &hreq->content_buf, &hreq->content_len,
212                                soap_handlers);
213             if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
214             {
215                 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
216                 
217                 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
218                     (*srw_pdu)->u.request->database == 0)
219                     (*srw_pdu)->u.request->database = db;
220
221                 if ((*srw_pdu)->which == Z_SRW_explain_request &&
222                     (*srw_pdu)->u.explain_request->database == 0)
223                     (*srw_pdu)->u.explain_request->database = db;
224
225                 if ((*srw_pdu)->which == Z_SRW_scan_request &&
226                     (*srw_pdu)->u.scan_request->database == 0)
227                     (*srw_pdu)->u.scan_request->database = db;
228
229                 return 0;
230             }
231             return 1;
232         }
233     }
234     return 2;
235 }
236
237 /**
238   http://www.loc.gov/z3950/agency/zing/srw/service.html
239 */ 
240 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
241                    Z_SOAP **soap_package, ODR decode, char **charset,
242                    Z_SRW_diagnostic **diag, int *num_diag)
243 {
244 #if HAVE_XML2
245     static Z_SOAP_Handler soap_handlers[2] = {
246         {"http://www.loc.gov/zing/srw/", 0,
247          (Z_SOAP_fun) yaz_srw_codec},
248         {0, 0, 0}
249     };
250 #endif
251     if (!strcmp(hreq->method, "GET"))
252     {
253         char *db = "Default";
254         const char *p0 = hreq->path, *p1;
255         const char *operation = 0;
256         char *version = 0;
257         char *query = 0;
258         char *pQuery = 0;
259         char *sortKeys = 0;
260         char *stylesheet = 0;
261         char *scanClause = 0;
262         char *pScanClause = 0;
263         char *recordXPath = 0;
264         char *recordSchema = 0;
265         char *recordPacking = "xml";  /* xml packing is default for SRU */
266         char *maximumRecords = 0;
267         char *startRecord = 0;
268         char *maximumTerms = 0;
269         char *responsePosition = 0;
270         char *extraRequestData = 0;
271         char **uri_name;
272         char **uri_val;
273
274         if (charset)
275             *charset = 0;
276         if (*p0 == '/')
277             p0++;
278         p1 = strchr(p0, '?');
279         if (!p1)
280             p1 = p0 + strlen(p0);
281         if (p1 != p0)
282         {
283             db = (char*) odr_malloc(decode, p1 - p0 + 1);
284             memcpy (db, p0, p1 - p0);
285             db[p1 - p0] = '\0';
286         }
287         yaz_uri_array(p1, decode, &uri_name, &uri_val);
288 #if HAVE_XML2
289         if (uri_name)
290         {
291             int i;
292             for (i = 0; uri_name[i]; i++)
293             {
294                 char *n = uri_name[i];
295                 char *v = uri_val[i];
296                 if (!strcmp(n, "query"))
297                     query = v;
298                 else if (!strcmp(n, "x-pquery"))
299                     pQuery = v;
300                 else if (!strcmp(n, "operation"))
301                     operation = v;
302                 else if (!strcmp(n, "stylesheet"))
303                     stylesheet = v;
304                 else if (!strcmp(n, "sortKeys"))
305                     sortKeys = v;
306                 else if (!strcmp(n, "recordXPath"))
307                     recordXPath = v;
308                 else if (!strcmp(n, "recordSchema"))
309                     recordSchema = v;
310                 else if (!strcmp(n, "recordPacking"))
311                     recordPacking = v;
312                 else if (!strcmp(n, "version"))
313                     version = v;
314                 else if (!strcmp(n, "scanClause"))
315                     scanClause = v;
316                 else if (!strcmp(n, "x-pScanClause"))
317                     pScanClause = v;
318                 else if (!strcmp(n, "maximumRecords"))
319                     maximumRecords = v;
320                 else if (!strcmp(n, "startRecord"))
321                     startRecord = v;
322                 else if (!strcmp(n, "maximumTerms"))
323                     maximumTerms = v;
324                 else if (!strcmp(n, "responsePosition"))
325                     responsePosition = v;
326                 else if (!strcmp(n, "extraRequestData"))
327                     extraRequestData = v;
328                 else
329                     yaz_add_srw_diagnostic(decode, diag, num_diag, 8, n);
330             }
331         }
332         if (!version)
333         {
334             if (uri_name)
335                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
336             version = "1.1";
337         }
338         if (strcmp(version, "1.1"))
339             yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
340         if (!operation)
341         {
342             if (uri_name)
343                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
344             operation = "explain";
345         }
346         if (!strcmp(operation, "searchRetrieve"))
347         {
348             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
349
350             sr->srw_version = version;
351             *srw_pdu = sr;
352             if (query)
353             {
354                 sr->u.request->query_type = Z_SRW_query_type_cql;
355                 sr->u.request->query.cql = query;
356             }
357             else if (pQuery)
358             {
359                 sr->u.request->query_type = Z_SRW_query_type_pqf;
360                 sr->u.request->query.pqf = pQuery;
361             }
362             else
363                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
364
365             if (sortKeys)
366             {
367                 sr->u.request->sort_type = Z_SRW_sort_type_sort;
368                 sr->u.request->sort.sortKeys = sortKeys;
369             }
370             sr->u.request->recordXPath = recordXPath;
371             sr->u.request->recordSchema = recordSchema;
372             sr->u.request->recordPacking = recordPacking;
373             sr->u.request->stylesheet = stylesheet;
374
375             if (maximumRecords)
376                 sr->u.request->maximumRecords =
377                     odr_intdup(decode, atoi(maximumRecords));
378             if (startRecord)
379                 sr->u.request->startRecord =
380                     odr_intdup(decode, atoi(startRecord));
381
382             sr->u.request->database = db;
383
384             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
385             (*soap_package)->which = Z_SOAP_generic;
386             
387             (*soap_package)->u.generic =
388                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
389             
390             (*soap_package)->u.generic->p = sr;
391             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
392             (*soap_package)->u.generic->no = 0;
393             
394             (*soap_package)->ns = "SRU";
395
396             return 0;
397         }
398         else if (!strcmp(operation, "explain"))
399         {
400             /* Transfer SRU explain parameters to common struct */
401             /* http://www.loc.gov/z3950/agency/zing/srw/explain.html */
402             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
403
404             sr->srw_version = version;
405             *srw_pdu = sr;
406             sr->u.explain_request->recordPacking = recordPacking;
407             sr->u.explain_request->database = db;
408
409             sr->u.explain_request->stylesheet = stylesheet;
410
411             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
412             (*soap_package)->which = Z_SOAP_generic;
413             
414             (*soap_package)->u.generic =
415                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
416             
417             (*soap_package)->u.generic->p = sr;
418             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
419             (*soap_package)->u.generic->no = 0;
420             
421             (*soap_package)->ns = "SRU";
422
423             return 0;
424         }
425         else if (!strcmp(operation, "scan"))
426         {
427             /* Transfer SRU scan parameters to common struct */
428             /* http://www.loc.gov/z3950/agency/zing/srw/scan.html */
429             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
430
431             sr->srw_version = version;
432             *srw_pdu = sr;
433
434             if (scanClause)
435             {
436                 sr->u.scan_request->query_type = Z_SRW_query_type_cql;
437                 sr->u.scan_request->scanClause.cql = scanClause;
438             }
439             else if (pScanClause)
440             {
441                 sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
442                 sr->u.scan_request->scanClause.pqf = pScanClause;
443             }
444             else
445                 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
446                                        "scanClause");
447             sr->u.scan_request->database = db;
448
449             if (maximumTerms)
450                 sr->u.scan_request->maximumTerms =
451                     odr_intdup(decode, atoi(maximumTerms));
452             if (responsePosition)
453                 sr->u.scan_request->responsePosition =
454                     odr_intdup(decode, atoi(responsePosition));
455
456             sr->u.scan_request->stylesheet = stylesheet;
457
458             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
459             (*soap_package)->which = Z_SOAP_generic;
460             
461             (*soap_package)->u.generic =
462                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
463             
464             (*soap_package)->u.generic->p = sr;
465             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
466             (*soap_package)->u.generic->no = 0;
467             
468             (*soap_package)->ns = "SRU";
469
470             return 0;
471         }
472         else
473         {
474             /* unsupported operation ... */
475             /* Act as if we received a explain request and throw diagnostic. */
476
477             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
478
479             sr->srw_version = version;
480             *srw_pdu = sr;
481             sr->u.explain_request->recordPacking = recordPacking;
482             sr->u.explain_request->database = db;
483
484             sr->u.explain_request->stylesheet = stylesheet;
485
486             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
487             (*soap_package)->which = Z_SOAP_generic;
488             
489             (*soap_package)->u.generic =
490                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
491             
492             (*soap_package)->u.generic->p = sr;
493             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
494             (*soap_package)->u.generic->no = 0;
495             
496             (*soap_package)->ns = "SRU";
497
498             yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
499             return 0;
500         }
501 #endif
502         return 1;
503     }
504     return 2;
505 }
506
507 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
508 {
509     Z_SRW_PDU *sr = (Z_SRW_PDU *) odr_malloc(o, sizeof(*o));
510
511     sr->srw_version = odr_strdup(o, "1.1");
512     sr->which = which;
513     switch(which)
514     {
515     case Z_SRW_searchRetrieve_request:
516         sr->u.request = (Z_SRW_searchRetrieveRequest *)
517             odr_malloc(o, sizeof(*sr->u.request));
518         sr->u.request->query_type = Z_SRW_query_type_cql;
519         sr->u.request->query.cql = 0;
520         sr->u.request->sort_type = Z_SRW_sort_type_none;
521         sr->u.request->sort.none = 0;
522         sr->u.request->startRecord = 0;
523         sr->u.request->maximumRecords = 0;
524         sr->u.request->recordSchema = 0;
525         sr->u.request->recordPacking = 0;
526         sr->u.request->recordXPath = 0;
527         sr->u.request->database = 0;
528         sr->u.request->resultSetTTL = 0;
529         sr->u.request->stylesheet = 0;
530         break;
531     case Z_SRW_searchRetrieve_response:
532         sr->u.response = (Z_SRW_searchRetrieveResponse *)
533             odr_malloc(o, sizeof(*sr->u.response));
534         sr->u.response->numberOfRecords = 0;
535         sr->u.response->resultSetId = 0;
536         sr->u.response->resultSetIdleTime = 0;
537         sr->u.response->records = 0;
538         sr->u.response->num_records = 0;
539         sr->u.response->diagnostics = 0;
540         sr->u.response->num_diagnostics = 0;
541         sr->u.response->nextRecordPosition = 0;
542         break;
543     case Z_SRW_explain_request:
544         sr->u.explain_request = (Z_SRW_explainRequest *)
545             odr_malloc(o, sizeof(*sr->u.explain_request));
546         sr->u.explain_request->recordPacking = 0;
547         sr->u.explain_request->database = 0;
548         sr->u.explain_request->stylesheet = 0;
549         break;
550     case Z_SRW_explain_response:
551         sr->u.explain_response = (Z_SRW_explainResponse *)
552             odr_malloc(o, sizeof(*sr->u.explain_response));
553         sr->u.explain_response->record.recordData_buf = 0;
554         sr->u.explain_response->record.recordData_len = 0;
555         sr->u.explain_response->record.recordSchema = 0;
556         sr->u.explain_response->record.recordPosition = 0;
557         sr->u.explain_response->record.recordPacking =
558             Z_SRW_recordPacking_string;
559         sr->u.explain_response->diagnostics = 0;
560         sr->u.explain_response->num_diagnostics = 0;
561         break;
562     case Z_SRW_scan_request:
563         sr->u.scan_request = (Z_SRW_scanRequest *)
564             odr_malloc(o, sizeof(*sr->u.scan_request));
565         sr->u.scan_request->database = 0;
566         sr->u.scan_request->stylesheet = 0;
567         sr->u.scan_request->maximumTerms = 0;
568         sr->u.scan_request->responsePosition = 0;
569         sr->u.scan_request->query_type = Z_SRW_query_type_cql;
570         sr->u.scan_request->scanClause.cql = 0;
571         break;
572     case Z_SRW_scan_response:
573         sr->u.scan_response = (Z_SRW_scanResponse *)
574             odr_malloc(o, sizeof(*sr->u.scan_response));
575         sr->u.scan_response->terms = 0;
576         sr->u.scan_response->num_terms = 0;
577         sr->u.scan_response->diagnostics = 0;
578         sr->u.scan_response->num_diagnostics = 0;
579     }
580     return sr;
581 }
582
583
584
585 /* bib1:srw */
586 static int srw_bib1_map[] = {
587     1, 1,
588     2, 2,
589     3, 11,
590     4, 35,
591     5, 12,
592     6, 38,
593     7, 30,
594     8, 32,
595     9, 29,
596     108, 10,  /* Malformed query : Syntax error */
597     10, 10,
598     11, 12,
599     11, 23,
600     12, 60,
601     13, 61,
602     13, 62,
603     14, 63,
604     14, 64,
605     14, 65,
606     15, 68,
607     15, 69,
608     16, 70,
609     17, 70,
610     18, 50,
611     19, 55,
612     20, 56, 
613     21, 52,
614     22, 50,
615     23, 3,
616     24, 66,
617     25, 66,
618     26, 66,
619     27, 51,
620     28, 52,
621     29, 52,
622     30, 51,
623     31, 57,
624     32, 58,
625     33, 59,
626     100, 1, /* bad map */
627     101, 3,
628     102, 3,
629     103, 3,
630     104, 3,
631     105, 3, 
632     106, 66,
633     107, 11,
634     108, 13,
635     108, 14,
636     108, 25,
637     108, 26,
638     108, 27,
639     108, 45,
640         
641     109, 2,
642     110, 37,
643     111, 1,
644     112, 58,
645     113, 10,
646     114, 16,
647     115, 16,
648     116, 16,
649     117, 19,
650     117, 20,
651     118, 22,
652     119, 32,
653     119, 31,
654     120, 28,
655     121, 15,
656     122, 32,
657     123, 22,
658     123, 17,
659     123, 18,
660     124, 24,
661     125, 36,
662     126, 36, 
663     127, 36,
664     128, 51,
665     129, 39,
666     130, 43,
667     131, 40,
668     132, 42,
669     201, 44,
670     201, 33,
671     201, 34,
672     202, 41,
673     203, 43,
674     205, 1,  /* bad map */
675     206, 1,  /* bad map */
676     207, 89,
677     208, 1,  /* bad map */
678     209, 80,
679     210, 80,
680     210, 81,
681     211, 84,
682     212, 85,
683     213, 92,
684     214, 90,
685     215, 91,
686     216, 92,
687     217, 63,
688     218, 1,  /* bad map */
689     219, 1,  /* bad map */
690     220, 1,  /* bad map */
691     221, 1,  /* bad map */
692     222, 1,  /* bad map */
693     223, 1,  /* bad map */
694     224, 1,  /* bad map */
695     225, 1,  /* bad map */
696     226, 1,  /* bad map */
697     227, 66,
698     228, 1,  /* bad map */
699     229, 36,
700     230, 83,
701     231, 89,
702     232, 1,
703     233, 1, /* bad map */
704     234, 1, /* bad map */
705     235, 2,
706     236, 3, 
707     237, 82,
708     238, 67,
709     239, 66,
710     240, 1, /* bad map */
711     241, 1, /* bad map */
712     242, 70,
713     243, 1, /* bad map */
714     244, 66,
715     245, 10,
716     246, 10,
717     247, 10,
718     1001, 1, /* bad map */
719     1002, 1, /* bad map */
720     1003, 1, /* bad map */
721     1004, 1, /* bad map */
722     1005, 1, /* bad map */
723     1006, 1, /* bad map */
724     1007, 100,
725     1008, 1, 
726     1009, 1,
727     1010, 3,
728     1011, 3,
729     1012, 3,
730     1013, 3,
731     1014, 3,
732     1015, 3,
733     1015, 3,
734     1016, 3,
735     1017, 3,
736     1018, 2,
737     1019, 2,
738     1020, 2,
739     1021, 3,
740     1022, 3,
741     1023, 3,
742     1024, 16,
743     1025, 3,
744     1026, 64,
745     1027, 1,
746     1028, 65,
747     1029, 1,
748     1040, 1,
749     /* 1041-1065 */
750     1066, 66,
751     1066, 67,
752     0
753 };
754
755 int yaz_diag_bib1_to_srw (int code)
756 {
757     const int *p = srw_bib1_map;
758     while (*p)
759     {
760         if (code == p[0])
761             return p[1];
762         p += 2;
763     }
764     return 1;
765 }
766
767 int yaz_diag_srw_to_bib1(int code)
768 {
769     const int *p = srw_bib1_map;
770     while (*p)
771     {
772         if (code == p[1])
773             return p[0];
774         p += 2;
775     }
776     return 1;
777 }
778