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