Fixed 523: PQF parser does not properly diagnose @prox syntax errors.
[yaz-moved-to-github.git] / src / marcdisp.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: marcdisp.c,v 1.25 2006-01-26 15:37:05 adam Exp $
6  */
7
8 /**
9  * \file marcdisp.c
10  * \brief Implements MARC display - and conversion utilities
11  */
12
13 #if HAVE_CONFIG_H
14 #include <config.h>
15 #endif
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <yaz/marcdisp.h>
21 #include <yaz/wrbuf.h>
22 #include <yaz/yaz-util.h>
23
24 struct yaz_marc_t_ {
25     WRBUF m_wr;
26     int xml;
27     int debug;
28     yaz_iconv_t iconv_cd;
29     char subfield_str[8];
30     char endline_str[8];
31 };
32
33 yaz_marc_t yaz_marc_create(void)
34 {
35     yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
36     mt->xml = YAZ_MARC_LINE;
37     mt->debug = 0;
38     mt->m_wr = wrbuf_alloc();
39     mt->iconv_cd = 0;
40     strcpy(mt->subfield_str, " $");
41     strcpy(mt->endline_str, "\n");
42     return mt;
43 }
44
45 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
46 {
47     strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
48     mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
49 }
50
51 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
52 {
53     strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
54     mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
55 }
56
57 void yaz_marc_destroy(yaz_marc_t mt)
58 {
59     if (!mt)
60         return ;
61     wrbuf_free (mt->m_wr, 1);
62     xfree (mt);
63 }
64
65 static void marc_cdata (yaz_marc_t mt, const char *buf, size_t len, WRBUF wr)
66 {
67     if (mt->xml == YAZ_MARC_ISO2709)
68         wrbuf_iconv_write(wr, mt->iconv_cd, buf, len);
69     else if (mt->xml == YAZ_MARC_LINE)
70         wrbuf_iconv_write(wr, mt->iconv_cd, buf, len);
71     else
72         wrbuf_iconv_write_cdata(wr, mt->iconv_cd, buf, len);
73 }
74
75 /* try to guess how many bytes the identifier really is! */
76 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
77 {
78     if (mt->iconv_cd)
79     {
80         size_t i;
81         for (i = 1; i<5; i++)
82         {
83             char outbuf[12];
84             size_t outbytesleft = sizeof(outbuf);
85             char *outp = outbuf;
86             const char *inp = buf;
87
88             size_t inbytesleft = i;
89             size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
90                                  &outp, &outbytesleft);
91             if (r != (size_t) (-1))
92                 return i;  /* got a complete sequence */
93         }
94         return 1; /* giving up */
95     }
96     return 1; /* we don't know */
97 }
98                               
99 static int atoi_n_check(const char *buf, int size, int *val)
100 {
101     if (!isdigit(*(const unsigned char *) buf))
102         return 0;
103     *val = atoi_n(buf, size);
104     return 1;
105 }
106
107 int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
108 {
109     int entry_p;
110     int record_length;
111     int indicator_length;
112     int identifier_length;
113     int end_of_directory;
114     int base_address;
115     int length_data_entry;
116     int length_starting;
117     int length_implementation;
118     char lead[24];
119     int produce_warnings = 0;
120
121     if (mt->debug)
122         produce_warnings = 1;
123     if (mt->xml == YAZ_MARC_SIMPLEXML || mt->xml == YAZ_MARC_OAIMARC
124         || mt->xml == YAZ_MARC_MARCXML || mt->xml == YAZ_MARC_XCHANGE)
125         produce_warnings = 1;
126
127     record_length = atoi_n (buf, 5);
128     if (record_length < 25)
129     {
130         if (mt->debug)
131             wrbuf_printf(wr, "<!-- Record length %d - aborting -->\n",
132                             record_length);
133         return -1;
134     }
135     memcpy(lead, buf, 24);  /* se can modify the header for output */
136
137     /* ballout if bsize is known and record_length is less than that */
138     if (bsize != -1 && record_length > bsize)
139         return -1;
140     if (!atoi_n_check(buf+10, 1, &indicator_length))
141     {
142         if (produce_warnings)
143             wrbuf_printf(wr, "<!-- Indicator length at offset 10 should hold a digit. Assuming 2 -->\n");
144         lead[10] = '2';
145         indicator_length = 2;
146     }
147     if (!atoi_n_check(buf+11, 1, &identifier_length))
148     {
149         if (produce_warnings)
150             wrbuf_printf(wr, "<!-- Identifier length at offset 11 should hold a digit. Assuming 2 -->\n");
151         lead[11] = '2';
152         identifier_length = 2;
153     }
154     if (!atoi_n_check(buf+12, 5, &base_address))
155     {
156         if (produce_warnings)
157             wrbuf_printf(wr, "<!-- Base address at offsets 12..16 should hold a number. Assuming 0 -->\n");
158         base_address = 0;
159     }
160     if (!atoi_n_check(buf+20, 1, &length_data_entry))
161     {
162         if (produce_warnings)
163             wrbuf_printf(wr, "<!-- Length data entry at offset 20 should hold a digit. Assuming 4 -->\n");
164         length_data_entry = 4;
165         lead[20] = '4';
166     }
167     if (!atoi_n_check(buf+21, 1, &length_starting))
168     {
169         if (produce_warnings)
170             wrbuf_printf(wr, "<!-- Length starting at offset 21 should hold a digit. Assuming 5 -->\n");
171         length_starting = 5;
172         lead[21] = '5';
173     }
174     if (!atoi_n_check(buf+22, 1, &length_implementation))
175     {
176         if (produce_warnings)
177             wrbuf_printf(wr, "<!-- Length implementation at offset 22 should hold a digit. Assuming 0 -->\n");
178         length_implementation = 0;
179         lead[22] = '0';
180     }
181
182     if (mt->xml != YAZ_MARC_LINE)
183     {
184         char str[80];
185         int i;
186         switch(mt->xml)
187         {
188         case YAZ_MARC_ISO2709:
189             break;
190         case YAZ_MARC_SIMPLEXML:
191             wrbuf_puts (wr, "<iso2709\n");
192             sprintf (str, " RecordStatus=\"%c\"\n", buf[5]);
193             wrbuf_puts (wr, str);
194             sprintf (str, " TypeOfRecord=\"%c\"\n", buf[6]);
195             wrbuf_puts (wr, str);
196             for (i = 1; i<=19; i++)
197             {
198                 sprintf (str, " ImplDefined%d=\"%c\"\n", i, buf[6+i]);
199                 wrbuf_puts (wr, str);
200             }
201             wrbuf_puts (wr, ">\n");
202             break;
203         case YAZ_MARC_OAIMARC:
204             wrbuf_puts(
205                 wr,
206                 "<oai_marc xmlns=\"http://www.openarchives.org/OIA/oai_marc\""
207                 "\n"
208                 " xmlns:xsi=\"http://www.w3.org/2000/10/XMLSchema-instance\""
209                 "\n"
210                 " xsi:schemaLocation=\"http://www.openarchives.org/OAI/oai_marc.xsd\""
211                 "\n"
212                 );
213             
214             sprintf (str, " status=\"%c\" type=\"%c\" catForm=\"%c\">\n",
215                      buf[5], buf[6], buf[7]);
216             wrbuf_puts (wr, str);
217             break;
218         case YAZ_MARC_MARCXML:
219             wrbuf_printf(
220                 wr,
221                 "<record xmlns=\"http://www.loc.gov/MARC21/slim\">\n"
222                 "  <leader>");
223             lead[9] = 'a';                 /* set leader to signal unicode */
224             marc_cdata(mt, lead, 24, wr); 
225             wrbuf_printf(wr, "</leader>\n");
226             break;
227         case YAZ_MARC_XCHANGE:
228             wrbuf_printf(
229                 wr,
230                 "<record xmlns=\"http://www.bs.dk/standards/MarcXchange\">\n"
231                 "  <leader>");
232             marc_cdata(mt, lead, 24, wr);
233             wrbuf_printf(wr, "</leader>\n");
234             break;
235         }
236     }
237     if (mt->debug)
238     {
239         char str[40];
240
241         wrbuf_puts (wr, "<!--\n");
242         sprintf (str, "Record length         %5d\n", record_length);
243         wrbuf_puts (wr, str);
244         sprintf (str, "Indicator length      %5d\n", indicator_length);
245         wrbuf_puts (wr, str);
246         sprintf (str, "Identifier length     %5d\n", identifier_length);
247         wrbuf_puts (wr, str);
248         sprintf (str, "Base address          %5d\n", base_address);
249         wrbuf_puts (wr, str);
250         sprintf (str, "Length data entry     %5d\n", length_data_entry);
251         wrbuf_puts (wr, str);
252         sprintf (str, "Length starting       %5d\n", length_starting);
253         wrbuf_puts (wr, str);
254         sprintf (str, "Length implementation %5d\n", length_implementation);
255         wrbuf_puts (wr, str);
256         wrbuf_puts (wr, "-->\n");
257     }
258
259     /* first pass. determine length of directory & base of data */
260     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
261     {
262         /* length of directory entry */
263         int l = 3 + length_data_entry + length_starting;
264         if (entry_p + l >= record_length)
265         {
266             wrbuf_printf (wr, "<!-- Directory offset %d: end of record. "
267                             "Missing FS char -->\n", entry_p);
268             return -1;
269         }
270         if (mt->debug)
271             wrbuf_printf (wr, "<!-- Directory offset %d: Tag %.3s -->\n",
272                             entry_p, buf+entry_p);
273         /* check for digits in length info */
274         while (--l >= 3)
275             if (!isdigit(*(const unsigned char *) (buf + entry_p+l)))
276                 break;
277         if (l >= 3)
278         {
279             /* not all digits, so stop directory scan */
280             wrbuf_printf (wr, "<!-- Directory offset %d: Bad data for data "
281                             "length and/or length starting -->\n", entry_p);
282             break;
283         }
284         entry_p += 3 + length_data_entry + length_starting;
285     }
286     end_of_directory = entry_p;
287     if (base_address != entry_p+1)
288     {
289         if (produce_warnings)
290             wrbuf_printf (wr,"<!-- Base address not at end of directory, "
291                           "base %d, end %d -->\n", base_address, entry_p+1);
292     }
293     if (mt->xml == YAZ_MARC_ISO2709)
294     {
295         WRBUF wr_head = wrbuf_alloc();
296         WRBUF wr_dir = wrbuf_alloc();
297         WRBUF wr_tmp = wrbuf_alloc();
298
299         int data_p = 0;
300         /* second pass. create directory for ISO2709 output */
301         for (entry_p = 24; entry_p != end_of_directory; )
302         {
303             int data_length, data_offset, end_offset;
304             int i, sz1, sz2;
305             
306             wrbuf_write(wr_dir, buf+entry_p, 3);
307             entry_p += 3;
308             
309             data_length = atoi_n (buf+entry_p, length_data_entry);
310             entry_p += length_data_entry;
311             data_offset = atoi_n (buf+entry_p, length_starting);
312             entry_p += length_starting;
313             i = data_offset + base_address;
314             end_offset = i+data_length-1;
315             
316             if (data_length <= 0 || data_offset < 0 || end_offset >= record_length)
317                 return -1;
318         
319             while (i < end_offset &&
320                     buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
321                 i++;
322             sz1 = 1+i - (data_offset + base_address);
323             if (mt->iconv_cd)
324             {
325                 sz2 = wrbuf_iconv_write(wr_tmp, mt->iconv_cd,
326                                         buf + data_offset+base_address, sz1);
327                 wrbuf_rewind(wr_tmp);
328             }
329             else
330                 sz2 = sz1;
331             wrbuf_printf(wr_dir, "%0*d", length_data_entry, sz2);
332             wrbuf_printf(wr_dir, "%0*d", length_starting, data_p);
333             data_p += sz2;
334         }
335         wrbuf_putc(wr_dir, ISO2709_FS);
336         wrbuf_printf(wr_head, "%05d", data_p+1 + base_address);
337         wrbuf_write(wr_head, lead+5, 7);
338         wrbuf_printf(wr_head, "%05d", base_address);
339         wrbuf_write(wr_head, lead+17, 7);
340
341         wrbuf_write(wr, wrbuf_buf(wr_head), 24);
342         wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
343         wrbuf_free(wr_head, 1);
344         wrbuf_free(wr_dir, 1);
345         wrbuf_free(wr_tmp, 1);
346     }
347     /* third pass. create data output */
348     for (entry_p = 24; entry_p != end_of_directory; )
349     {
350         int data_length;
351         int data_offset;
352         int end_offset;
353         int i, j;
354         char tag[4];
355         int identifier_flag = 0;
356         int entry_p0 = entry_p;
357
358         memcpy (tag, buf+entry_p, 3);
359         entry_p += 3;
360         tag[3] = '\0';
361         data_length = atoi_n (buf+entry_p, length_data_entry);
362         entry_p += length_data_entry;
363         data_offset = atoi_n (buf+entry_p, length_starting);
364         entry_p += length_starting;
365         i = data_offset + base_address;
366         end_offset = i+data_length-1;
367
368         if (data_length <= 0 || data_offset < 0)
369             break;
370         
371         if (mt->debug)
372         {
373             wrbuf_printf(wr, "<!-- Directory offset %d: data-length %d, "
374                             "data-offset %d -->\n",
375                     entry_p0, data_length, data_offset);
376         }
377         if (end_offset >= record_length)
378         {
379             wrbuf_printf (wr,"<!-- Directory offset %d: Data out of bounds "
380                             "%d >= %d -->\n",
381                                    entry_p0, end_offset, record_length);
382             break;
383         }
384         
385         if (memcmp (tag, "00", 2))
386             identifier_flag = 1;  /* if not 00X assume subfields */
387         else if (indicator_length < 4 && indicator_length > 0)
388         {
389             /* Danmarc 00X have subfields */
390             if (buf[i + indicator_length] == ISO2709_IDFS)
391                 identifier_flag = 1;
392             else if (buf[i + indicator_length + 1] == ISO2709_IDFS)
393                 identifier_flag = 2;
394         }
395
396         if (mt->debug)
397         {
398             wrbuf_printf(wr, "<!-- identifier_flag = %d -->\n",
399                          identifier_flag);
400         } 
401        
402         switch(mt->xml)
403         {
404         case YAZ_MARC_LINE:
405             wrbuf_puts (wr, tag);
406             wrbuf_puts (wr, " ");
407             break;
408         case YAZ_MARC_SIMPLEXML:
409             wrbuf_printf (wr, "<field tag=\"");
410             marc_cdata(mt, tag, strlen(tag), wr);
411             wrbuf_printf(wr, "\"");
412             break;
413         case YAZ_MARC_OAIMARC:
414             if (identifier_flag)
415                 wrbuf_printf (wr, "  <varfield id=\"");
416             else
417                 wrbuf_printf (wr, "  <fixfield id=\"");
418             marc_cdata(mt, tag, strlen(tag), wr);
419             wrbuf_printf(wr, "\"");
420             break;
421         case YAZ_MARC_MARCXML:
422         case YAZ_MARC_XCHANGE:
423             if (identifier_flag)
424                 wrbuf_printf (wr, "  <datafield tag=\"");
425             else
426                 wrbuf_printf (wr, "  <controlfield tag=\"");
427             marc_cdata(mt, tag, strlen(tag), wr);
428             wrbuf_printf(wr, "\"");
429         }
430         
431         if (identifier_flag)
432         {
433             i += identifier_flag-1;
434             for (j = 0; j<indicator_length; j++, i++)
435             {
436                 switch(mt->xml)
437                 {
438                 case YAZ_MARC_ISO2709:
439                     wrbuf_putc(wr, buf[i]);
440                     break;
441                 case YAZ_MARC_LINE:
442                     wrbuf_putc(wr, buf[i]);
443                     break;
444                 case YAZ_MARC_SIMPLEXML:
445                     wrbuf_printf(wr, " Indicator%d=\"", j+1);
446                     marc_cdata(mt, buf+i, 1, wr);
447                     wrbuf_printf(wr, "\"");
448                     break;
449                 case YAZ_MARC_OAIMARC:
450                     wrbuf_printf(wr, " i%d=\"", j+1);
451                     marc_cdata(mt, buf+i, 1, wr);
452                     wrbuf_printf(wr, "\"");
453                     break;
454                 case YAZ_MARC_MARCXML:
455                 case YAZ_MARC_XCHANGE:
456                     wrbuf_printf(wr, " ind%d=\"", j+1);
457                     marc_cdata(mt, buf+i, 1, wr);
458                     wrbuf_printf(wr, "\"");
459                 }
460             }
461         }
462         if (mt->xml == YAZ_MARC_SIMPLEXML || mt->xml == YAZ_MARC_MARCXML
463             || mt->xml == YAZ_MARC_OAIMARC || mt->xml == YAZ_MARC_XCHANGE)
464         {
465             wrbuf_puts (wr, ">");
466             if (identifier_flag)
467                 wrbuf_puts (wr, "\n");
468         }
469         if (identifier_flag)
470         {
471             while (i < end_offset &&
472                     buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
473             {
474                 int i0;
475
476                 int sb_octet_length = identifier_length-1;
477                 if (identifier_length == 2)
478                     sb_octet_length = cdata_one_character(mt, buf+i);
479
480                 i++;
481                 switch(mt->xml)
482                 {
483                 case YAZ_MARC_ISO2709:
484                     --i;
485                     wrbuf_iconv_write(wr, mt->iconv_cd, 
486                                       buf+i, identifier_length);
487                     i += identifier_length;
488                     break;
489                 case YAZ_MARC_LINE: 
490                     wrbuf_puts (wr, mt->subfield_str); 
491                     marc_cdata(mt, buf+i, sb_octet_length, wr);
492                     i = i+sb_octet_length;
493                     wrbuf_putc (wr, ' ');
494                     break;
495                 case YAZ_MARC_SIMPLEXML:
496                     wrbuf_puts (wr, "  <subfield code=\"");
497                     marc_cdata(mt, buf+i, sb_octet_length, wr);
498                     i = i+sb_octet_length;
499                     wrbuf_puts (wr, "\">");
500                     break;
501                 case YAZ_MARC_OAIMARC:
502                     wrbuf_puts (wr, "    <subfield label=\"");
503                     marc_cdata(mt, buf+i, sb_octet_length, wr);
504                     i = i+sb_octet_length;
505                     wrbuf_puts (wr, "\">");
506                     break;
507                 case YAZ_MARC_MARCXML:
508                 case YAZ_MARC_XCHANGE:
509                     wrbuf_puts (wr, "    <subfield code=\"");
510                     marc_cdata(mt, buf+i, sb_octet_length, wr);
511                     i = i+sb_octet_length;
512                     wrbuf_puts (wr, "\">");
513                     break;
514                 }
515                 i0 = i;
516                 while (i < end_offset &&
517                         buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
518                         buf[i] != ISO2709_FS)
519                     i++;
520                 marc_cdata(mt, buf + i0, i - i0, wr);
521
522                 if (mt->xml == YAZ_MARC_ISO2709 && buf[i] != ISO2709_IDFS)
523                     marc_cdata(mt, buf + i, 1, wr);
524
525                 if (mt->xml == YAZ_MARC_SIMPLEXML || 
526                     mt->xml == YAZ_MARC_MARCXML ||
527                     mt->xml == YAZ_MARC_XCHANGE ||
528                     mt->xml == YAZ_MARC_OAIMARC)
529                     wrbuf_puts (wr, "</subfield>\n");
530             }
531         }
532         else
533         {
534             int i0 = i;
535             while (i < end_offset && 
536                 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
537                 i++;
538             marc_cdata(mt, buf + i0, i - i0, wr);
539             if (mt->xml == YAZ_MARC_ISO2709)
540                 marc_cdata(mt, buf + i, 1, wr);
541         }
542         if (mt->xml == YAZ_MARC_LINE)
543             wrbuf_puts (wr, mt->endline_str);
544         if (i < end_offset)
545             wrbuf_printf(wr, "<!-- separator but not at end of field length=%d-->\n", data_length);
546         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
547             wrbuf_printf(wr, "<!-- no separator at end of field length=%d-->\n", data_length);
548         switch(mt->xml)
549         {
550         case YAZ_MARC_SIMPLEXML:
551             wrbuf_puts (wr, "</field>\n");
552             break;
553         case YAZ_MARC_OAIMARC:
554             if (identifier_flag)
555                 wrbuf_puts (wr, "</varfield>\n");
556             else
557                 wrbuf_puts (wr, "</fixfield>\n");
558             break;
559         case YAZ_MARC_MARCXML:
560         case YAZ_MARC_XCHANGE:
561             if (identifier_flag)
562                 wrbuf_puts (wr, "  </datafield>\n");
563             else
564                 wrbuf_puts (wr, "</controlfield>\n");
565             break;
566         }
567     }
568     switch (mt->xml)
569     {
570     case YAZ_MARC_LINE:
571         wrbuf_puts (wr, "");
572         break;
573     case YAZ_MARC_SIMPLEXML:
574         wrbuf_puts (wr, "</iso2709>\n");
575         break;
576     case YAZ_MARC_OAIMARC:
577         wrbuf_puts (wr, "</oai_marc>\n");
578         break;
579     case YAZ_MARC_MARCXML:
580     case YAZ_MARC_XCHANGE:
581         wrbuf_puts (wr, "</record>\n");
582         break;
583     case YAZ_MARC_ISO2709:
584         wrbuf_putc (wr, ISO2709_RS);
585         break;
586     }
587     return record_length;
588 }
589
590 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
591                          char **result, int *rsize)
592 {
593     int r;
594
595     wrbuf_rewind(mt->m_wr);
596     r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
597     if (result)
598         *result = wrbuf_buf(mt->m_wr);
599     if (rsize)
600         *rsize = wrbuf_len(mt->m_wr);
601     return r;
602 }
603
604 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
605 {
606     if (mt)
607         mt->xml = xmlmode;
608 }
609
610 void yaz_marc_debug(yaz_marc_t mt, int level)
611 {
612     if (mt)
613         mt->debug = level;
614 }
615
616 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
617 {
618     mt->iconv_cd = cd;
619 }
620
621 /* depricated */
622 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
623 {
624     yaz_marc_t mt = yaz_marc_create();
625     int r;
626
627     mt->debug = debug;
628     mt->xml = xml;
629     r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
630     yaz_marc_destroy(mt);
631     return r;
632 }
633
634 /* depricated */
635 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
636 {
637     return yaz_marc_decode(buf, wr, debug, bsize, 0);
638 }
639
640 /* depricated */
641 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
642 {
643     yaz_marc_t mt = yaz_marc_create();
644     int r;
645
646     mt->debug = debug;
647     r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
648     if (!outf)
649         outf = stdout;
650     if (r > 0)
651         fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
652     yaz_marc_destroy(mt);
653     return r;
654 }
655
656 /* depricated */
657 int marc_display_ex (const char *buf, FILE *outf, int debug)
658 {
659     return marc_display_exl (buf, outf, debug, -1);
660 }
661
662 /* depricated */
663 int marc_display (const char *buf, FILE *outf)
664 {
665     return marc_display_ex (buf, outf, 0);
666 }
667
668 /*
669  * Local variables:
670  * c-basic-offset: 4
671  * indent-tabs-mode: nil
672  * End:
673  * vim: shiftwidth=4 tabstop=8 expandtab
674  */
675