53d4e81eeefa87e8f8d1eca91daa3d8246aec72b
[yaz-moved-to-github.git] / src / marcdisp.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file marcdisp.c
8  * \brief Implements MARC conversion utilities
9  */
10
11 #if HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #ifdef WIN32
16 #include <windows.h>
17 #endif
18
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <yaz/marcdisp.h>
25 #include <yaz/wrbuf.h>
26 #include <yaz/yaz-util.h>
27 #include <yaz/nmem_xml.h>
28 #include <yaz/snprintf.h>
29
30 #if YAZ_HAVE_XML2
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #endif
34
35 enum yaz_collection_state {
36     no_collection,
37     collection_first,
38     collection_second
39 };
40    
41 /** \brief node types for yaz_marc_node */
42 enum YAZ_MARC_NODE_TYPE
43
44     YAZ_MARC_DATAFIELD,
45     YAZ_MARC_CONTROLFIELD,
46     YAZ_MARC_COMMENT,
47     YAZ_MARC_LEADER
48 };
49
50 /** \brief represets a data field */
51 struct yaz_marc_datafield {
52     char *tag;
53     char *indicator;
54     struct yaz_marc_subfield *subfields;
55 };
56
57 /** \brief represents a control field */
58 struct yaz_marc_controlfield {
59     char *tag;
60     char *data;
61 };
62
63 /** \brief a comment node */
64 struct yaz_marc_comment {
65     char *comment;
66 };
67
68 /** \brief MARC node */
69 struct yaz_marc_node {
70     enum YAZ_MARC_NODE_TYPE which;
71     union {
72         struct yaz_marc_datafield datafield;
73         struct yaz_marc_controlfield controlfield;
74         char *comment;
75         char *leader;
76     } u;
77     struct yaz_marc_node *next;
78 };
79
80 /** \brief represents a subfield */
81 struct yaz_marc_subfield {
82     char *code_data;
83     struct yaz_marc_subfield *next;
84 };
85
86 /** \brief the internals of a yaz_marc_t handle */
87 struct yaz_marc_t_ {
88     WRBUF m_wr;
89     NMEM nmem;
90     int input_format;
91     int output_format;
92     int debug;
93     int write_using_libxml2;
94     enum yaz_collection_state enable_collection;
95     yaz_iconv_t iconv_cd;
96     char subfield_str[8];
97     char endline_str[8];
98     char *leader_spec;
99     struct yaz_marc_node *nodes;
100     struct yaz_marc_node **nodes_pp;
101     struct yaz_marc_subfield **subfield_pp;
102 };
103
104 yaz_marc_t yaz_marc_create(void)
105 {
106     yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
107     mt->output_format = YAZ_MARC_LINE;
108     mt->debug = 0;
109     mt->write_using_libxml2 = 0;
110     mt->enable_collection = no_collection;
111     mt->m_wr = wrbuf_alloc();
112     mt->iconv_cd = 0;
113     mt->leader_spec = 0;
114     strcpy(mt->subfield_str, " $");
115     strcpy(mt->endline_str, "\n");
116
117     mt->nmem = nmem_create();
118     yaz_marc_reset(mt);
119     return mt;
120 }
121
122 void yaz_marc_destroy(yaz_marc_t mt)
123 {
124     if (!mt)
125         return ;
126     nmem_destroy(mt->nmem);
127     wrbuf_destroy(mt->m_wr);
128     xfree(mt->leader_spec);
129     xfree(mt);
130 }
131
132 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
133 {
134     return mt->nmem;
135 }
136
137 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
138 {
139     wrbuf_iconv_reset(wr, mt->iconv_cd);
140 }
141
142 static int marc_exec_leader(const char *leader_spec, char *leader,
143                             size_t size);
144
145
146 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
147 {
148     struct yaz_marc_node *n = (struct yaz_marc_node *)
149         nmem_malloc(mt->nmem, sizeof(*n));
150     n->next = 0;
151     *mt->nodes_pp = n;
152     mt->nodes_pp = &n->next;
153     return n;
154 }
155
156 #if YAZ_HAVE_XML2
157 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
158                                    const xmlNode *ptr_data)
159 {
160     struct yaz_marc_node *n = yaz_marc_add_node(mt);
161     n->which = YAZ_MARC_CONTROLFIELD;
162     n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
163     n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
164 }
165
166 void yaz_marc_add_controlfield_turbo_xml(yaz_marc_t mt, char *tag,
167                                    const xmlNode *ptr_data)
168 {
169     struct yaz_marc_node *n = yaz_marc_add_node(mt);
170     n->which = YAZ_MARC_CONTROLFIELD;
171     n->u.controlfield.tag = tag;
172     n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
173 }
174
175 #endif
176
177
178 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
179 {
180     struct yaz_marc_node *n = yaz_marc_add_node(mt);
181     n->which = YAZ_MARC_COMMENT;
182     n->u.comment = nmem_strdup(mt->nmem, comment);
183 }
184
185 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
186 {
187     va_list ap;
188     char buf[200];
189
190     va_start(ap, fmt);
191     yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
192     yaz_marc_add_comment(mt, buf);
193     va_end (ap);
194 }
195
196 int yaz_marc_get_debug(yaz_marc_t mt)
197 {
198     return mt->debug;
199 }
200
201 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
202 {
203     struct yaz_marc_node *n = yaz_marc_add_node(mt);
204     n->which = YAZ_MARC_LEADER;
205     n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
206     marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
207 }
208
209 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
210                                const char *data, size_t data_len)
211 {
212     struct yaz_marc_node *n = yaz_marc_add_node(mt);
213     n->which = YAZ_MARC_CONTROLFIELD;
214     n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
215     n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
216     if (mt->debug)
217     {
218         size_t i;
219         char msg[80];
220
221         sprintf(msg, "controlfield:");
222         for (i = 0; i < 16 && i < data_len; i++)
223             sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
224         if (i < data_len)
225             sprintf(msg + strlen(msg), " ..");
226         yaz_marc_add_comment(mt, msg);
227     }
228 }
229
230 void yaz_marc_add_datafield(yaz_marc_t mt, const char *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_strdup(mt->nmem, tag);
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
244 char *element_name_encode(yaz_marc_t mt, WRBUF buffer, char *code_data, size_t code_len) {
245         // TODO Map special codes to something possible for XML ELEMENT names
246
247         int encode = 0;
248         int index = 0;
249         for (index = 0; index < code_len; index++) {
250                 if (!((code_data[index] >= '0' && code_data[index] <= '9') ||
251                           (code_data[index] >= 'a' && code_data[index] <= 'z') ||
252                           (code_data[index] >= 'A' && code_data[index] <= 'Z')))
253                         encode = 1;
254         }
255         if (!encode) {
256                 wrbuf_iconv_write(buffer, mt->iconv_cd, code_data, code_len);
257         }
258         else {
259                 char temp[2*code_len + 1];
260                 wrbuf_puts(buffer, "-");
261                 int index;
262                 for (index = 0; index < code_len; index++) {
263                         sprintf(temp, "%02X", (unsigned char) code_data[index] & 0xFF);
264                         temp[2] = 0;
265                         wrbuf_puts(buffer, temp);
266                 };
267                 yaz_log(YLOG_WARN, "Using numeric value in element name: %s", wrbuf_cstr(buffer));
268         }
269 }
270
271 #if YAZ_HAVE_XML2
272 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
273                                 const char *indicator, size_t indicator_len)
274 {
275     struct yaz_marc_node *n = yaz_marc_add_node(mt);
276     n->which = YAZ_MARC_DATAFIELD;
277     n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
278     n->u.datafield.indicator =
279         nmem_strdupn(mt->nmem, indicator, indicator_len);
280     n->u.datafield.subfields = 0;
281
282     /* make subfield_pp the current (last one) */
283     mt->subfield_pp = &n->u.datafield.subfields;
284 }
285
286 struct yaz_marc_node* yaz_marc_add_datafield_turbo_xml(yaz_marc_t mt, char *tag_value)
287 {
288     struct yaz_marc_node *n = yaz_marc_add_node(mt);
289     n->which = YAZ_MARC_DATAFIELD;
290     n->u.datafield.tag = tag_value;
291     n->u.datafield.indicator = 0;
292     n->u.datafield.subfields = 0;
293
294     /* make subfield_pp the current (last one) */
295     mt->subfield_pp = &n->u.datafield.subfields;
296     return n;
297 }
298
299 void yaz_marc_datafield_set_indicators(struct yaz_marc_node *n, char *indicator)
300 {
301     n->u.datafield.indicator = indicator;
302 }
303
304 #endif
305
306 void yaz_marc_add_subfield(yaz_marc_t mt,
307                            const char *code_data, size_t code_data_len)
308 {
309     if (mt->debug)
310     {
311         size_t i;
312         char msg[80];
313
314         sprintf(msg, "subfield:");
315         for (i = 0; i < 16 && i < code_data_len; i++)
316             sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
317         if (i < code_data_len)
318             sprintf(msg + strlen(msg), " ..");
319         yaz_marc_add_comment(mt, msg);
320     }
321
322     if (mt->subfield_pp)
323     {
324         struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
325             nmem_malloc(mt->nmem, sizeof(*n));
326         n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
327         n->next = 0;
328         /* mark subfield_pp to point to this one, so we append here next */
329         *mt->subfield_pp = n;
330         mt->subfield_pp = &n->next;
331     }
332 }
333
334 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
335                          int *indicator_length,
336                          int *identifier_length,
337                          int *base_address,
338                          int *length_data_entry,
339                          int *length_starting,
340                          int *length_implementation)
341 {
342     char leader[24];
343
344     memcpy(leader, leader_c, 24);
345
346     if (!atoi_n_check(leader+10, 1, indicator_length))
347     {
348         yaz_marc_cprintf(mt, 
349                          "Indicator length at offset 10 should hold a digit."
350                          " Assuming 2");
351         leader[10] = '2';
352         *indicator_length = 2;
353     }
354     if (!atoi_n_check(leader+11, 1, identifier_length))
355     {
356         yaz_marc_cprintf(mt, 
357                          "Identifier length at offset 11 should hold a digit."
358                          " Assuming 2");
359         leader[11] = '2';
360         *identifier_length = 2;
361     }
362     if (!atoi_n_check(leader+12, 5, base_address))
363     {
364         yaz_marc_cprintf(mt, 
365                          "Base address at offsets 12..16 should hold a number."
366                          " Assuming 0");
367         *base_address = 0;
368     }
369     if (!atoi_n_check(leader+20, 1, length_data_entry))
370     {
371         yaz_marc_cprintf(mt, 
372                          "Length data entry at offset 20 should hold a digit."
373                          " Assuming 4");
374         *length_data_entry = 4;
375         leader[20] = '4';
376     }
377     if (!atoi_n_check(leader+21, 1, length_starting))
378     {
379         yaz_marc_cprintf(mt,
380                          "Length starting at offset 21 should hold a digit."
381                          " Assuming 5");
382         *length_starting = 5;
383         leader[21] = '5';
384     }
385     if (!atoi_n_check(leader+22, 1, length_implementation))
386     {
387         yaz_marc_cprintf(mt, 
388                          "Length implementation at offset 22 should hold a digit."
389                          " Assuming 0");
390         *length_implementation = 0;
391         leader[22] = '0';
392     }
393
394     if (mt->debug)
395     {
396         yaz_marc_cprintf(mt, "Indicator length      %5d", *indicator_length);
397         yaz_marc_cprintf(mt, "Identifier length     %5d", *identifier_length);
398         yaz_marc_cprintf(mt, "Base address          %5d", *base_address);
399         yaz_marc_cprintf(mt, "Length data entry     %5d", *length_data_entry);
400         yaz_marc_cprintf(mt, "Length starting       %5d", *length_starting);
401         yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
402     }
403     yaz_marc_add_leader(mt, leader, 24);
404 }
405
406 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
407 {
408     strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
409     mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
410 }
411
412 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
413 {
414     strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
415     mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
416 }
417
418 /* try to guess how many bytes the identifier really is! */
419 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
420 {
421     if (mt->iconv_cd)
422     {
423         size_t i;
424         for (i = 1; i<5; i++)
425         {
426             char outbuf[12];
427             size_t outbytesleft = sizeof(outbuf);
428             char *outp = outbuf;
429             const char *inp = buf;
430
431             size_t inbytesleft = i;
432             size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
433                                  &outp, &outbytesleft);
434             if (r != (size_t) (-1))
435                 return i;  /* got a complete sequence */
436         }
437         return 1; /* giving up */
438     }
439     return 1; /* we don't know */
440 }
441                               
442 void yaz_marc_reset(yaz_marc_t mt)
443 {
444     nmem_reset(mt->nmem);
445     mt->nodes = 0;
446     mt->nodes_pp = &mt->nodes;
447     mt->subfield_pp = 0;
448 }
449
450 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
451 {
452     struct yaz_marc_node *n;
453     int identifier_length;
454     const char *leader = 0;
455
456     for (n = mt->nodes; n; n = n->next)
457         if (n->which == YAZ_MARC_LEADER)
458         {
459             leader = n->u.leader;
460             break;
461         }
462     
463     if (!leader)
464         return -1;
465     if (!atoi_n_check(leader+11, 1, &identifier_length))
466         return -1;
467
468     for (n = mt->nodes; n; n = n->next)
469     {
470         switch(n->which)
471         {
472         case YAZ_MARC_COMMENT:
473             wrbuf_iconv_write(wr, mt->iconv_cd, 
474                               n->u.comment, strlen(n->u.comment));
475             wrbuf_puts(wr, "\n");
476             break;
477         default:
478             break;
479         }
480     }
481     return 0;
482 }
483
484 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
485                                int identifier_length)
486 {
487     /* if identifier length is 2 (most MARCs) or less (probably an error),
488        the code is a single character .. However we've
489        seen multibyte codes, so see how big it really is */
490     if (identifier_length > 2)
491         return identifier_length - 1;
492     else
493         return cdata_one_character(mt, data);
494 }
495
496 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
497 {
498     struct yaz_marc_node *n;
499     int identifier_length;
500     const char *leader = 0;
501
502     for (n = mt->nodes; n; n = n->next)
503         if (n->which == YAZ_MARC_LEADER)
504         {
505             leader = n->u.leader;
506             break;
507         }
508     
509     if (!leader)
510         return -1;
511     if (!atoi_n_check(leader+11, 1, &identifier_length))
512         return -1;
513
514     for (n = mt->nodes; n; n = n->next)
515     {
516         struct yaz_marc_subfield *s;
517         switch(n->which)
518         {
519         case YAZ_MARC_DATAFIELD:
520             wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
521                          n->u.datafield.indicator);
522             for (s = n->u.datafield.subfields; s; s = s->next)
523             {
524                 size_t using_code_len = get_subfield_len(mt, s->code_data,
525                                                          identifier_length);
526                 
527                 wrbuf_puts (wr, mt->subfield_str); 
528                 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data, 
529                                   using_code_len);
530                 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
531                 wrbuf_iconv_puts(wr, mt->iconv_cd, 
532                                  s->code_data + using_code_len);
533                 marc_iconv_reset(mt, wr);
534             }
535             wrbuf_puts (wr, mt->endline_str);
536             break;
537         case YAZ_MARC_CONTROLFIELD:
538             wrbuf_printf(wr, "%s", n->u.controlfield.tag);
539             wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
540             wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
541             marc_iconv_reset(mt, wr);
542             wrbuf_puts (wr, mt->endline_str);
543             break;
544         case YAZ_MARC_COMMENT:
545             wrbuf_puts(wr, "(");
546             wrbuf_iconv_write(wr, mt->iconv_cd, 
547                               n->u.comment, strlen(n->u.comment));
548             marc_iconv_reset(mt, wr);
549             wrbuf_puts(wr, ")\n");
550             break;
551         case YAZ_MARC_LEADER:
552             wrbuf_printf(wr, "%s\n", n->u.leader);
553         }
554     }
555     wrbuf_puts(wr, "\n");
556     return 0;
557 }
558
559 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
560 {
561     if (mt->enable_collection == collection_second)
562     {
563         switch(mt->output_format)
564         {
565         case YAZ_MARC_MARCXML:
566         case YAZ_MARC_TMARCXML:
567             wrbuf_printf(wr, "</collection>\n");
568             break;
569         case YAZ_MARC_XCHANGE:
570             wrbuf_printf(wr, "</collection>\n");
571             break;
572         }
573     }
574     return 0;
575 }
576
577 void yaz_marc_enable_collection(yaz_marc_t mt)
578 {
579     mt->enable_collection = collection_first;
580 }
581
582 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
583 {
584     switch(mt->output_format)
585     {
586     case YAZ_MARC_LINE:
587         return yaz_marc_write_line(mt, wr);
588     case YAZ_MARC_MARCXML:
589     case YAZ_MARC_TMARCXML:
590         return yaz_marc_write_marcxml(mt, wr);
591     case YAZ_MARC_XCHANGE:
592         return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
593     case YAZ_MARC_ISO2709:
594         return yaz_marc_write_iso2709(mt, wr);
595     case YAZ_MARC_CHECK:
596         return yaz_marc_write_check(mt, wr);
597     }
598     return -1;
599 }
600
601 const char *collection_name[2]  = { "collection", "collection"};
602 const char *record_name[2]      = { "record", "r"};
603 const char *leader_name[2]      = { "leader", "l"};
604 const char *controlfield_name[2]= { "controlfield", "c"};
605 const char *datafield_name[2]   = { "datafield", "d"};
606 const char *indicator_name[2]   = { "ind", "i"};
607 const char *subfield_name[2]    = { "subfield", "s"};
608
609
610 /** \brief common MARC XML/Xchange writer
611     \param mt handle
612     \param wr WRBUF output
613     \param ns XMLNS for the elements
614     \param format record format (e.g. "MARC21")
615     \param type record type (e.g. "Bibliographic")
616 */
617 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
618                                       const char *ns, 
619                                       const char *format,
620                                       const char *type)
621 {
622     struct yaz_marc_node *n;
623     int identifier_length;
624     const char *leader = 0;
625
626     int turbo = yaz_marc_get_write_format(mt) == YAZ_MARC_TMARCXML;
627
628     for (n = mt->nodes; n; n = n->next)
629         if (n->which == YAZ_MARC_LEADER)
630         {
631             leader = n->u.leader;
632             break;
633         }
634     
635     if (!leader)
636         return -1;
637     if (!atoi_n_check(leader+11, 1, &identifier_length))
638         return -1;
639     
640     if (mt->enable_collection != no_collection)
641     {
642         if (mt->enable_collection == collection_first) {
643             wrbuf_printf(wr, "<%s xmlns=\"%s\">\n", collection_name[turbo], ns);
644             mt->enable_collection = collection_second;
645         }
646         wrbuf_printf(wr, "<%s", record_name[turbo]);
647     }
648     else
649     {
650         wrbuf_printf(wr, "<%s xmlns=\"%s\"", record_name[turbo], ns);
651     }
652     if (format)
653         wrbuf_printf(wr, " format=\"%.80s\"", format);
654     if (type)
655         wrbuf_printf(wr, " type=\"%.80s\"", type);
656     wrbuf_printf(wr, ">\n");
657     for (n = mt->nodes; n; n = n->next)
658     {
659         struct yaz_marc_subfield *s;
660
661         switch(n->which)
662         {
663         case YAZ_MARC_DATAFIELD:
664
665                 wrbuf_printf(wr, "  <%s", datafield_name[turbo]);
666             if (!turbo)
667                 wrbuf_printf(wr, " tag=\"");
668             wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
669                                     strlen(n->u.datafield.tag));
670                 if (!turbo)
671                         wrbuf_printf(wr, "\"");
672             if (n->u.datafield.indicator)
673             {
674                 int i;
675                 for (i = 0; n->u.datafield.indicator[i]; i++)
676                 {
677                         wrbuf_printf(wr, " %s%d=\"", indicator_name[turbo], i+1);
678                         wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
679                                         n->u.datafield.indicator+i, 1);
680                         wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
681                                 }
682             }
683                 wrbuf_printf(wr, ">\n");
684             for (s = n->u.datafield.subfields; s; s = s->next)
685             {
686                 size_t using_code_len = get_subfield_len(mt, s->code_data,
687                                                          identifier_length);
688                 wrbuf_printf(wr, "    <%s", subfield_name[turbo]);
689                                 if (!turbo) {
690                                         wrbuf_printf(wr, " code=\"");
691                         wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
692                                         s->code_data, using_code_len);
693                         wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
694                                 } else {
695                                 element_name_encode(mt, wr, s->code_data, using_code_len);
696                                         wrbuf_puts(wr, ">");
697                                 }
698                 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
699                                         s->code_data + using_code_len,
700                                         strlen(s->code_data + using_code_len));
701                 marc_iconv_reset(mt, wr);
702                                 wrbuf_printf(wr, "</%s", subfield_name[turbo]);
703                 if (turbo)
704                         wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
705                                         s->code_data, using_code_len);
706                 wrbuf_puts(wr, ">\n");
707             }
708             wrbuf_printf(wr, "  </%s", datafield_name[turbo]);
709                 //TODO Not CDATA
710             if (turbo)
711                 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
712                                 strlen(n->u.datafield.tag));
713             wrbuf_printf(wr, ">\n", datafield_name[turbo]);
714             break;
715         case YAZ_MARC_CONTROLFIELD:
716                 wrbuf_printf(wr, "  <%s", controlfield_name[turbo]);
717                 if (!turbo) {
718                 wrbuf_printf(wr, " tag=\"");
719                         wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
720                                         strlen(n->u.controlfield.tag));
721                         wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
722                 }
723                 else {
724                         //TODO convert special
725                         wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
726                                         strlen(n->u.controlfield.tag));
727                         wrbuf_iconv_puts(wr, mt->iconv_cd, ">");
728                 }
729                 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
730                                                                         n->u.controlfield.data,
731                                                                         strlen(n->u.controlfield.data));
732                 marc_iconv_reset(mt, wr);
733                 wrbuf_printf(wr, "</%s", controlfield_name[turbo]);
734                 //TODO convert special
735                 if (turbo)
736                         wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
737                                         strlen(n->u.controlfield.tag));
738                 wrbuf_puts(wr, ">\n");
739             break;
740         case YAZ_MARC_COMMENT:
741             wrbuf_printf(wr, "<!-- ");
742             wrbuf_puts(wr, n->u.comment);
743             wrbuf_printf(wr, " -->\n");
744             break;
745         case YAZ_MARC_LEADER:
746             wrbuf_printf(wr, "  <%s>", leader_name[turbo]);
747             wrbuf_iconv_write_cdata(wr, 
748                                     0 /* no charset conversion for leader */,
749                                     n->u.leader, strlen(n->u.leader));
750             wrbuf_printf(wr, "</%s>\n", leader_name[turbo]);
751         }
752     }
753     wrbuf_printf(wr, "</%s>\n", record_name[turbo]);
754     return 0;
755 }
756
757 static int yaz_marc_write_marcxml_ns2(yaz_marc_t mt, WRBUF wr,
758                                       const char *ns, 
759                                       const char *format,
760                                       const char *type)
761 {
762     struct yaz_marc_node *n;
763     int identifier_length;
764     const char *leader = 0;
765
766     for (n = mt->nodes; n; n = n->next)
767         if (n->which == YAZ_MARC_LEADER)
768         {
769             leader = n->u.leader;
770             break;
771         }
772     
773     if (!leader)
774         return -1;
775     if (!atoi_n_check(leader+11, 1, &identifier_length))
776         return -1;
777     
778     if (mt->enable_collection != no_collection)
779     {
780         if (mt->enable_collection == collection_first)
781             wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
782         mt->enable_collection = collection_second;
783         wrbuf_printf(wr, "<record");
784     }
785     else
786     {
787         wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
788     }
789     if (format)
790         wrbuf_printf(wr, " format=\"%.80s\"", format);
791     if (type)
792         wrbuf_printf(wr, " type=\"%.80s\"", type);
793     wrbuf_printf(wr, ">\n");
794     for (n = mt->nodes; n; n = n->next)
795     {
796         struct yaz_marc_subfield *s;
797
798         switch(n->which)
799         {
800         case YAZ_MARC_DATAFIELD:
801             wrbuf_printf(wr, "  <datafield tag=\"");
802             wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
803                                     strlen(n->u.datafield.tag));
804             wrbuf_printf(wr, "\"");
805             if (n->u.datafield.indicator)
806             {
807                 int i;
808                 for (i = 0; n->u.datafield.indicator[i]; i++)
809                 {
810                     wrbuf_printf(wr, " ind%d=\"", i+1);
811                     wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
812                                           n->u.datafield.indicator+i, 1);
813                     wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
814                 }
815             }
816             wrbuf_printf(wr, ">\n");
817             for (s = n->u.datafield.subfields; s; s = s->next)
818             {
819                 size_t using_code_len = get_subfield_len(mt, s->code_data,
820                                                          identifier_length);
821                 wrbuf_iconv_puts(wr, mt->iconv_cd, "    <subfield code=\"");
822                 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
823                                         s->code_data, using_code_len);
824                 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
825                 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
826                                         s->code_data + using_code_len,
827                                         strlen(s->code_data + using_code_len));
828                 marc_iconv_reset(mt, wr);
829                 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
830                 wrbuf_puts(wr, "\n");
831             }
832             wrbuf_printf(wr, "  </datafield>\n");
833             break;
834         case YAZ_MARC_CONTROLFIELD:
835             wrbuf_printf(wr, "  <controlfield tag=\"");
836             wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
837                                     strlen(n->u.controlfield.tag));
838             wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
839             wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
840                                     n->u.controlfield.data,
841                                     strlen(n->u.controlfield.data));
842
843             marc_iconv_reset(mt, wr);
844             wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
845             wrbuf_puts(wr, "\n");
846             break;
847         case YAZ_MARC_COMMENT:
848             wrbuf_printf(wr, "<!-- ");
849             wrbuf_puts(wr, n->u.comment);
850             wrbuf_printf(wr, " -->\n");
851             break;
852         case YAZ_MARC_LEADER:
853             wrbuf_printf(wr, "  <leader>");
854             wrbuf_iconv_write_cdata(wr, 
855                                     0 /* no charset conversion for leader */,
856                                     n->u.leader, strlen(n->u.leader));
857             wrbuf_printf(wr, "</leader>\n");
858         }
859     }
860     wrbuf_puts(wr, "</record>\n");
861     return 0;
862 }
863
864
865 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
866                                      const char *ns, 
867                                      const char *format,
868                                      const char *type)
869 {
870     if (mt->write_using_libxml2)
871     {
872 #if YAZ_HAVE_XML2
873         int ret;
874         xmlNode *root_ptr;
875
876         if (yaz_marc_get_write_format(mt) == YAZ_MARC_MARCXML)
877                 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
878         else // Check for Turbo XML
879                 ret = yaz_marc_write_turbo_xml(mt, &root_ptr, ns, format, type);
880         if (ret == 0)
881         {
882             xmlChar *buf_out;
883             xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
884             int len_out;
885
886             xmlDocSetRootElement(doc, root_ptr);
887             xmlDocDumpMemory(doc, &buf_out, &len_out);
888
889             wrbuf_write(wr, (const char *) buf_out, len_out);
890             wrbuf_puts(wr, "");
891             xmlFree(buf_out);
892             xmlFreeDoc(doc);
893         }
894         return ret;
895 #else
896         return -1;
897 #endif
898     }
899     else
900         return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
901 }
902
903 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
904 {
905     /* set leader 09 to 'a' for UNICODE */
906     /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
907     if (!mt->leader_spec)
908         yaz_marc_modify_leader(mt, 9, "a");
909     char *name_space = "http://www.loc.gov/MARC21/slim";
910     if (mt->output_format == YAZ_MARC_TMARCXML)
911         name_space = "http://www.indexdata.com/MARC21/turboxml";
912     return yaz_marc_write_marcxml_ns(mt, wr, name_space,
913                                      0, 0);
914 }
915
916 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
917                                const char *format,
918                                const char *type)
919 {
920     return yaz_marc_write_marcxml_ns(mt, wr,
921                                      "info:lc/xmlns/marcxchange-v1",
922                                      0, 0);
923 }
924
925 #if YAZ_HAVE_XML2
926
927 void add_marc_datafield_turbo_xml(yaz_marc_t mt, struct yaz_marc_node *n, xmlNode *record_ptr, xmlNsPtr ns_record, WRBUF wr_cdata, int identifier_length)
928 {
929     xmlNode *ptr;
930     struct yaz_marc_subfield *s;
931     int turbo = mt->output_format == YAZ_MARC_TMARCXML;
932     if (!turbo) {
933         ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
934         xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
935     }
936     else {
937         //TODO consider if safe
938         char field[10];
939         field[0] = 'd';
940         strncpy(field + 1, n->u.datafield.tag, 3);
941         field[4] = '\0';
942         ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST field, 0);
943     }
944     if (n->u.datafield.indicator)
945     {
946         int i;
947         for (i = 0; n->u.datafield.indicator[i]; i++)
948         {
949             char ind_str[6];
950             char ind_val[2];
951             
952             ind_val[0] = n->u.datafield.indicator[i];
953             ind_val[1] = '\0';
954             sprintf(ind_str, "%s%d", indicator_name[turbo], i+1);
955                         xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
956         }
957     }
958         WRBUF subfield_name = wrbuf_alloc();
959     for (s = n->u.datafield.subfields; s; s = s->next)
960     {
961         xmlNode *ptr_subfield;
962         size_t using_code_len = get_subfield_len(mt, s->code_data,
963                                                  identifier_length);
964         wrbuf_rewind(wr_cdata);
965         wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, s->code_data + using_code_len);
966         marc_iconv_reset(mt, wr_cdata);
967         
968         if (!turbo) {
969                 ptr_subfield = xmlNewTextChild(
970                                 ptr, ns_record,
971                                 BAD_CAST "subfield",  BAD_CAST wrbuf_cstr(wr_cdata));
972                 wrbuf_rewind(wr_cdata);
973                 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,s->code_data, using_code_len);
974                 xmlNewProp(ptr_subfield, BAD_CAST "code",
975                                 BAD_CAST wrbuf_cstr(wr_cdata));
976         }
977         else { // Turbo format
978                 wrbuf_rewind(subfield_name);
979                 wrbuf_puts(subfield_name, "s");
980                 element_name_encode(mt, subfield_name, s->code_data, using_code_len);
981                 ptr_subfield = xmlNewTextChild(ptr, ns_record,
982                                 BAD_CAST wrbuf_cstr(subfield_name),
983                                 BAD_CAST wrbuf_cstr(wr_cdata));
984         }
985     }
986         wrbuf_destroy(subfield_name);
987 }
988
989 int yaz_marc_write_turbo_xml(yaz_marc_t mt, xmlNode **root_ptr,
990                        const char *ns, 
991                        const char *format,
992                        const char *type)
993 {
994     struct yaz_marc_node *n;
995     int identifier_length;
996     const char *leader = 0;
997     xmlNode *record_ptr;
998     xmlNsPtr ns_record;
999     WRBUF wr_cdata = 0;
1000     int turbo = mt->output_format == YAZ_MARC_TMARCXML;
1001     for (n = mt->nodes; n; n = n->next)
1002         if (n->which == YAZ_MARC_LEADER)
1003         {
1004             leader = n->u.leader;
1005             break;
1006         }
1007     
1008     if (!leader)
1009         return -1;
1010     if (!atoi_n_check(leader+11, 1, &identifier_length))
1011         return -1;
1012
1013     wr_cdata = wrbuf_alloc();
1014
1015     record_ptr = xmlNewNode(0, BAD_CAST "r");
1016     *root_ptr = record_ptr;
1017
1018     ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
1019     xmlSetNs(record_ptr, ns_record);
1020
1021     if (format)
1022         xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
1023     if (type)
1024         xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
1025     for (n = mt->nodes; n; n = n->next)
1026     {
1027         struct yaz_marc_subfield *s;
1028         xmlNode *ptr;
1029
1030         switch(n->which)
1031         {
1032         case YAZ_MARC_DATAFIELD:
1033                 add_marc_datafield_turbo_xml(mt, n, record_ptr, ns_record, wr_cdata, identifier_length);
1034             break;
1035         case YAZ_MARC_CONTROLFIELD:
1036             wrbuf_rewind(wr_cdata);
1037             wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1038             marc_iconv_reset(mt, wr_cdata);
1039             
1040             if (!turbo) {
1041                                 ptr = xmlNewTextChild(record_ptr, ns_record,
1042                                                                           BAD_CAST "controlfield",
1043                                                                           BAD_CAST wrbuf_cstr(wr_cdata));
1044                                 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1045             }
1046             else {
1047                 // TODO required iconv?
1048                 char field[10];
1049                                 field[0] = 'c';
1050                 strncpy(field + 1, n->u.controlfield.tag, 3);
1051                 field[4] = '\0';
1052                 ptr = xmlNewTextChild(record_ptr, ns_record,
1053                                                                           BAD_CAST field,
1054                                                                           BAD_CAST wrbuf_cstr(wr_cdata));
1055             }
1056
1057             break;
1058         case YAZ_MARC_COMMENT:
1059             ptr = xmlNewComment(BAD_CAST n->u.comment);
1060             xmlAddChild(record_ptr, ptr);
1061             break;
1062         case YAZ_MARC_LEADER:
1063                         {
1064                                 char *field = "leader";
1065                                 if (turbo)
1066                                         field = "l";
1067                                 xmlNewTextChild(record_ptr, ns_record, BAD_CAST field,
1068                                                                 BAD_CAST n->u.leader);
1069                         }
1070             break;
1071         }
1072     }
1073     wrbuf_destroy(wr_cdata);
1074     return 0;
1075 }
1076
1077
1078 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
1079                        const char *ns, 
1080                        const char *format,
1081                        const char *type)
1082 {
1083     struct yaz_marc_node *n;
1084     int identifier_length;
1085     const char *leader = 0;
1086     xmlNode *record_ptr;
1087     xmlNsPtr ns_record;
1088     WRBUF wr_cdata = 0;
1089
1090     for (n = mt->nodes; n; n = n->next)
1091         if (n->which == YAZ_MARC_LEADER)
1092         {
1093             leader = n->u.leader;
1094             break;
1095         }
1096     
1097     if (!leader)
1098         return -1;
1099     if (!atoi_n_check(leader+11, 1, &identifier_length))
1100         return -1;
1101
1102     wr_cdata = wrbuf_alloc();
1103
1104     record_ptr = xmlNewNode(0, BAD_CAST "record");
1105     *root_ptr = record_ptr;
1106
1107     ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
1108     xmlSetNs(record_ptr, ns_record);
1109
1110     if (format)
1111         xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
1112     if (type)
1113         xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
1114     for (n = mt->nodes; n; n = n->next)
1115     {
1116         struct yaz_marc_subfield *s;
1117         xmlNode *ptr;
1118
1119         switch(n->which)
1120         {
1121         case YAZ_MARC_DATAFIELD:
1122             ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
1123             xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
1124             if (n->u.datafield.indicator)
1125             {
1126                 int i;
1127                 for (i = 0; n->u.datafield.indicator[i]; i++)
1128                 {
1129                     char ind_str[6];
1130                     char ind_val[2];
1131
1132                     sprintf(ind_str, "ind%d", i+1);
1133                     ind_val[0] = n->u.datafield.indicator[i];
1134                     ind_val[1] = '\0';
1135                     xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
1136                 }
1137             }
1138             for (s = n->u.datafield.subfields; s; s = s->next)
1139             {
1140                 xmlNode *ptr_subfield;
1141                 size_t using_code_len = get_subfield_len(mt, s->code_data,
1142                                                          identifier_length);
1143                 wrbuf_rewind(wr_cdata);
1144                 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
1145                                  s->code_data + using_code_len);
1146                 marc_iconv_reset(mt, wr_cdata);
1147                 ptr_subfield = xmlNewTextChild(
1148                     ptr, ns_record,
1149                     BAD_CAST "subfield",  BAD_CAST wrbuf_cstr(wr_cdata));
1150
1151                 wrbuf_rewind(wr_cdata);
1152                 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
1153                                   s->code_data, using_code_len);
1154                 xmlNewProp(ptr_subfield, BAD_CAST "code",
1155                            BAD_CAST wrbuf_cstr(wr_cdata));
1156             }
1157             break;
1158         case YAZ_MARC_CONTROLFIELD:
1159             wrbuf_rewind(wr_cdata);
1160             wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
1161             marc_iconv_reset(mt, wr_cdata);
1162             
1163             ptr = xmlNewTextChild(record_ptr, ns_record,
1164                                   BAD_CAST "controlfield",
1165                                   BAD_CAST wrbuf_cstr(wr_cdata));
1166             
1167             xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
1168             break;
1169         case YAZ_MARC_COMMENT:
1170             ptr = xmlNewComment(BAD_CAST n->u.comment);
1171             xmlAddChild(record_ptr, ptr);
1172             break;
1173         case YAZ_MARC_LEADER:
1174             xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
1175                             BAD_CAST n->u.leader);
1176             break;
1177         }
1178     }
1179     wrbuf_destroy(wr_cdata);
1180     return 0;
1181 }
1182
1183
1184
1185
1186 #endif
1187
1188 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
1189 {
1190     struct yaz_marc_node *n;
1191     int indicator_length;
1192     int identifier_length;
1193     int length_data_entry;
1194     int length_starting;
1195     int length_implementation;
1196     int data_offset = 0;
1197     const char *leader = 0;
1198     WRBUF wr_dir, wr_head, wr_data_tmp;
1199     int base_address;
1200     
1201     for (n = mt->nodes; n; n = n->next)
1202         if (n->which == YAZ_MARC_LEADER)
1203             leader = n->u.leader;
1204     
1205     if (!leader)
1206         return -1;
1207     if (!atoi_n_check(leader+10, 1, &indicator_length))
1208         return -1;
1209     if (!atoi_n_check(leader+11, 1, &identifier_length))
1210         return -1;
1211     if (!atoi_n_check(leader+20, 1, &length_data_entry))
1212         return -1;
1213     if (!atoi_n_check(leader+21, 1, &length_starting))
1214         return -1;
1215     if (!atoi_n_check(leader+22, 1, &length_implementation))
1216         return -1;
1217
1218     wr_data_tmp = wrbuf_alloc();
1219     wr_dir = wrbuf_alloc();
1220     for (n = mt->nodes; n; n = n->next)
1221     {
1222         int data_length = 0;
1223         struct yaz_marc_subfield *s;
1224
1225         switch(n->which)
1226         {
1227         case YAZ_MARC_DATAFIELD:
1228             wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
1229             data_length += indicator_length;
1230             wrbuf_rewind(wr_data_tmp);
1231             for (s = n->u.datafield.subfields; s; s = s->next)
1232             {
1233                 /* write dummy IDFS + content */
1234                 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1235                 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
1236                 marc_iconv_reset(mt, wr_data_tmp);
1237             }
1238             /* write dummy FS (makes MARC-8 to become ASCII) */
1239             wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
1240             marc_iconv_reset(mt, wr_data_tmp);
1241             data_length += wrbuf_len(wr_data_tmp);
1242             break;
1243         case YAZ_MARC_CONTROLFIELD:
1244             wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
1245
1246             wrbuf_rewind(wr_data_tmp);
1247             wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, 
1248                              n->u.controlfield.data);
1249             marc_iconv_reset(mt, wr_data_tmp);
1250             wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
1251             marc_iconv_reset(mt, wr_data_tmp);
1252             data_length += wrbuf_len(wr_data_tmp);
1253             break;
1254         case YAZ_MARC_COMMENT:
1255             break;
1256         case YAZ_MARC_LEADER:
1257             break;
1258         }
1259         if (data_length)
1260         {
1261             wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
1262             wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
1263             data_offset += data_length;
1264         }
1265     }
1266     /* mark end of directory */
1267     wrbuf_putc(wr_dir, ISO2709_FS);
1268
1269     /* base address of data (comes after leader+directory) */
1270     base_address = 24 + wrbuf_len(wr_dir);
1271
1272     wr_head = wrbuf_alloc();
1273
1274     /* write record length */
1275     wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
1276     /* from "original" leader */
1277     wrbuf_write(wr_head, leader+5, 7);
1278     /* base address of data */
1279     wrbuf_printf(wr_head, "%05d", base_address);
1280     /* from "original" leader */
1281     wrbuf_write(wr_head, leader+17, 7);
1282     
1283     wrbuf_write(wr, wrbuf_buf(wr_head), 24);
1284     wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
1285     wrbuf_destroy(wr_head);
1286     wrbuf_destroy(wr_dir);
1287     wrbuf_destroy(wr_data_tmp);
1288
1289     for (n = mt->nodes; n; n = n->next)
1290     {
1291         struct yaz_marc_subfield *s;
1292
1293         switch(n->which)
1294         {
1295         case YAZ_MARC_DATAFIELD:
1296             wrbuf_printf(wr, "%.*s", indicator_length,
1297                          n->u.datafield.indicator);
1298             for (s = n->u.datafield.subfields; s; s = s->next)
1299             {
1300                 wrbuf_putc(wr, ISO2709_IDFS);
1301                 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
1302                 marc_iconv_reset(mt, wr);
1303             }
1304             wrbuf_putc(wr, ISO2709_FS);
1305             break;
1306         case YAZ_MARC_CONTROLFIELD:
1307             wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
1308             marc_iconv_reset(mt, wr);
1309             wrbuf_putc(wr, ISO2709_FS);
1310             break;
1311         case YAZ_MARC_COMMENT:
1312             break;
1313         case YAZ_MARC_LEADER:
1314             break;
1315         }
1316     }
1317     wrbuf_printf(wr, "%c", ISO2709_RS);
1318     return 0;
1319 }
1320
1321
1322 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
1323 {
1324     int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
1325     if (r <= 0)
1326         return r;
1327     s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
1328     if (s != 0)
1329         return -1; /* error */
1330     return r; /* OK, return length > 0 */
1331 }
1332
1333 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
1334                          const char **result, size_t *rsize)
1335 {
1336     int r;
1337
1338     wrbuf_rewind(mt->m_wr);
1339     r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
1340     if (result)
1341         *result = wrbuf_cstr(mt->m_wr);
1342     if (rsize)
1343         *rsize = wrbuf_len(mt->m_wr);
1344     return r;
1345 }
1346
1347 void yaz_marc_set_read_format(yaz_marc_t mt, int format)
1348 {
1349     if (mt)
1350         mt->input_format = format;
1351 }
1352
1353 int yaz_marc_get_read_format(yaz_marc_t mt)
1354 {
1355     if (mt)
1356         return mt->input_format;
1357     return -1;
1358 }
1359
1360
1361 void yaz_marc_set_write_format(yaz_marc_t mt, int format)
1362 {
1363     if (mt) {
1364         mt->output_format = format;
1365 /*
1366         // Force using libxml2
1367         if (mt->output_format == YAZ_MARC_TMARCXML)
1368                 mt->write_using_libxml2 = 1;
1369 */
1370     }
1371 }
1372
1373 int yaz_marc_get_write_format(yaz_marc_t mt)
1374 {
1375     if (mt)
1376         return mt->output_format;
1377     return -1;
1378 }
1379
1380
1381 /**
1382  * Deprecated, use yaz_marc_set_write_format
1383  */
1384 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1385 {
1386         yaz_marc_set_write_format(mt, xmlmode);
1387 }
1388
1389
1390
1391 void yaz_marc_debug(yaz_marc_t mt, int level)
1392 {
1393     if (mt)
1394         mt->debug = level;
1395 }
1396
1397 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1398 {
1399     mt->iconv_cd = cd;
1400 }
1401
1402 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1403 {
1404     return mt->iconv_cd;
1405 }
1406
1407 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1408 {
1409     struct yaz_marc_node *n;
1410     char *leader = 0;
1411     for (n = mt->nodes; n; n = n->next)
1412         if (n->which == YAZ_MARC_LEADER)
1413         {
1414             leader = n->u.leader;
1415             memcpy(leader+off, str, strlen(str));
1416             break;
1417         }
1418 }
1419
1420 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1421 {
1422     xfree(mt->leader_spec);
1423     mt->leader_spec = 0;
1424     if (leader_spec)
1425     {
1426         char dummy_leader[24];
1427         if (marc_exec_leader(leader_spec, dummy_leader, 24))
1428             return -1;
1429         mt->leader_spec = xstrdup(leader_spec);
1430     }
1431     return 0;
1432 }
1433
1434 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1435 {
1436     const char *cp = leader_spec;
1437     while (cp)
1438     {
1439         char val[21];
1440         int pos;
1441         int no_read = 0, no = 0;
1442
1443         no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1444         if (no < 2 || no_read < 3)
1445             return -1;
1446         if (pos < 0 || (size_t) pos >= size)
1447             return -1;
1448
1449         if (*val == '\'')
1450         {
1451             const char *vp = strchr(val+1, '\'');
1452             size_t len;
1453             
1454             if (!vp)
1455                 return -1;
1456             len = vp-val-1;
1457             if (len + pos > size)
1458                 return -1;
1459             memcpy(leader + pos, val+1, len);
1460         }
1461         else if (*val >= '0' && *val <= '9')
1462         {
1463             int ch = atoi(val);
1464             leader[pos] = ch;
1465         }
1466         else
1467             return -1;
1468         cp += no_read;
1469         if (*cp != ',')
1470             break;
1471
1472         cp++;
1473     }
1474     return 0;
1475 }
1476
1477 int yaz_marc_decode_formatstr(const char *arg)
1478 {
1479     int mode = -1; 
1480     if (!strcmp(arg, "marc"))
1481         mode = YAZ_MARC_ISO2709;
1482     if (!strcmp(arg, "marcxml"))
1483         mode = YAZ_MARC_MARCXML;
1484     if (!strcmp(arg, "tmarcxml"))
1485         mode = YAZ_MARC_TMARCXML;
1486     if (!strcmp(arg, "marcxchange"))
1487         mode = YAZ_MARC_XCHANGE;
1488     if (!strcmp(arg, "line"))
1489         mode = YAZ_MARC_LINE;
1490     return mode;
1491 }
1492
1493 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1494 {
1495     mt->write_using_libxml2 = enable;
1496 }
1497
1498 int yaz_marc_is_turbo_format(yaz_marc_t mt)
1499 {
1500     return mt->output_format == YAZ_MARC_TMARCXML;
1501 }
1502
1503
1504 /*
1505  * Local variables:
1506  * c-basic-offset: 4
1507  * c-file-style: "Stroustrup"
1508  * indent-tabs-mode: nil
1509  * End:
1510  * vim: shiftwidth=4 tabstop=8 expandtab
1511  */
1512