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