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