Update SRW messages strings to version 1.1
[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.9 2004-01-09 19:54:05 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 {4, "Unsupported operation"},
536 {5, "Unsupported version"},
537 {6, "Unsupported parameter value"},
538 {7, "Mandatory parameter not supplied"},
539 {8, "Unknown database"},
540 {9, "Unknown parameter type"},
541 /* Diagnostics Relating to CQL */
542 {10, "Query syntax error"}, 
543 {11, "Unsupported query type"}, 
544 {12, "Too many characters in query"}, 
545 {13, "Invalid or unsupported use of parentheses"}, 
546 {14, "Invalid or unsupported use of quotes"}, 
547 {15, "Unsupported context context set"}, 
548 {16, "Unsupported index"}, 
549 {17, "Unsupported combination of index and context set"}, 
550 {18, "Unsupported combination of indexes"}, 
551 {19, "Unsupported relation"}, 
552 {20, "Unsupported relation modifier"}, 
553 {21, "Unsupported combination of relation modifers"}, 
554 {22, "Unsupported combination of relation and index"}, 
555 {23, "Too many characters in term"}, 
556 {24, "Unsupported combination of relation and term"}, 
557 {25, "Special characters not quoted in term"}, 
558 {26, "Non special character escaped in term"}, 
559 {27, "Empty term unsupported"}, 
560 {28, "Masking character not supported"}, 
561 {29, "Masked words too short"}, 
562 {30, "Too many masking characters in term"}, 
563 {31, "Anchoring character not supported"}, 
564 {32, "Anchoring character in unsupported position"}, 
565 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
566 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
567 {35, "Terms only exclusion stopwords"}, 
568 {36, "Term in invalid format for index or relation"}, 
569 {37, "Unsupported boolean operator"}, 
570 {38, "Too many boolean operators in query"}, 
571 {39, "Proximity not supported"}, 
572 {40, "Unsupported proximity relation"}, 
573 {41, "Unsupported proximity distance"}, 
574 {42, "Unsupported proximity unit"}, 
575 {43, "Unsupported proximity ordering"}, 
576 {44, "Unsupported combination of proximity modifiers"}, 
577 {45, "context set name (prefix) assigned to multiple identifiers"}, 
578 /* Diagnostics Relating to Result Sets */
579 {50, "Result sets not supported"}, 
580 {51, "Result set does not exist"}, 
581 {52, "Result set temporarily unavailable"}, 
582 {53, "Result sets only supported for retrieval"}, 
583 {54, "Retrieval may only occur from an existing result set"}, 
584 {55, "Combination of result sets with search terms not supported"}, 
585 {56, "Only combination of single result set with search terms supported"}, 
586 {57, "Result set created but no records available"}, 
587 {58, "Result set created with unpredictable partial results available"}, 
588 {59, "Result set created with valid partial results available"}, 
589 /* Diagnostics Relating to Records */
590 {60, "Result set no created: too many records retrieved"}, 
591 {61, "First record position out of range"}, 
592 {62, "Negative number of records requested"}, 
593 {63, "System error in retrieving records"}, 
594 {64, "Record temporarily unavailable"}, 
595 {65, "Record does not exist"}, 
596 {66, "Unknown schema for retrieval"}, 
597 {67, "Record not available in this schema"}, 
598 {68, "Not authorised to send record"}, 
599 {69, "Not authorised to send record in this schema"}, 
600 {70, "Record too large to send"}, 
601 {71, "Unsupported record packing"},
602 {72, "XPath retrieval unsupported"},
603 {73, "XPath expression contains unsupported feature"},
604 {74, "Unable to evaluate XPath expression"},
605 /* Diagnostics Relating to Sorting */
606 {80, "Sort not supported"}, 
607 {81, "Unsupported sort type"}, 
608 {82, "Unsupported sort sequence"}, 
609 {83, "Too many records to sort"}, 
610 {84, "Too many sort keys to sort"}, 
611 {85, "Duplicate sort keys"}, 
612 {86, "Cannot sort: incompatible record formats"}, 
613 {87, "Unsupported schema for sort"}, 
614 {88, "Unsupported path for sort"}, 
615 {89, "Path unsupported for schema"}, 
616 {90, "Unsupported direction value"}, 
617 {91, "Unsupported case value"}, 
618 {92, "Unsupported missing value action"}, 
619 /* Diagnostics Relating to Explain */
620 {100, "Explain not supported"}, 
621 {101, "Explain request type not supported (SOAP vs GET)"}, 
622 {102, "Explain record temporarily unavailable"},
623 /* Diagnostics Relating to Stylesheets */
624 {110, "Stylesheets not supported"},
625 {111, "Unsupported stylesheet"},
626 /* Diagnostics relating to Scan */
627 {120, "Response position out of range"},
628 {0, 0}
629 };
630
631 const char *yaz_diag_srw_str (int code)
632 {
633     int i;
634     for (i = 0; yaz_srw_codes[i].code; i++)
635         if (yaz_srw_codes[i].code == code)
636             return yaz_srw_codes[i].msg;
637     return 0;
638 }
639
640
641 /* bib1:srw */
642 static int srw_bib1_map[] = {
643     1, 1,
644     2, 2,
645     3, 11,
646     4, 35,
647     5, 12,
648     6, 38,
649     7, 30,
650     8, 32,
651     9, 29,
652     108, 10,  /* Malformed query : Syntax error */
653     10, 10,
654     11, 12,
655     11, 23,
656     12, 60,
657     13, 61,
658     13, 62,
659     14, 63,
660     14, 64,
661     14, 65,
662     15, 68,
663     15, 69,
664     16, 70,
665     17, 70,
666     18, 50,
667     19, 55,
668     20, 56, 
669     21, 52,
670     22, 50,
671     23, 3,
672     24, 66,
673     25, 66,
674     26, 66,
675     27, 51,
676     28, 52,
677     29, 52,
678     30, 51,
679     31, 57,
680     32, 58,
681     33, 59,
682     100, 1, /* bad map */
683     101, 3,
684     102, 3,
685     103, 3,
686     104, 3,
687     105, 3, 
688     106, 66,
689     107, 11,
690     108, 13,
691     108, 14,
692     108, 25,
693     108, 26,
694     108, 27,
695     108, 45,
696         
697     109, 9,
698     110, 37,
699     111, 1,
700     112, 58,
701     113, 10,
702     114, 16,
703     115, 16,
704     116, 16,
705     117, 19,
706     118, 22,
707     119, 32,
708     119, 31,
709     120, 28,
710     121, 15,
711     122, 32,
712     123, 22,
713     123, 17,
714     123, 18,
715     124, 24,
716     125, 36,
717     126, 36, 
718     127, 36,
719     128, 51,
720     129, 39,
721     130, 43,
722     131, 40,
723     132, 42,
724     201, 44,
725     201, 33,
726     201, 34,
727     202, 41,
728     203, 43,
729     205, 1,  /* bad map */
730     206, 1,  /* bad map */
731     207, 89,
732     208, 1,  /* bad map */
733     209, 80,
734     210, 80,
735     210, 81,
736     211, 84,
737     212, 85,
738     213, 92,
739     214, 90,
740     215, 91,
741     216, 92,
742     217, 63,
743     218, 1,  /* bad map */
744     219, 1,  /* bad map */
745     220, 1,  /* bad map */
746     221, 1,  /* bad map */
747     222, 1,  /* bad map */
748     223, 1,  /* bad map */
749     224, 1,  /* bad map */
750     225, 1,  /* bad map */
751     226, 1,  /* bad map */
752     227, 66,
753     228, 1,  /* bad map */
754     229, 36,
755     230, 83,
756     231, 89,
757     232, 1,
758     233, 1, /* bad map */
759     234, 1, /* bad map */
760     235, 2,
761     236, 3, 
762     237, 82,
763     238, 67,
764     239, 66,
765     240, 1, /* bad map */
766     241, 1, /* bad map */
767     242, 70,
768     243, 1, /* bad map */
769     244, 66,
770     245, 10,
771     246, 10,
772     247, 10,
773     1001, 1, /* bad map */
774     1002, 1, /* bad map */
775     1003, 1, /* bad map */
776     1004, 1, /* bad map */
777     1005, 1, /* bad map */
778     1006, 1, /* bad map */
779     1007, 100,
780     1008, 1, 
781     1009, 1,
782     1010, 3,
783     1011, 3,
784     1012, 3,
785     1013, 3,
786     1014, 3,
787     1015, 3,
788     1015, 3,
789     1016, 3,
790     1017, 3,
791     1018, 2,
792     1019, 2,
793     1020, 2,
794     1021, 3,
795     1022, 3,
796     1023, 3,
797     1024, 16,
798     1025, 3,
799     1026, 64,
800     1027, 1,
801     1028, 65,
802     1029, 1,
803     1040, 1,
804     /* 1041-1065 */
805     1066, 66,
806     1066, 67,
807     0
808 };
809
810 int yaz_diag_bib1_to_srw (int code)
811 {
812     const int *p = srw_bib1_map;
813     while (*p)
814     {
815         if (code == p[0])
816             return p[1];
817         p += 2;
818     }
819     return 1;
820 }
821
822 int yaz_diag_srw_to_bib1(int code)
823 {
824     const int *p = srw_bib1_map;
825     while (*p)
826     {
827         if (code == p[1])
828             return p[0];
829         p += 2;
830     }
831     return 1;
832 }
833