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