Source restructure. yaz-marcdump part of installation
[yaz-moved-to-github.git] / src / marcdisp.c
1 /*
2  * Copyright (c) 1995-2003, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: marcdisp.c,v 1.1 2003-10-27 12:21:30 adam Exp $
6  */
7
8 #if HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <yaz/marcdisp.h>
16 #include <yaz/wrbuf.h>
17 #include <yaz/yaz-util.h>
18
19 struct yaz_marc_t_ {
20     WRBUF m_wr;
21     int xml;
22     int debug;
23 };
24
25 yaz_marc_t yaz_marc_create(void)
26 {
27     yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
28     mt->xml = YAZ_MARC_LINE;
29     mt->debug = 0;
30     mt->m_wr = wrbuf_alloc();
31     return mt;
32 }
33
34 void yaz_marc_destroy(yaz_marc_t mt)
35 {
36     if (!mt)
37         return ;
38     wrbuf_free (mt->m_wr, 1);
39     xfree (mt);
40 }
41
42 static void marc_cdata (yaz_marc_t mt, const char *buf, size_t len, WRBUF wr)
43 {
44     size_t i;
45     for (i = 0; i<len; i++)
46     {
47         if (mt->xml)
48         {
49             switch (buf[i]) {
50             case '<':
51                 wrbuf_puts(wr, "&lt;");
52                 break;
53             case '>':
54                 wrbuf_puts(wr, "&gt;");
55                 break;
56             case '&':
57                 wrbuf_puts(wr, "&amp;");
58                 break;
59             case '"':
60                 wrbuf_puts(wr, "&quot;");
61                 break;
62             case '\'':
63                 wrbuf_puts(wr, "&apos;");
64                 break;
65             default:
66                 wrbuf_putc(wr, buf[i]);
67             }
68         }
69         else
70             wrbuf_putc(wr, buf[i]);
71     }
72 }
73
74 #if 0
75 static void marc_cdata (yaz_marc_t mt, const char *buf, size_t len)
76 {
77     if (!mt->cd)
78         marc_cdata2 (mt, buf, len);
79     else
80     {
81         char outbuf[12];
82         size_t inbytesleft = len;
83         const char *inp = buf;
84         
85         while (inbytesleft)
86         {
87             size_t outbytesleft = sizeof(outbuf);
88             char *outp = outbuf;
89             size_t r = yaz_iconv (mt->cd, (char**) &inp, &inbytesleft, 
90                                   &outp, &outbytesleft);
91             if (r == (size_t) (-1))
92             {
93                 int e = yaz_iconv_error(mt->cd);
94                 if (e != YAZ_ICONV_E2BIG)
95                     break;
96             }
97             marc_cdata2 (mt, outbuf, outp - outbuf);
98         }
99     }
100 }
101 #endif
102
103 int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
104 {
105     int entry_p;
106     int record_length;
107     int indicator_length;
108     int identifier_length;
109     int base_address;
110     int length_data_entry;
111     int length_starting;
112     int length_implementation;
113
114     wrbuf_rewind(wr);
115
116     record_length = atoi_n (buf, 5);
117     if (record_length < 25)
118     {
119         if (mt->debug)
120         {
121             char str[40];
122             
123             sprintf (str, "Record length %d - aborting\n", record_length);
124             wrbuf_puts (wr, str);
125         }
126         return -1;
127     }
128     /* ballout if bsize is known and record_length is than that */
129     if (bsize != -1 && record_length > bsize)
130         return -1;
131     if (isdigit(buf[10]))
132         indicator_length = atoi_n (buf+10, 1);
133     else
134         indicator_length = 2;
135     if (isdigit(buf[11]))
136         identifier_length = atoi_n (buf+11, 1);
137     else
138         identifier_length = 2;
139     base_address = atoi_n (buf+12, 5);
140
141     length_data_entry = atoi_n (buf+20, 1);
142     length_starting = atoi_n (buf+21, 1);
143     length_implementation = atoi_n (buf+22, 1);
144
145     if (mt->xml)
146     {
147         char str[80];
148         int i;
149         switch(mt->xml)
150         {
151         case YAZ_MARC_SIMPLEXML:
152             wrbuf_puts (wr, "<iso2709\n");
153             sprintf (str, " RecordStatus=\"%c\"\n", buf[5]);
154             wrbuf_puts (wr, str);
155             sprintf (str, " TypeOfRecord=\"%c\"\n", buf[6]);
156             wrbuf_puts (wr, str);
157             for (i = 1; i<=19; i++)
158             {
159                 sprintf (str, " ImplDefined%d=\"%c\"\n", i, buf[6+i]);
160                 wrbuf_puts (wr, str);
161             }
162             wrbuf_puts (wr, ">\n");
163             break;
164         case YAZ_MARC_OAIMARC:
165             wrbuf_puts(
166                 wr,
167                 "<oai_marc xmlns=\"http://www.openarchives.org/OIA/oai_marc\""
168                 "\n"
169                 " xmlns:xsi=\"http://www.w3.org/2000/10/XMLSchema-instance\""
170                 "\n"
171                 " xsi:schemaLocation=\"http://www.openarchives.org/OAI/oai_marc.xsd\""
172                 "\n"
173                 );
174             
175             sprintf (str, " status=\"%c\" type=\"%c\" catForm=\"%c\">\n",
176                      buf[5], buf[6], buf[7]);
177             wrbuf_puts (wr, str);
178             break;
179         case YAZ_MARC_MARCXML:
180             wrbuf_printf(
181                 wr,
182                 "<record xmlns=\"http://www.loc.gov/MARC21/slim\">\n"
183                 "  <leader>%.24s</leader>\n", buf);
184             break;
185         }
186     }
187     if (mt->debug)
188     {
189         char str[40];
190
191         if (mt->xml)
192             wrbuf_puts (wr, "<!--\n");
193         sprintf (str, "Record length         %5d\n", record_length);
194         wrbuf_puts (wr, str);
195         sprintf (str, "Indicator length      %5d\n", indicator_length);
196         wrbuf_puts (wr, str);
197         sprintf (str, "Identifier length     %5d\n", identifier_length);
198         wrbuf_puts (wr, str);
199         sprintf (str, "Base address          %5d\n", base_address);
200         wrbuf_puts (wr, str);
201         sprintf (str, "Length data entry     %5d\n", length_data_entry);
202         wrbuf_puts (wr, str);
203         sprintf (str, "Length starting       %5d\n", length_starting);
204         wrbuf_puts (wr, str);
205         sprintf (str, "Length implementation %5d\n", length_implementation);
206         wrbuf_puts (wr, str);
207         if (mt->xml)
208             wrbuf_puts (wr, "-->\n");
209     }
210
211     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
212     {
213         entry_p += 3+length_data_entry+length_starting;
214         if (entry_p >= record_length)
215             return -1;
216     }
217     base_address = entry_p+1;
218     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
219     {
220         int data_length;
221         int data_offset;
222         int end_offset;
223         int i, j;
224         char tag[4];
225         int identifier_flag = 1;
226
227         memcpy (tag, buf+entry_p, 3);
228         entry_p += 3;
229         tag[3] = '\0';
230         data_length = atoi_n (buf+entry_p, length_data_entry);
231         entry_p += length_data_entry;
232         data_offset = atoi_n (buf+entry_p, length_starting);
233         entry_p += length_starting;
234         i = data_offset + base_address;
235         end_offset = i+data_length-1;
236         
237         if (indicator_length < 4 && indicator_length > 0)
238         {
239             if (buf[i + indicator_length] != ISO2709_IDFS)
240                 identifier_flag = 0;
241         }
242         else if (!memcmp (tag, "00", 2))
243             identifier_flag = 0;
244         
245         switch(mt->xml)
246         {
247         case YAZ_MARC_LINE:
248             if (mt->debug)
249                 wrbuf_puts (wr, "Tag: ");
250             wrbuf_puts (wr, tag);
251             wrbuf_puts (wr, " ");
252             break;
253         case YAZ_MARC_SIMPLEXML:
254             wrbuf_printf (wr, "<field tag=\"%s\"", tag);
255             break;
256         case YAZ_MARC_OAIMARC:
257             if (identifier_flag)
258                 wrbuf_printf (wr, "  <varfield id=\"%s\"", tag);
259             else
260                 wrbuf_printf (wr, "  <fixfield id=\"%s\"", tag);
261             break;
262         case YAZ_MARC_MARCXML:
263             if (identifier_flag)
264                 wrbuf_printf (wr, "  <datafield tag=\"%s\"", tag);
265             else
266                 wrbuf_printf (wr, "  <controlfield tag=\"%s\"", tag);
267         }
268         
269         if (identifier_flag)
270         {
271             for (j = 0; j<indicator_length; j++, i++)
272             {
273                 switch(mt->xml)
274                 {
275                 case YAZ_MARC_LINE:
276                     if (mt->debug)
277                         wrbuf_puts (wr, " Ind: ");
278                     wrbuf_putc (wr, buf[i]);
279                     break;
280                 case YAZ_MARC_SIMPLEXML:
281                     wrbuf_printf (wr, " Indicator%d=\"%c\"", j+1, buf[i]);
282                     break;
283                 case YAZ_MARC_OAIMARC:
284                     wrbuf_printf (wr, " i%d=\"%c\"", j+1, buf[i]);
285                     break;
286                 case YAZ_MARC_MARCXML:
287                     wrbuf_printf (wr, " ind%d=\"%c\"", j+1, buf[i]);
288                 }
289             }
290         }
291         if (mt->xml)
292         {
293             wrbuf_puts (wr, ">");
294             if (identifier_flag)
295                 wrbuf_puts (wr, "\n");
296         }
297         else
298         {
299             if (mt->debug && !mt->xml)
300                 wrbuf_puts (wr, " Fields: ");
301         }
302         if (identifier_flag)
303         {
304             while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
305             {
306                 int i0;
307                 i++;
308                 switch(mt->xml)
309                 {
310                 case YAZ_MARC_LINE: 
311                     wrbuf_puts (wr, " $"); 
312                     for (j = 1; j<identifier_length; j++, i++)
313                         wrbuf_putc (wr, buf[i]);
314                     wrbuf_putc (wr, ' ');
315                     break;
316                 case YAZ_MARC_SIMPLEXML:
317                     wrbuf_puts (wr, "  <subfield code=\"");
318                     for (j = 1; j<identifier_length; j++, i++)
319                         wrbuf_putc (wr, buf[i]);
320                     wrbuf_puts (wr, "\">");
321                     break;
322                 case YAZ_MARC_OAIMARC:
323                     wrbuf_puts (wr, "    <subfield label=\"");
324                     for (j = 1; j<identifier_length; j++, i++)
325                         wrbuf_putc (wr, buf[i]);
326                     wrbuf_puts (wr, "\">");
327                     break;
328                 case YAZ_MARC_MARCXML:
329                     wrbuf_puts (wr, "    <subfield code=\"");
330                     for (j = 1; j<identifier_length; j++, i++)
331                         wrbuf_putc (wr, buf[i]);
332                     wrbuf_puts (wr, "\">");
333                     break;
334                 }
335                 i0 = i;
336                 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
337                        buf[i] != ISO2709_FS && i < end_offset)
338                     i++;
339                 marc_cdata(mt, buf + i0, i - i0, wr);
340                 
341                 if (mt->xml)
342                     wrbuf_puts (wr, "</subfield>\n");
343             }
344         }
345         else
346         {
347             int i0 = i;
348             while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
349                 i++;
350             marc_cdata(mt, buf + i0, i - i0, wr);
351         }
352         if (!mt->xml)
353             wrbuf_putc (wr, '\n');
354         if (i < end_offset)
355             wrbuf_puts (wr, "  <!-- separator but not at end of field -->\n");
356         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
357             wrbuf_puts (wr, "  <!-- no separator at end of field -->\n");
358         switch(mt->xml)
359         {
360         case YAZ_MARC_SIMPLEXML:
361             wrbuf_puts (wr, "</field>\n");
362             break;
363         case YAZ_MARC_OAIMARC:
364             if (identifier_flag)
365                 wrbuf_puts (wr, "  </varfield>\n");
366             else
367                 wrbuf_puts (wr, "  </fixfield>\n");
368             break;
369         case YAZ_MARC_MARCXML:
370             if (identifier_flag)
371                 wrbuf_puts (wr, "  </datafield>\n");
372             else
373                 wrbuf_puts (wr, "  </controlfield>\n");
374             break;
375         }
376     }
377     switch (mt->xml)
378     {
379     case YAZ_MARC_LINE:
380         wrbuf_puts (wr, "");
381         break;
382     case YAZ_MARC_SIMPLEXML:
383         wrbuf_puts (wr, "</iso2709>\n");
384         break;
385     case YAZ_MARC_OAIMARC:
386         wrbuf_puts (wr, "</oai_marc>\n");
387         break;
388     case YAZ_MARC_MARCXML:
389         wrbuf_puts (wr, "</record>\n");
390         break;
391     }
392     return record_length;
393 }
394
395 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
396                          char **result, int *rsize)
397 {
398     int r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
399     if (r > 0)
400     {
401         if (result)
402             *result = wrbuf_buf(mt->m_wr);
403         if (rsize)
404             *rsize = wrbuf_len(mt->m_wr);
405     }
406     return r;
407 }
408
409 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
410 {
411     if (mt)
412         mt->xml = xmlmode;
413 }
414
415 void yaz_marc_debug(yaz_marc_t mt, int level)
416 {
417     if (mt)
418         mt->debug = level;
419 }
420
421 /* depricated */
422 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
423 {
424     yaz_marc_t mt = yaz_marc_create();
425     int r;
426
427     mt->debug = debug;
428     mt->xml = xml;
429     r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
430     yaz_marc_destroy(mt);
431     return r;
432 }
433
434 /* depricated */
435 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
436 {
437     return yaz_marc_decode(buf, wr, debug, bsize, 0);
438 }
439
440 /* depricated */
441 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
442 {
443     yaz_marc_t mt = yaz_marc_create();
444     int r;
445
446     mt->debug = debug;
447     r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
448     if (!outf)
449         outf = stdout;
450     if (r > 0)
451         fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
452     yaz_marc_destroy(mt);
453     return r;
454 }
455
456 /* depricated */
457 int marc_display_ex (const char *buf, FILE *outf, int debug)
458 {
459     return marc_display_exl (buf, outf, debug, -1);
460 }
461
462 /* depricated */
463 int marc_display (const char *buf, FILE *outf)
464 {
465     return marc_display_ex (buf, outf, 0);
466 }
467