Added yaz_marc_write_xml which creates MARCXML/MarcXchange record as
[yaz-moved-to-github.git] / src / marcdisp.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: marcdisp.c,v 1.40 2006-12-18 10:33:22 adam Exp $
6  */
7
8 /**
9  * \file marcdisp.c
10  * \brief Implements MARC conversion utilities
11  */
12
13 #if HAVE_CONFIG_H
14 #include <config.h>
15 #endif
16
17 #ifdef WIN32
18 #include <windows.h>
19 #endif
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <yaz/marcdisp.h>
26 #include <yaz/wrbuf.h>
27 #include <yaz/yaz-util.h>
28 #include <yaz/nmem_xml.h>
29
30 #if YAZ_HAVE_XML2
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #endif
34
35 /** \brief node types for yaz_marc_node */
36 enum YAZ_MARC_NODE_TYPE
37
38     YAZ_MARC_DATAFIELD,
39     YAZ_MARC_CONTROLFIELD,
40     YAZ_MARC_COMMENT,
41     YAZ_MARC_LEADER
42 };
43
44 /** \brief represets a data field */
45 struct yaz_marc_datafield {
46     char *tag;
47     char *indicator;
48     struct yaz_marc_subfield *subfields;
49 };
50
51 /** \brief represents a control field */
52 struct yaz_marc_controlfield {
53     char *tag;
54     char *data;
55 };
56
57 /** \brief a comment node */
58 struct yaz_marc_comment {
59     char *comment;
60 };
61
62 /** \brief MARC node */
63 struct yaz_marc_node {
64     enum YAZ_MARC_NODE_TYPE which;
65     union {
66         struct yaz_marc_datafield datafield;
67         struct yaz_marc_controlfield controlfield;
68         char *comment;
69         char *leader;
70     } u;
71     struct yaz_marc_node *next;
72 };
73
74 /** \brief represents a subfield */
75 struct yaz_marc_subfield {
76     char *code_data;
77     struct yaz_marc_subfield *next;
78 };
79
80 /** \brief the internals of a yaz_marc_t handle */
81 struct yaz_marc_t_ {
82     WRBUF m_wr;
83     NMEM nmem;
84     int xml;
85     int debug;
86     int write_using_libxml2;
87     yaz_iconv_t iconv_cd;
88     char subfield_str[8];
89     char endline_str[8];
90     char *leader_spec;
91     struct yaz_marc_node *nodes;
92     struct yaz_marc_node **nodes_pp;
93     struct yaz_marc_subfield **subfield_pp;
94 };
95
96 yaz_marc_t yaz_marc_create(void)
97 {
98     yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
99     mt->xml = YAZ_MARC_LINE;
100     mt->debug = 0;
101     mt->write_using_libxml2 = 0;
102     mt->m_wr = wrbuf_alloc();
103     mt->iconv_cd = 0;
104     mt->leader_spec = 0;
105     strcpy(mt->subfield_str, " $");
106     strcpy(mt->endline_str, "\n");
107
108     mt->nmem = nmem_create();
109     yaz_marc_reset(mt);
110     return mt;
111 }
112
113 void yaz_marc_destroy(yaz_marc_t mt)
114 {
115     if (!mt)
116         return ;
117     nmem_destroy(mt->nmem);
118     wrbuf_free(mt->m_wr, 1);
119     xfree(mt->leader_spec);
120     xfree(mt);
121 }
122
123 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
124 {
125     return mt->nmem;
126 }
127
128 static int marc_exec_leader(const char *leader_spec, char *leader,
129                             size_t size);
130
131
132 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
133 {
134     struct yaz_marc_node *n = nmem_malloc(mt->nmem, sizeof(*n));
135     n->next = 0;
136     *mt->nodes_pp = n;
137     mt->nodes_pp = &n->next;
138     return n;
139 }
140
141 #if YAZ_HAVE_XML2
142 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
143                                    const xmlNode *ptr_data)
144 {
145     struct yaz_marc_node *n = yaz_marc_add_node(mt);
146     n->which = YAZ_MARC_CONTROLFIELD;
147     n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
148     n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
149 }
150 #endif
151
152
153 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
154 {
155     struct yaz_marc_node *n = yaz_marc_add_node(mt);
156     n->which = YAZ_MARC_COMMENT;
157     n->u.comment = nmem_strdup(mt->nmem, comment);
158 }
159
160 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
161 {
162     va_list ap;
163     char buf[200];
164     va_start(ap, fmt);
165
166 #ifdef WIN32
167     _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
168 #else
169 /* !WIN32 */
170 #if HAVE_VSNPRINTF
171     vsnprintf(buf, sizeof(buf), fmt, ap);
172 #else
173     vsprintf(buf, fmt, ap);
174 #endif
175 #endif
176 /* WIN32 */
177     yaz_marc_add_comment(mt, buf);
178     va_end (ap);
179 }
180
181 int yaz_marc_get_debug(yaz_marc_t mt)
182 {
183     return mt->debug;
184 }
185
186 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
187 {
188     struct yaz_marc_node *n = yaz_marc_add_node(mt);
189     n->which = YAZ_MARC_LEADER;
190     n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
191     marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
192 }
193
194 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
195                                const char *data, size_t data_len)
196 {
197     struct yaz_marc_node *n = yaz_marc_add_node(mt);
198     n->which = YAZ_MARC_CONTROLFIELD;
199     n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
200     n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
201     if (mt->debug)
202     {
203         size_t i;
204         char msg[80];
205
206         sprintf(msg, "controlfield:");
207         for (i = 0; i < 16 && i < data_len; i++)
208             sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
209         if (i < data_len)
210             sprintf(msg + strlen(msg), " ..");
211         yaz_marc_add_comment(mt, msg);
212     }
213 }
214
215 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
216                             const char *indicator, size_t indicator_len)
217 {
218     struct yaz_marc_node *n = yaz_marc_add_node(mt);
219     n->which = YAZ_MARC_DATAFIELD;
220     n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
221     n->u.datafield.indicator =
222         nmem_strdupn(mt->nmem, indicator, indicator_len);
223     n->u.datafield.subfields = 0;
224
225     /* make subfield_pp the current (last one) */
226     mt->subfield_pp = &n->u.datafield.subfields;
227 }
228
229 #if YAZ_HAVE_XML2
230 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
231                                 const char *indicator, size_t indicator_len)
232 {
233     struct yaz_marc_node *n = yaz_marc_add_node(mt);
234     n->which = YAZ_MARC_DATAFIELD;
235     n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
236     n->u.datafield.indicator =
237         nmem_strdupn(mt->nmem, indicator, indicator_len);
238     n->u.datafield.subfields = 0;
239
240     /* make subfield_pp the current (last one) */
241     mt->subfield_pp = &n->u.datafield.subfields;
242 }
243 #endif
244
245 void yaz_marc_add_subfield(yaz_marc_t mt,
246                            const char *code_data, size_t code_data_len)
247 {
248     if (mt->debug)
249     {
250         size_t i;
251         char msg[80];
252
253         sprintf(msg, "subfield:");
254         for (i = 0; i < 16 && i < code_data_len; i++)
255             sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
256         if (i < code_data_len)
257             sprintf(msg + strlen(msg), " ..");
258         yaz_marc_add_comment(mt, msg);
259     }
260
261     if (mt->subfield_pp)
262     {
263         struct yaz_marc_subfield *n = nmem_malloc(mt->nmem, sizeof(*n));
264         n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
265         n->next = 0;
266         /* mark subfield_pp to point to this one, so we append here next */
267         *mt->subfield_pp = n;
268         mt->subfield_pp = &n->next;
269     }
270 }
271
272 int atoi_n_check(const char *buf, int size, int *val)
273 {
274     int i;
275     for (i = 0; i < size; i++)
276         if (!isdigit(i[(const unsigned char *) buf]))
277             return 0;
278     *val = atoi_n(buf, size);
279     return 1;
280 }
281
282 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
283                          int *indicator_length,
284                          int *identifier_length,
285                          int *base_address,
286                          int *length_data_entry,
287                          int *length_starting,
288                          int *length_implementation)
289 {
290     char leader[24];
291
292     memcpy(leader, leader_c, 24);
293
294     if (!atoi_n_check(leader+10, 1, indicator_length))
295     {
296         yaz_marc_cprintf(mt, 
297                          "Indicator length at offset 10 should hold a digit."
298                          " Assuming 2");
299         leader[10] = '2';
300         *indicator_length = 2;
301     }
302     if (!atoi_n_check(leader+11, 1, identifier_length))
303     {
304         yaz_marc_cprintf(mt, 
305                          "Identifier length at offset 11 should hold a digit."
306                          " Assuming 2");
307         leader[11] = '2';
308         *identifier_length = 2;
309     }
310     if (!atoi_n_check(leader+12, 5, base_address))
311     {
312         yaz_marc_cprintf(mt, 
313                          "Base address at offsets 12..16 should hold a number."
314                          " Assuming 0");
315         *base_address = 0;
316     }
317     if (!atoi_n_check(leader+20, 1, length_data_entry))
318     {
319         yaz_marc_cprintf(mt, 
320                          "Length data entry at offset 20 should hold a digit."
321                          " Assuming 4");
322         *length_data_entry = 4;
323         leader[20] = '4';
324     }
325     if (!atoi_n_check(leader+21, 1, length_starting))
326     {
327         yaz_marc_cprintf(mt,
328                          "Length starting at offset 21 should hold a digit."
329                          " Assuming 5");
330         *length_starting = 5;
331         leader[21] = '5';
332     }
333     if (!atoi_n_check(leader+22, 1, length_implementation))
334     {
335         yaz_marc_cprintf(mt, 
336                          "Length implementation at offset 22 should hold a digit."
337                          " Assuming 0");
338         *length_implementation = 0;
339         leader[22] = '0';
340     }
341
342     if (mt->debug)
343     {
344         yaz_marc_cprintf(mt, "Indicator length      %5d", *indicator_length);
345         yaz_marc_cprintf(mt, "Identifier length     %5d", *identifier_length);
346         yaz_marc_cprintf(mt, "Base address          %5d", *base_address);
347         yaz_marc_cprintf(mt, "Length data entry     %5d", *length_data_entry);
348         yaz_marc_cprintf(mt, "Length starting       %5d", *length_starting);
349         yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
350     }
351     yaz_marc_add_leader(mt, leader, 24);
352 }
353
354 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
355 {
356     strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
357     mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
358 }
359
360 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
361 {
362     strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
363     mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
364 }
365
366 /* try to guess how many bytes the identifier really is! */
367 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
368 {
369     if (mt->iconv_cd)
370     {
371         size_t i;
372         for (i = 1; i<5; i++)
373         {
374             char outbuf[12];
375             size_t outbytesleft = sizeof(outbuf);
376             char *outp = outbuf;
377             const char *inp = buf;
378
379             size_t inbytesleft = i;
380             size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
381                                  &outp, &outbytesleft);
382             if (r != (size_t) (-1))
383                 return i;  /* got a complete sequence */
384         }
385         return 1; /* giving up */
386     }
387     return 1; /* we don't know */
388 }
389                               
390 void yaz_marc_reset(yaz_marc_t mt)
391 {
392     nmem_reset(mt->nmem);
393     mt->nodes = 0;
394     mt->nodes_pp = &mt->nodes;
395     mt->subfield_pp = 0;
396 }
397
398 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
399 {
400     struct yaz_marc_node *n;
401     int identifier_length;
402     const char *leader = 0;
403
404     for (n = mt->nodes; n; n = n->next)
405         if (n->which == YAZ_MARC_LEADER)
406         {
407             leader = n->u.leader;
408             break;
409         }
410     
411     if (!leader)
412         return -1;
413     if (!atoi_n_check(leader+11, 1, &identifier_length))
414         return -1;
415
416     for (n = mt->nodes; n; n = n->next)
417     {
418         switch(n->which)
419         {
420         case YAZ_MARC_COMMENT:
421             wrbuf_iconv_write(wr, mt->iconv_cd, 
422                               n->u.comment, strlen(n->u.comment));
423             wrbuf_puts(wr, ")\n");
424             break;
425         default:
426             break;
427         }
428     }
429     return 0;
430 }
431
432
433 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
434 {
435     struct yaz_marc_node *n;
436     int identifier_length;
437     const char *leader = 0;
438
439     for (n = mt->nodes; n; n = n->next)
440         if (n->which == YAZ_MARC_LEADER)
441         {
442             leader = n->u.leader;
443             break;
444         }
445     
446     if (!leader)
447         return -1;
448     if (!atoi_n_check(leader+11, 1, &identifier_length))
449         return -1;
450
451     for (n = mt->nodes; n; n = n->next)
452     {
453         struct yaz_marc_subfield *s;
454         switch(n->which)
455         {
456         case YAZ_MARC_DATAFIELD:
457             wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
458                          n->u.datafield.indicator);
459             for (s = n->u.datafield.subfields; s; s = s->next)
460             {
461                 /* if identifier length is 2 (most MARCs),
462                    the code is a single character .. However we've
463                    seen multibyte codes, so see how big it really is */
464                 size_t using_code_len = 
465                     (identifier_length != 2) ? identifier_length - 1
466                     :
467                     cdata_one_character(mt, s->code_data);
468                 
469                 wrbuf_puts (wr, mt->subfield_str); 
470                 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data, 
471                                   using_code_len);
472                 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
473                 wrbuf_iconv_puts(wr, mt->iconv_cd, 
474                                  s->code_data + using_code_len);
475                 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
476                 wr->pos--;
477             }
478             wrbuf_puts (wr, mt->endline_str);
479             break;
480         case YAZ_MARC_CONTROLFIELD:
481             wrbuf_printf(wr, "%s", n->u.controlfield.tag);
482             wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
483             wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
484             wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
485             wr->pos--;
486             wrbuf_puts (wr, mt->endline_str);
487             break;
488         case YAZ_MARC_COMMENT:
489             wrbuf_puts(wr, "(");
490             wrbuf_iconv_write(wr, mt->iconv_cd, 
491                               n->u.comment, strlen(n->u.comment));
492             wrbuf_puts(wr, ")\n");
493             break;
494         case YAZ_MARC_LEADER:
495             wrbuf_printf(wr, "%s\n", n->u.leader);
496         }
497     }
498     wrbuf_puts(wr, "\n");
499     return 0;
500 }
501
502 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
503 {
504     switch(mt->xml)
505     {
506     case YAZ_MARC_LINE:
507         return yaz_marc_write_line(mt, wr);
508     case YAZ_MARC_MARCXML:
509         return yaz_marc_write_marcxml(mt, wr);
510     case YAZ_MARC_XCHANGE:
511         return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
512     case YAZ_MARC_ISO2709:
513         return yaz_marc_write_iso2709(mt, wr);
514     case YAZ_MARC_CHECK:
515         return yaz_marc_write_check(mt, wr);
516     }
517     return -1;
518 }
519
520 /** \brief common MARC XML/Xchange writer
521     \param mt handle
522     \param wr WRBUF output
523     \param ns XMLNS for the elements
524     \param format record format (e.g. "MARC21")
525     \param type record type (e.g. "Bibliographic")
526 */
527 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
528                                       const char *ns, 
529                                       const char *format,
530                                       const char *type)
531 {
532     struct yaz_marc_node *n;
533     int identifier_length;
534     const char *leader = 0;
535
536     for (n = mt->nodes; n; n = n->next)
537         if (n->which == YAZ_MARC_LEADER)
538         {
539             leader = n->u.leader;
540             break;
541         }
542     
543     if (!leader)
544         return -1;
545     if (!atoi_n_check(leader+11, 1, &identifier_length))
546         return -1;
547
548     wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
549     if (format)
550         wrbuf_printf(wr, " format=\"%.80s\"", format);
551     if (type)
552         wrbuf_printf(wr, " type=\"%.80s\"", type);
553     wrbuf_printf(wr, ">\n");
554     for (n = mt->nodes; n; n = n->next)
555     {
556         struct yaz_marc_subfield *s;
557
558         switch(n->which)
559         {
560         case YAZ_MARC_DATAFIELD:
561             wrbuf_printf(wr, "  <datafield tag=\"");
562             wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
563                                     strlen(n->u.datafield.tag));
564             wrbuf_printf(wr, "\"");
565             if (n->u.datafield.indicator)
566             {
567                 int i;
568                 for (i = 0; n->u.datafield.indicator[i]; i++)
569                 {
570                     wrbuf_printf(wr, " ind%d=\"", i+1);
571                     wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
572                                           n->u.datafield.indicator+i, 1);
573                     wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
574                 }
575             }
576             wrbuf_printf(wr, ">\n");
577             for (s = n->u.datafield.subfields; s; s = s->next)
578             {
579                 /* if identifier length is 2 (most MARCs),
580                    the code is a single character .. However we've
581                    seen multibyte codes, so see how big it really is */
582                 size_t using_code_len = 
583                     (identifier_length != 2) ? identifier_length - 1
584                     :
585                     cdata_one_character(mt, s->code_data);
586                 
587                 wrbuf_iconv_puts(wr, mt->iconv_cd, "    <subfield code=\"");
588                 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
589                                         s->code_data, using_code_len);
590                 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
591                 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
592                                         s->code_data + using_code_len,
593                                         strlen(s->code_data + using_code_len));
594                 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
595                 wrbuf_puts(wr, "\n");
596             }
597             wrbuf_printf(wr, "  </datafield>\n");
598             break;
599         case YAZ_MARC_CONTROLFIELD:
600             wrbuf_printf(wr, "  <controlfield tag=\"");
601             wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
602                                     strlen(n->u.controlfield.tag));
603             wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
604             wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
605             wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
606             wrbuf_puts(wr, "\n");
607             break;
608         case YAZ_MARC_COMMENT:
609             wrbuf_printf(wr, "<!-- ");
610             wrbuf_puts(wr, n->u.comment);
611             wrbuf_printf(wr, " -->\n");
612             break;
613         case YAZ_MARC_LEADER:
614             wrbuf_printf(wr, "  <leader>");
615             wrbuf_iconv_write_cdata(wr, 
616                                     0 /* no charset conversion for leader */,
617                                     n->u.leader, strlen(n->u.leader));
618             wrbuf_printf(wr, "</leader>\n");
619         }
620     }
621     wrbuf_puts(wr, "</record>\n");
622     return 0;
623 }
624
625 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
626                                      const char *ns, 
627                                      const char *format,
628                                      const char *type)
629 {
630     if (mt->write_using_libxml2)
631     {
632         int ret;
633         xmlNode *root_ptr;
634
635         ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
636         if (ret == 0)
637         {
638             xmlChar *buf_out;
639             xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
640             int len_out;
641
642             xmlDocSetRootElement(doc, root_ptr);
643             xmlDocDumpMemory(doc, &buf_out, &len_out);
644
645             wrbuf_write(wr, (const char *) buf_out, len_out);
646             wrbuf_puts(wr, "");
647             xmlFree(buf_out);
648             xmlFreeDoc(doc);
649         }
650         return ret;
651     }
652     else
653         return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
654 }
655
656 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
657 {
658     if (!mt->leader_spec)
659         yaz_marc_modify_leader(mt, 9, "a");
660     return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
661                                      0, 0);
662 }
663
664 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
665                                const char *format,
666                                const char *type)
667 {
668     return yaz_marc_write_marcxml_ns(mt, wr,
669                                      "http://www.bs.dk/standards/MarcXchange",
670                                      0, 0);
671 }
672
673
674 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
675                        const char *ns, 
676                        const char *format,
677                        const char *type)
678 {
679 #if YAZ_HAVE_XML2
680     struct yaz_marc_node *n;
681     int identifier_length;
682     const char *leader = 0;
683     xmlNode *record_ptr;
684     xmlNsPtr ns_record;
685
686     for (n = mt->nodes; n; n = n->next)
687         if (n->which == YAZ_MARC_LEADER)
688         {
689             leader = n->u.leader;
690             break;
691         }
692     
693     if (!leader)
694         return -1;
695     if (!atoi_n_check(leader+11, 1, &identifier_length))
696         return -1;
697
698     record_ptr = xmlNewNode(0, BAD_CAST "record");
699     *root_ptr = record_ptr;
700
701     ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
702
703     if (format)
704         xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
705     if (type)
706         xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
707     for (n = mt->nodes; n; n = n->next)
708     {
709         struct yaz_marc_subfield *s;
710         xmlNode *ptr;
711
712         switch(n->which)
713         {
714         case YAZ_MARC_DATAFIELD:
715             ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
716             xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
717             if (n->u.datafield.indicator)
718             {
719                 int i;
720                 for (i = 0; n->u.datafield.indicator[i]; i++)
721                 {
722                     char ind_str[6];
723                     char ind_val[2];
724
725                     sprintf(ind_str, "ind%d", i+1);
726                     ind_val[0] = n->u.datafield.indicator[i];
727                     ind_val[1] = '\0';
728                     xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
729                 }
730             }
731             for (s = n->u.datafield.subfields; s; s = s->next)
732             {
733                 char code_val[8];
734
735                 xmlNode *ptr_subfield;
736                 /* if identifier length is 2 (most MARCs),
737                    the code is a single character .. However we've
738                    seen multibyte codes, so see how big it really is */
739                 size_t using_code_len = 
740                     (identifier_length != 2) ? identifier_length - 1
741                     :
742                     cdata_one_character(mt, s->code_data);
743
744                 if (using_code_len >= sizeof(code_val)-1)
745                     continue;
746
747                 ptr_subfield = xmlNewTextChild(
748                     ptr, ns_record, 
749                     BAD_CAST "subfield", 
750                     BAD_CAST (s->code_data + using_code_len));
751                 
752                 memcpy(code_val, s->code_data, using_code_len);
753                 code_val[using_code_len] = '\0';
754
755                 xmlNewProp(ptr_subfield, BAD_CAST "code", BAD_CAST code_val);
756             }
757             break;
758         case YAZ_MARC_CONTROLFIELD:
759             ptr = xmlNewTextChild(record_ptr, ns_record,
760                                   BAD_CAST "controlfield",
761                                   BAD_CAST n->u.controlfield.data);
762             
763             xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
764             break;
765         case YAZ_MARC_COMMENT:
766             ptr = xmlNewComment(BAD_CAST n->u.comment);
767             xmlAddChild(record_ptr, ptr);
768             break;
769         case YAZ_MARC_LEADER:
770             xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
771                             BAD_CAST n->u.leader);
772             break;
773         }
774     }
775     return 0;
776 #else
777     return -1;
778 #endif
779 }
780
781 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
782 {
783     struct yaz_marc_node *n;
784     int indicator_length;
785     int identifier_length;
786     int length_data_entry;
787     int length_starting;
788     int length_implementation;
789     int data_offset = 0;
790     const char *leader = 0;
791     WRBUF wr_dir, wr_head, wr_data_tmp;
792     int base_address;
793     
794     for (n = mt->nodes; n; n = n->next)
795         if (n->which == YAZ_MARC_LEADER)
796             leader = n->u.leader;
797     
798     if (!leader)
799         return -1;
800     if (!atoi_n_check(leader+10, 1, &indicator_length))
801         return -1;
802     if (!atoi_n_check(leader+11, 1, &identifier_length))
803         return -1;
804     if (!atoi_n_check(leader+20, 1, &length_data_entry))
805         return -1;
806     if (!atoi_n_check(leader+21, 1, &length_starting))
807         return -1;
808     if (!atoi_n_check(leader+22, 1, &length_implementation))
809         return -1;
810
811     wr_data_tmp = wrbuf_alloc();
812     wr_dir = wrbuf_alloc();
813     for (n = mt->nodes; n; n = n->next)
814     {
815         int data_length = 0;
816         struct yaz_marc_subfield *s;
817
818         switch(n->which)
819         {
820         case YAZ_MARC_DATAFIELD:
821             wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
822             data_length += indicator_length;
823             wrbuf_rewind(wr_data_tmp);
824             for (s = n->u.datafield.subfields; s; s = s->next)
825             {
826                 /* write dummy IDFS + content */
827                 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
828                 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
829             }
830             /* write dummy FS (makes MARC-8 to become ASCII) */
831             wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
832             data_length += wrbuf_len(wr_data_tmp);
833             break;
834         case YAZ_MARC_CONTROLFIELD:
835             wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
836
837             wrbuf_rewind(wr_data_tmp);
838             wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, 
839                              n->u.controlfield.data);
840             wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
841             data_length += wrbuf_len(wr_data_tmp);
842             break;
843         case YAZ_MARC_COMMENT:
844             break;
845         case YAZ_MARC_LEADER:
846             break;
847         }
848         if (data_length)
849         {
850             wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
851             wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
852             data_offset += data_length;
853         }
854     }
855     /* mark end of directory */
856     wrbuf_putc(wr_dir, ISO2709_FS);
857
858     /* base address of data (comes after leader+directory) */
859     base_address = 24 + wrbuf_len(wr_dir);
860
861     wr_head = wrbuf_alloc();
862
863     /* write record length */
864     wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
865     /* from "original" leader */
866     wrbuf_write(wr_head, leader+5, 7);
867     /* base address of data */
868     wrbuf_printf(wr_head, "%05d", base_address);
869     /* from "original" leader */
870     wrbuf_write(wr_head, leader+17, 7);
871     
872     wrbuf_write(wr, wrbuf_buf(wr_head), 24);
873     wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
874     wrbuf_free(wr_head, 1);
875     wrbuf_free(wr_dir, 1);
876     wrbuf_free(wr_data_tmp, 1);
877
878     for (n = mt->nodes; n; n = n->next)
879     {
880         struct yaz_marc_subfield *s;
881
882         switch(n->which)
883         {
884         case YAZ_MARC_DATAFIELD:
885             wrbuf_printf(wr, "%.*s", indicator_length,
886                          n->u.datafield.indicator);
887             for (s = n->u.datafield.subfields; s; s = s->next)
888             {
889                 wrbuf_putc(wr, ISO2709_IDFS);
890                 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
891                 /* write dummy blank - makes MARC-8 to become ASCII */
892                 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
893                 wr->pos--;
894             }
895             wrbuf_putc(wr, ISO2709_FS);
896             break;
897         case YAZ_MARC_CONTROLFIELD:
898             wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
899             /* write dummy blank - makes MARC-8 to become ASCII */
900             wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
901             wr->pos--;
902             wrbuf_putc(wr, ISO2709_FS);
903             break;
904         case YAZ_MARC_COMMENT:
905             break;
906         case YAZ_MARC_LEADER:
907             break;
908         }
909     }
910     wrbuf_printf(wr, "%c", ISO2709_RS);
911     return 0;
912 }
913
914
915 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
916 {
917     int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
918     if (r <= 0)
919         return r;
920     s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
921     if (s != 0)
922         return -1; /* error */
923     return r; /* OK, return length > 0 */
924 }
925
926 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
927                          char **result, int *rsize)
928 {
929     int r;
930
931     wrbuf_rewind(mt->m_wr);
932     r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
933     if (result)
934         *result = wrbuf_buf(mt->m_wr);
935     if (rsize)
936         *rsize = wrbuf_len(mt->m_wr);
937     return r;
938 }
939
940 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
941 {
942     if (mt)
943         mt->xml = xmlmode;
944 }
945
946 void yaz_marc_debug(yaz_marc_t mt, int level)
947 {
948     if (mt)
949         mt->debug = level;
950 }
951
952 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
953 {
954     mt->iconv_cd = cd;
955 }
956
957 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
958 {
959     struct yaz_marc_node *n;
960     char *leader = 0;
961     for (n = mt->nodes; n; n = n->next)
962         if (n->which == YAZ_MARC_LEADER)
963         {
964             leader = n->u.leader;
965             memcpy(leader+off, str, strlen(str));
966             break;
967         }
968 }
969
970 /* deprecated */
971 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
972 {
973     yaz_marc_t mt = yaz_marc_create();
974     int r;
975
976     mt->debug = debug;
977     mt->xml = xml;
978     r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
979     yaz_marc_destroy(mt);
980     return r;
981 }
982
983 /* deprecated */
984 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
985 {
986     return yaz_marc_decode(buf, wr, debug, bsize, 0);
987 }
988
989 /* deprecated */
990 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
991 {
992     yaz_marc_t mt = yaz_marc_create();
993     int r;
994
995     mt->debug = debug;
996     r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
997     if (!outf)
998         outf = stdout;
999     if (r > 0)
1000         fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1001     yaz_marc_destroy(mt);
1002     return r;
1003 }
1004
1005 /* deprecated */
1006 int marc_display_ex (const char *buf, FILE *outf, int debug)
1007 {
1008     return marc_display_exl (buf, outf, debug, -1);
1009 }
1010
1011 /* deprecated */
1012 int marc_display (const char *buf, FILE *outf)
1013 {
1014     return marc_display_ex (buf, outf, 0);
1015 }
1016
1017 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1018 {
1019     xfree(mt->leader_spec);
1020     mt->leader_spec = 0;
1021     if (leader_spec)
1022     {
1023         char dummy_leader[24];
1024         if (marc_exec_leader(leader_spec, dummy_leader, 24))
1025             return -1;
1026         mt->leader_spec = xstrdup(leader_spec);
1027     }
1028     return 0;
1029 }
1030
1031 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1032 {
1033     const char *cp = leader_spec;
1034     while (cp)
1035     {
1036         char val[21];
1037         int pos;
1038         int no_read = 0, no = 0;
1039
1040         no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1041         if (no < 2 || no_read < 3)
1042             return -1;
1043         if (pos < 0 || pos >= size)
1044             return -1;
1045
1046         if (*val == '\'')
1047         {
1048             const char *vp = strchr(val+1, '\'');
1049             size_t len;
1050             
1051             if (!vp)
1052                 return -1;
1053             len = vp-val-1;
1054             if (len + pos > size)
1055                 return -1;
1056             memcpy(leader + pos, val+1, len);
1057         }
1058         else if (*val >= '0' && *val <= '9')
1059         {
1060             int ch = atoi(val);
1061             leader[pos] = ch;
1062         }
1063         else
1064             return -1;
1065         cp += no_read;
1066         if (*cp != ',')
1067             break;
1068
1069         cp++;
1070     }
1071     return 0;
1072 }
1073
1074 int yaz_marc_decode_formatstr(const char *arg)
1075 {
1076     int mode = -1; 
1077     if (!strcmp(arg, "marc"))
1078         mode = YAZ_MARC_ISO2709;
1079     if (!strcmp(arg, "marcxml"))
1080         mode = YAZ_MARC_MARCXML;
1081     if (!strcmp(arg, "marcxchange"))
1082         mode = YAZ_MARC_XCHANGE;
1083     if (!strcmp(arg, "line"))
1084         mode = YAZ_MARC_LINE;
1085     return mode;
1086 }
1087
1088 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1089 {
1090     mt->write_using_libxml2 = enable;
1091 }
1092
1093 /*
1094  * Local variables:
1095  * c-basic-offset: 4
1096  * indent-tabs-mode: nil
1097  * End:
1098  * vim: shiftwidth=4 tabstop=8 expandtab
1099  */
1100