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