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