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