3e4e9d24215bc5c423df9afbcf4c87eee04e929c
[yaz-moved-to-github.git] / util / marcdisp.c
1 /*
2  * Copyright (c) 1995-2002, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: marcdisp.c,v 1.25 2002-12-09 23:32:29 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 int yaz_marc_decode (const char *buf, WRBUF wr, int debug, int bsize, int xml)
20 {
21     int entry_p;
22     int record_length;
23     int indicator_length;
24     int identifier_length;
25     int base_address;
26     int length_data_entry;
27     int length_starting;
28     int length_implementation;
29
30     record_length = atoi_n (buf, 5);
31     if (record_length < 25)
32     {
33         if (debug)
34         {
35             char str[40];
36             
37             sprintf (str, "Record length %d - aborting\n", record_length);
38             wrbuf_puts (wr, str);
39         }
40         return -1;
41     }
42     /* ballout if bsize is known and record_length is than that */
43     if (bsize != -1 && record_length > bsize)
44         return -1;
45     if (isdigit(buf[10]))
46         indicator_length = atoi_n (buf+10, 1);
47     else
48         indicator_length = 2;
49     if (isdigit(buf[11]))
50         identifier_length = atoi_n (buf+11, 1);
51     else
52         identifier_length = 2;
53     base_address = atoi_n (buf+12, 5);
54
55     length_data_entry = atoi_n (buf+20, 1);
56     length_starting = atoi_n (buf+21, 1);
57     length_implementation = atoi_n (buf+22, 1);
58
59     if (xml)
60     {
61         char str[80];
62         int i;
63         switch(xml)
64         {
65         case YAZ_MARC_XML:
66             wrbuf_puts (wr, "<iso2709\n");
67             sprintf (str, " RecordStatus=\"%c\"\n", buf[5]);
68             wrbuf_puts (wr, str);
69             sprintf (str, " TypeOfRecord=\"%c\"\n", buf[6]);
70             wrbuf_puts (wr, str);
71             for (i = 1; i<=19; i++)
72             {
73                 sprintf (str, " ImplDefined%d=\"%c\"\n", i, buf[6+i]);
74                 wrbuf_puts (wr, str);
75             }
76             wrbuf_puts (wr, ">\n");
77             break;
78         case YAZ_MARC_OAIMARC:
79             wrbuf_puts(
80                 wr,
81                 "<oai_marc xmlns=\"http://www.openarchives.org/OIA/oai_marc\""
82                 "\n"
83                 " xmlns:xsi=\"http://www.w3.org/2000/10/XMLSchema-instance\""
84                 "\n"
85                 " xsi:schemaLocation=\"http://www.openarchives.org/OAI/oai_marc.xsd\""
86                 "\n"
87                 );
88             
89             sprintf (str, " status=\"%c\" type=\"%c\" catForm=\"%c\">\n",
90                      buf[5], buf[6], buf[7]);
91             wrbuf_puts (wr, str);
92             break;
93         case YAZ_MARC_MARCXML:
94             wrbuf_printf(
95                 wr,
96                 "<record xmlns=\"http://www.loc.gov/MARC21/slim\">\n"
97                 "  <leader>%.24s</leader>\n", buf);
98             break;
99         }
100     }
101     if (debug)
102     {
103         char str[40];
104
105         if (xml)
106             wrbuf_puts (wr, "<!--\n");
107         sprintf (str, "Record length         %5d\n", record_length);
108         wrbuf_puts (wr, str);
109         sprintf (str, "Indicator length      %5d\n", indicator_length);
110         wrbuf_puts (wr, str);
111         sprintf (str, "Identifier length     %5d\n", identifier_length);
112         wrbuf_puts (wr, str);
113         sprintf (str, "Base address          %5d\n", base_address);
114         wrbuf_puts (wr, str);
115         sprintf (str, "Length data entry     %5d\n", length_data_entry);
116         wrbuf_puts (wr, str);
117         sprintf (str, "Length starting       %5d\n", length_starting);
118         wrbuf_puts (wr, str);
119         sprintf (str, "Length implementation %5d\n", length_implementation);
120         wrbuf_puts (wr, str);
121         if (xml)
122             wrbuf_puts (wr, "-->\n");
123     }
124
125     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
126     {
127         entry_p += 3+length_data_entry+length_starting;
128         if (entry_p >= record_length)
129             return -1;
130     }
131     base_address = entry_p+1;
132     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
133     {
134         int data_length;
135         int data_offset;
136         int end_offset;
137         int i, j;
138         char tag[4];
139         int identifier_flag = 1;
140
141         memcpy (tag, buf+entry_p, 3);
142         entry_p += 3;
143         tag[3] = '\0';
144         data_length = atoi_n (buf+entry_p, length_data_entry);
145         entry_p += length_data_entry;
146         data_offset = atoi_n (buf+entry_p, length_starting);
147         entry_p += length_starting;
148         i = data_offset + base_address;
149         end_offset = i+data_length-1;
150         
151         if (indicator_length < 4 && indicator_length > 0)
152         {
153             if (buf[i + indicator_length] != ISO2709_IDFS)
154                 identifier_flag = 0;
155         }
156         else if (!memcmp (tag, "00", 2))
157             identifier_flag = 0;
158         
159         switch(xml)
160         {
161         case YAZ_MARC_LINE:
162             if (debug)
163                 wrbuf_puts (wr, "Tag: ");
164             wrbuf_puts (wr, tag);
165             wrbuf_puts (wr, " ");
166             break;
167         case YAZ_MARC_XML:
168             wrbuf_printf (wr, "<field tag=\"%s\"", tag);
169             break;
170         case YAZ_MARC_OAIMARC:
171             if (identifier_flag)
172                 wrbuf_printf (wr, "  <varfield id=\"%s\"", tag);
173             else
174                 wrbuf_printf (wr, "  <fixfield id=\"%s\"", tag);
175             break;
176         case YAZ_MARC_MARCXML:
177             if (identifier_flag)
178                 wrbuf_printf (wr, "  <datafield tag=\"%s\"", tag);
179             else
180                 wrbuf_printf (wr, "  <controlfield tag=\"%s\"", tag);
181         }
182         
183         if (identifier_flag)
184         {
185             for (j = 0; j<indicator_length; j++, i++)
186             {
187                 switch(xml)
188                 {
189                 case YAZ_MARC_LINE:
190                     if (debug)
191                         wrbuf_puts (wr, " Ind: ");
192                     wrbuf_putc (wr, buf[i]);
193                     break;
194                 case YAZ_MARC_XML:
195                     wrbuf_printf (wr, " Indicator%d=\"%c\"", j+1, buf[i]);
196                     break;
197                 case YAZ_MARC_OAIMARC:
198                     wrbuf_printf (wr, " i%d=\"%c\"", j+1, buf[i]);
199                     break;
200                 case YAZ_MARC_MARCXML:
201                     wrbuf_printf (wr, " ind%d=\"%c\"", j+1, buf[i]);
202                 }
203             }
204         }
205         if (xml)
206         {
207             wrbuf_puts (wr, ">");
208             if (identifier_flag)
209                 wrbuf_puts (wr, "\n");
210         }
211         else
212         {
213             if (debug && !xml)
214                 wrbuf_puts (wr, " Fields: ");
215         }
216         while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
217         {
218             if (identifier_flag)
219             {
220                 i++;
221                 switch(xml)
222                 {
223                 case YAZ_MARC_LINE: 
224                     wrbuf_puts (wr, " $"); 
225                     for (j = 1; j<identifier_length; j++, i++)
226                         wrbuf_putc (wr, buf[i]);
227                     wrbuf_putc (wr, ' ');
228                     break;
229                 case YAZ_MARC_XML:
230                         wrbuf_puts (wr, "  <subfield code=\"");
231                     for (j = 1; j<identifier_length; j++, i++)
232                         wrbuf_putc (wr, buf[i]);
233                     wrbuf_puts (wr, "\">");
234                     break;
235                 case YAZ_MARC_OAIMARC:
236                     wrbuf_puts (wr, "    <subfield label=\"");
237                     for (j = 1; j<identifier_length; j++, i++)
238                         wrbuf_putc (wr, buf[i]);
239                     wrbuf_puts (wr, "\">");
240                     break;
241                 case YAZ_MARC_MARCXML:
242                     wrbuf_puts (wr, "    <subfield code=\"");
243                     for (j = 1; j<identifier_length; j++, i++)
244                         wrbuf_putc (wr, buf[i]);
245                     wrbuf_puts (wr, "\">");
246                     break;
247                 }
248                 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
249                        buf[i] != ISO2709_FS && i < end_offset)
250                 {
251                     if (xml && buf[i] == '<')
252                         wrbuf_puts(wr, "&#x003C;");
253                     else if (xml && buf[i] == '&')
254                         wrbuf_puts(wr, "&#x0026;");
255                     else
256                         wrbuf_putc (wr, buf[i]);
257                     i++;
258                 }
259                 if (xml)
260                     wrbuf_puts (wr, "</subfield>\n");
261             }
262             else
263             {
264                 if (xml && buf[i] == '<')
265                     wrbuf_puts(wr, "&lt;");
266                 else if (xml && buf[i] == '&')
267                     wrbuf_puts(wr, "&amp;");
268                 else if (xml && buf[i] == '"')
269                     wrbuf_puts(wr, "&quot;");
270                 else
271                     wrbuf_putc (wr, buf[i]);
272                 i++;
273             }
274         }
275         if (!xml)
276             wrbuf_putc (wr, '\n');
277         if (i < end_offset)
278             wrbuf_puts (wr, "  <!-- separator but not at end of field -->\n");
279         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
280             wrbuf_puts (wr, "  <!-- no separator at end of field -->\n");
281         switch(xml)
282         {
283         case YAZ_MARC_LINE: 
284             break;
285         case YAZ_MARC_XML:
286             wrbuf_puts (wr, "</field>\n");
287             break;
288         case YAZ_MARC_OAIMARC:
289             if (identifier_flag)
290                 wrbuf_puts (wr, "  </varfield>\n");
291             else
292                 wrbuf_puts (wr, "  </fixfield>\n");
293             break;
294         case YAZ_MARC_MARCXML:
295             if (identifier_flag)
296                 wrbuf_puts (wr, "  </datafield>\n");
297             else
298                 wrbuf_puts (wr, "  </controlfield>\n");
299             break;
300         }
301     }
302     switch(xml)
303     {
304     case YAZ_MARC_LINE:
305         wrbuf_puts (wr, "");
306         break;
307     case YAZ_MARC_XML:
308         wrbuf_puts (wr, "</iso2709>\n");
309         break;
310     case YAZ_MARC_OAIMARC:
311         wrbuf_puts (wr, "</oai_marc>\n");
312         break;
313     case YAZ_MARC_MARCXML:
314         wrbuf_puts (wr, "</record>\n");
315         break;
316     }
317     return record_length;
318 }
319
320 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug,
321                         int bsize)
322 {
323     return yaz_marc_decode (buf, wr, debug, bsize, 0);
324 }
325
326 int marc_display_exl (const char *buf, FILE *outf, int debug, int length)
327 {
328     int record_length;
329
330     WRBUF wrbuf = wrbuf_alloc ();
331     record_length = marc_display_wrbuf (buf, wrbuf, debug, length);
332     if (!outf)
333         outf = stdout;
334     if (record_length > 0)
335         fwrite (wrbuf_buf(wrbuf), 1, wrbuf_len(wrbuf), outf);
336     wrbuf_free (wrbuf, 1);
337     return record_length;
338 }
339
340 int marc_display_ex (const char *buf, FILE *outf, int debug)
341 {
342     return marc_display_exl (buf, outf, debug, -1);
343 }
344
345 int marc_display (const char *buf, FILE *outf)
346 {
347     return marc_display_ex (buf, outf, 0);
348 }
349
350