Fixed bug #797: yaz_marc_write_xml does not honor character conversion.
[yaz-moved-to-github.git] / src / marcdisp.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: marcdisp.c,v 1.43 2007-01-06 16:08:04 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     WRBUF wr_cdata = 0;
686
687     for (n = mt->nodes; n; n = n->next)
688         if (n->which == YAZ_MARC_LEADER)
689         {
690             leader = n->u.leader;
691             break;
692         }
693     
694     if (!leader)
695         return -1;
696     if (!atoi_n_check(leader+11, 1, &identifier_length))
697         return -1;
698
699     wr_cdata = wrbuf_alloc();
700
701     record_ptr = xmlNewNode(0, BAD_CAST "record");
702     *root_ptr = record_ptr;
703
704     ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
705     xmlSetNs(record_ptr, ns_record);
706
707     if (format)
708         xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
709     if (type)
710         xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
711     for (n = mt->nodes; n; n = n->next)
712     {
713         struct yaz_marc_subfield *s;
714         xmlNode *ptr;
715
716         switch(n->which)
717         {
718         case YAZ_MARC_DATAFIELD:
719             ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
720             xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
721             if (n->u.datafield.indicator)
722             {
723                 int i;
724                 for (i = 0; n->u.datafield.indicator[i]; i++)
725                 {
726                     char ind_str[6];
727                     char ind_val[2];
728
729                     sprintf(ind_str, "ind%d", i+1);
730                     ind_val[0] = n->u.datafield.indicator[i];
731                     ind_val[1] = '\0';
732                     xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
733                 }
734             }
735             for (s = n->u.datafield.subfields; s; s = s->next)
736             {
737                 xmlNode *ptr_subfield;
738                 /* if identifier length is 2 (most MARCs),
739                    the code is a single character .. However we've
740                    seen multibyte codes, so see how big it really is */
741                 size_t using_code_len = 
742                     (identifier_length != 2) ? identifier_length - 1
743                     :
744                     cdata_one_character(mt, s->code_data);
745
746                 wrbuf_rewind(wr_cdata);
747                 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
748                                  s->code_data + using_code_len);
749
750                 ptr_subfield = xmlNewTextChild(
751                     ptr, ns_record, 
752                     BAD_CAST "subfield",  BAD_CAST wrbuf_cstr(wr_cdata));
753
754                 wrbuf_rewind(wr_cdata);
755                 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
756                                   s->code_data, using_code_len);
757                 xmlNewProp(ptr_subfield, BAD_CAST "code",
758                            BAD_CAST wrbuf_cstr(wr_cdata));
759             }
760             break;
761         case YAZ_MARC_CONTROLFIELD:
762             wrbuf_rewind(wr_cdata);
763             wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
764
765             ptr = xmlNewTextChild(record_ptr, ns_record,
766                                   BAD_CAST "controlfield",
767                                   BAD_CAST wrbuf_cstr(wr_cdata));
768             
769             xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
770             break;
771         case YAZ_MARC_COMMENT:
772             ptr = xmlNewComment(BAD_CAST n->u.comment);
773             xmlAddChild(record_ptr, ptr);
774             break;
775         case YAZ_MARC_LEADER:
776             xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
777                             BAD_CAST n->u.leader);
778             break;
779         }
780     }
781     wrbuf_destroy(wr_cdata);
782     return 0;
783 #else
784     return -1;
785 #endif
786 }
787
788 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
789 {
790     struct yaz_marc_node *n;
791     int indicator_length;
792     int identifier_length;
793     int length_data_entry;
794     int length_starting;
795     int length_implementation;
796     int data_offset = 0;
797     const char *leader = 0;
798     WRBUF wr_dir, wr_head, wr_data_tmp;
799     int base_address;
800     
801     for (n = mt->nodes; n; n = n->next)
802         if (n->which == YAZ_MARC_LEADER)
803             leader = n->u.leader;
804     
805     if (!leader)
806         return -1;
807     if (!atoi_n_check(leader+10, 1, &indicator_length))
808         return -1;
809     if (!atoi_n_check(leader+11, 1, &identifier_length))
810         return -1;
811     if (!atoi_n_check(leader+20, 1, &length_data_entry))
812         return -1;
813     if (!atoi_n_check(leader+21, 1, &length_starting))
814         return -1;
815     if (!atoi_n_check(leader+22, 1, &length_implementation))
816         return -1;
817
818     wr_data_tmp = wrbuf_alloc();
819     wr_dir = wrbuf_alloc();
820     for (n = mt->nodes; n; n = n->next)
821     {
822         int data_length = 0;
823         struct yaz_marc_subfield *s;
824
825         switch(n->which)
826         {
827         case YAZ_MARC_DATAFIELD:
828             wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
829             data_length += indicator_length;
830             wrbuf_rewind(wr_data_tmp);
831             for (s = n->u.datafield.subfields; s; s = s->next)
832             {
833                 /* write dummy IDFS + content */
834                 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
835                 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
836             }
837             /* write dummy FS (makes MARC-8 to become ASCII) */
838             wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
839             data_length += wrbuf_len(wr_data_tmp);
840             break;
841         case YAZ_MARC_CONTROLFIELD:
842             wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
843
844             wrbuf_rewind(wr_data_tmp);
845             wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, 
846                              n->u.controlfield.data);
847             wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
848             data_length += wrbuf_len(wr_data_tmp);
849             break;
850         case YAZ_MARC_COMMENT:
851             break;
852         case YAZ_MARC_LEADER:
853             break;
854         }
855         if (data_length)
856         {
857             wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
858             wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
859             data_offset += data_length;
860         }
861     }
862     /* mark end of directory */
863     wrbuf_putc(wr_dir, ISO2709_FS);
864
865     /* base address of data (comes after leader+directory) */
866     base_address = 24 + wrbuf_len(wr_dir);
867
868     wr_head = wrbuf_alloc();
869
870     /* write record length */
871     wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
872     /* from "original" leader */
873     wrbuf_write(wr_head, leader+5, 7);
874     /* base address of data */
875     wrbuf_printf(wr_head, "%05d", base_address);
876     /* from "original" leader */
877     wrbuf_write(wr_head, leader+17, 7);
878     
879     wrbuf_write(wr, wrbuf_buf(wr_head), 24);
880     wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
881     wrbuf_free(wr_head, 1);
882     wrbuf_free(wr_dir, 1);
883     wrbuf_free(wr_data_tmp, 1);
884
885     for (n = mt->nodes; n; n = n->next)
886     {
887         struct yaz_marc_subfield *s;
888
889         switch(n->which)
890         {
891         case YAZ_MARC_DATAFIELD:
892             wrbuf_printf(wr, "%.*s", indicator_length,
893                          n->u.datafield.indicator);
894             for (s = n->u.datafield.subfields; s; s = s->next)
895             {
896                 wrbuf_putc(wr, ISO2709_IDFS);
897                 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
898                 /* write dummy blank - makes MARC-8 to become ASCII */
899                 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
900                 wr->pos--;
901             }
902             wrbuf_putc(wr, ISO2709_FS);
903             break;
904         case YAZ_MARC_CONTROLFIELD:
905             wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
906             /* write dummy blank - makes MARC-8 to become ASCII */
907             wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
908             wr->pos--;
909             wrbuf_putc(wr, ISO2709_FS);
910             break;
911         case YAZ_MARC_COMMENT:
912             break;
913         case YAZ_MARC_LEADER:
914             break;
915         }
916     }
917     wrbuf_printf(wr, "%c", ISO2709_RS);
918     return 0;
919 }
920
921
922 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
923 {
924     int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
925     if (r <= 0)
926         return r;
927     s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
928     if (s != 0)
929         return -1; /* error */
930     return r; /* OK, return length > 0 */
931 }
932
933 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
934                          char **result, int *rsize)
935 {
936     int r;
937
938     wrbuf_rewind(mt->m_wr);
939     r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
940     if (result)
941         *result = wrbuf_buf(mt->m_wr);
942     if (rsize)
943         *rsize = wrbuf_len(mt->m_wr);
944     return r;
945 }
946
947 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
948 {
949     if (mt)
950         mt->xml = xmlmode;
951 }
952
953 void yaz_marc_debug(yaz_marc_t mt, int level)
954 {
955     if (mt)
956         mt->debug = level;
957 }
958
959 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
960 {
961     mt->iconv_cd = cd;
962 }
963
964 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
965 {
966     struct yaz_marc_node *n;
967     char *leader = 0;
968     for (n = mt->nodes; n; n = n->next)
969         if (n->which == YAZ_MARC_LEADER)
970         {
971             leader = n->u.leader;
972             memcpy(leader+off, str, strlen(str));
973             break;
974         }
975 }
976
977 /* deprecated */
978 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
979 {
980     yaz_marc_t mt = yaz_marc_create();
981     int r;
982
983     mt->debug = debug;
984     mt->xml = xml;
985     r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
986     yaz_marc_destroy(mt);
987     return r;
988 }
989
990 /* deprecated */
991 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
992 {
993     return yaz_marc_decode(buf, wr, debug, bsize, 0);
994 }
995
996 /* deprecated */
997 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
998 {
999     yaz_marc_t mt = yaz_marc_create();
1000     int r;
1001
1002     mt->debug = debug;
1003     r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
1004     if (!outf)
1005         outf = stdout;
1006     if (r > 0)
1007         fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1008     yaz_marc_destroy(mt);
1009     return r;
1010 }
1011
1012 /* deprecated */
1013 int marc_display_ex (const char *buf, FILE *outf, int debug)
1014 {
1015     return marc_display_exl (buf, outf, debug, -1);
1016 }
1017
1018 /* deprecated */
1019 int marc_display (const char *buf, FILE *outf)
1020 {
1021     return marc_display_ex (buf, outf, 0);
1022 }
1023
1024 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1025 {
1026     xfree(mt->leader_spec);
1027     mt->leader_spec = 0;
1028     if (leader_spec)
1029     {
1030         char dummy_leader[24];
1031         if (marc_exec_leader(leader_spec, dummy_leader, 24))
1032             return -1;
1033         mt->leader_spec = xstrdup(leader_spec);
1034     }
1035     return 0;
1036 }
1037
1038 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1039 {
1040     const char *cp = leader_spec;
1041     while (cp)
1042     {
1043         char val[21];
1044         int pos;
1045         int no_read = 0, no = 0;
1046
1047         no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1048         if (no < 2 || no_read < 3)
1049             return -1;
1050         if (pos < 0 || pos >= size)
1051             return -1;
1052
1053         if (*val == '\'')
1054         {
1055             const char *vp = strchr(val+1, '\'');
1056             size_t len;
1057             
1058             if (!vp)
1059                 return -1;
1060             len = vp-val-1;
1061             if (len + pos > size)
1062                 return -1;
1063             memcpy(leader + pos, val+1, len);
1064         }
1065         else if (*val >= '0' && *val <= '9')
1066         {
1067             int ch = atoi(val);
1068             leader[pos] = ch;
1069         }
1070         else
1071             return -1;
1072         cp += no_read;
1073         if (*cp != ',')
1074             break;
1075
1076         cp++;
1077     }
1078     return 0;
1079 }
1080
1081 int yaz_marc_decode_formatstr(const char *arg)
1082 {
1083     int mode = -1; 
1084     if (!strcmp(arg, "marc"))
1085         mode = YAZ_MARC_ISO2709;
1086     if (!strcmp(arg, "marcxml"))
1087         mode = YAZ_MARC_MARCXML;
1088     if (!strcmp(arg, "marcxchange"))
1089         mode = YAZ_MARC_XCHANGE;
1090     if (!strcmp(arg, "line"))
1091         mode = YAZ_MARC_LINE;
1092     return mode;
1093 }
1094
1095 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1096 {
1097     mt->write_using_libxml2 = enable;
1098 }
1099
1100 /*
1101  * Local variables:
1102  * c-basic-offset: 4
1103  * indent-tabs-mode: nil
1104  * End:
1105  * vim: shiftwidth=4 tabstop=8 expandtab
1106  */
1107