1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2008 Index Data
3 * See the file LICENSE for details.
8 * \brief Implements MARC conversion utilities
23 #include <yaz/marcdisp.h>
24 #include <yaz/wrbuf.h>
25 #include <yaz/yaz-util.h>
26 #include <yaz/nmem_xml.h>
27 #include <yaz/snprintf.h>
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
34 enum yaz_collection_state {
40 /** \brief node types for yaz_marc_node */
41 enum YAZ_MARC_NODE_TYPE
44 YAZ_MARC_CONTROLFIELD,
49 /** \brief represets a data field */
50 struct yaz_marc_datafield {
53 struct yaz_marc_subfield *subfields;
56 /** \brief represents a control field */
57 struct yaz_marc_controlfield {
62 /** \brief a comment node */
63 struct yaz_marc_comment {
67 /** \brief MARC node */
68 struct yaz_marc_node {
69 enum YAZ_MARC_NODE_TYPE which;
71 struct yaz_marc_datafield datafield;
72 struct yaz_marc_controlfield controlfield;
76 struct yaz_marc_node *next;
79 /** \brief represents a subfield */
80 struct yaz_marc_subfield {
82 struct yaz_marc_subfield *next;
85 /** \brief the internals of a yaz_marc_t handle */
91 int write_using_libxml2;
92 enum yaz_collection_state enable_collection;
97 struct yaz_marc_node *nodes;
98 struct yaz_marc_node **nodes_pp;
99 struct yaz_marc_subfield **subfield_pp;
102 yaz_marc_t yaz_marc_create(void)
104 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
105 mt->xml = YAZ_MARC_LINE;
107 mt->write_using_libxml2 = 0;
108 mt->enable_collection = no_collection;
109 mt->m_wr = wrbuf_alloc();
112 strcpy(mt->subfield_str, " $");
113 strcpy(mt->endline_str, "\n");
115 mt->nmem = nmem_create();
120 void yaz_marc_destroy(yaz_marc_t mt)
124 nmem_destroy(mt->nmem);
125 wrbuf_destroy(mt->m_wr);
126 xfree(mt->leader_spec);
130 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
135 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
137 wrbuf_iconv_reset(wr, mt->iconv_cd);
140 static int marc_exec_leader(const char *leader_spec, char *leader,
144 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
146 struct yaz_marc_node *n = (struct yaz_marc_node *)
147 nmem_malloc(mt->nmem, sizeof(*n));
150 mt->nodes_pp = &n->next;
155 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
156 const xmlNode *ptr_data)
158 struct yaz_marc_node *n = yaz_marc_add_node(mt);
159 n->which = YAZ_MARC_CONTROLFIELD;
160 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
161 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
166 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
168 struct yaz_marc_node *n = yaz_marc_add_node(mt);
169 n->which = YAZ_MARC_COMMENT;
170 n->u.comment = nmem_strdup(mt->nmem, comment);
173 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
179 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
180 yaz_marc_add_comment(mt, buf);
184 int yaz_marc_get_debug(yaz_marc_t mt)
189 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
191 struct yaz_marc_node *n = yaz_marc_add_node(mt);
192 n->which = YAZ_MARC_LEADER;
193 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
194 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
197 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
198 const char *data, size_t data_len)
200 struct yaz_marc_node *n = yaz_marc_add_node(mt);
201 n->which = YAZ_MARC_CONTROLFIELD;
202 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
203 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
209 sprintf(msg, "controlfield:");
210 for (i = 0; i < 16 && i < data_len; i++)
211 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
213 sprintf(msg + strlen(msg), " ..");
214 yaz_marc_add_comment(mt, msg);
218 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
219 const char *indicator, size_t indicator_len)
221 struct yaz_marc_node *n = yaz_marc_add_node(mt);
222 n->which = YAZ_MARC_DATAFIELD;
223 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
224 n->u.datafield.indicator =
225 nmem_strdupn(mt->nmem, indicator, indicator_len);
226 n->u.datafield.subfields = 0;
228 /* make subfield_pp the current (last one) */
229 mt->subfield_pp = &n->u.datafield.subfields;
233 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
234 const char *indicator, size_t indicator_len)
236 struct yaz_marc_node *n = yaz_marc_add_node(mt);
237 n->which = YAZ_MARC_DATAFIELD;
238 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
239 n->u.datafield.indicator =
240 nmem_strdupn(mt->nmem, indicator, indicator_len);
241 n->u.datafield.subfields = 0;
243 /* make subfield_pp the current (last one) */
244 mt->subfield_pp = &n->u.datafield.subfields;
248 void yaz_marc_add_subfield(yaz_marc_t mt,
249 const char *code_data, size_t code_data_len)
256 sprintf(msg, "subfield:");
257 for (i = 0; i < 16 && i < code_data_len; i++)
258 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
259 if (i < code_data_len)
260 sprintf(msg + strlen(msg), " ..");
261 yaz_marc_add_comment(mt, msg);
266 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
267 nmem_malloc(mt->nmem, sizeof(*n));
268 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
270 /* mark subfield_pp to point to this one, so we append here next */
271 *mt->subfield_pp = n;
272 mt->subfield_pp = &n->next;
276 int atoi_n_check(const char *buf, int size, int *val)
279 for (i = 0; i < size; i++)
280 if (!isdigit(i[(const unsigned char *) buf]))
282 *val = atoi_n(buf, size);
286 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
287 int *indicator_length,
288 int *identifier_length,
290 int *length_data_entry,
291 int *length_starting,
292 int *length_implementation)
296 memcpy(leader, leader_c, 24);
298 if (!atoi_n_check(leader+10, 1, indicator_length))
301 "Indicator length at offset 10 should hold a digit."
304 *indicator_length = 2;
306 if (!atoi_n_check(leader+11, 1, identifier_length))
309 "Identifier length at offset 11 should hold a digit."
312 *identifier_length = 2;
314 if (!atoi_n_check(leader+12, 5, base_address))
317 "Base address at offsets 12..16 should hold a number."
321 if (!atoi_n_check(leader+20, 1, length_data_entry))
324 "Length data entry at offset 20 should hold a digit."
326 *length_data_entry = 4;
329 if (!atoi_n_check(leader+21, 1, length_starting))
332 "Length starting at offset 21 should hold a digit."
334 *length_starting = 5;
337 if (!atoi_n_check(leader+22, 1, length_implementation))
340 "Length implementation at offset 22 should hold a digit."
342 *length_implementation = 0;
348 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
349 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
350 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
351 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
352 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
353 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
355 yaz_marc_add_leader(mt, leader, 24);
358 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
360 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
361 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
364 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
366 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
367 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
370 /* try to guess how many bytes the identifier really is! */
371 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
376 for (i = 1; i<5; i++)
379 size_t outbytesleft = sizeof(outbuf);
381 const char *inp = buf;
383 size_t inbytesleft = i;
384 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
385 &outp, &outbytesleft);
386 if (r != (size_t) (-1))
387 return i; /* got a complete sequence */
389 return 1; /* giving up */
391 return 1; /* we don't know */
394 void yaz_marc_reset(yaz_marc_t mt)
396 nmem_reset(mt->nmem);
398 mt->nodes_pp = &mt->nodes;
402 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
404 struct yaz_marc_node *n;
405 int identifier_length;
406 const char *leader = 0;
408 for (n = mt->nodes; n; n = n->next)
409 if (n->which == YAZ_MARC_LEADER)
411 leader = n->u.leader;
417 if (!atoi_n_check(leader+11, 1, &identifier_length))
420 for (n = mt->nodes; n; n = n->next)
424 case YAZ_MARC_COMMENT:
425 wrbuf_iconv_write(wr, mt->iconv_cd,
426 n->u.comment, strlen(n->u.comment));
427 wrbuf_puts(wr, ")\n");
437 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
439 struct yaz_marc_node *n;
440 int identifier_length;
441 const char *leader = 0;
443 for (n = mt->nodes; n; n = n->next)
444 if (n->which == YAZ_MARC_LEADER)
446 leader = n->u.leader;
452 if (!atoi_n_check(leader+11, 1, &identifier_length))
455 for (n = mt->nodes; n; n = n->next)
457 struct yaz_marc_subfield *s;
460 case YAZ_MARC_DATAFIELD:
461 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
462 n->u.datafield.indicator);
463 for (s = n->u.datafield.subfields; s; s = s->next)
465 /* if identifier length is 2 (most MARCs),
466 the code is a single character .. However we've
467 seen multibyte codes, so see how big it really is */
468 size_t using_code_len =
469 (identifier_length != 2) ? identifier_length - 1
471 cdata_one_character(mt, s->code_data);
473 wrbuf_puts (wr, mt->subfield_str);
474 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
476 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
477 wrbuf_iconv_puts(wr, mt->iconv_cd,
478 s->code_data + using_code_len);
479 marc_iconv_reset(mt, wr);
481 wrbuf_puts (wr, mt->endline_str);
483 case YAZ_MARC_CONTROLFIELD:
484 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
485 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
486 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
487 marc_iconv_reset(mt, wr);
488 wrbuf_puts (wr, mt->endline_str);
490 case YAZ_MARC_COMMENT:
492 wrbuf_iconv_write(wr, mt->iconv_cd,
493 n->u.comment, strlen(n->u.comment));
494 marc_iconv_reset(mt, wr);
495 wrbuf_puts(wr, ")\n");
497 case YAZ_MARC_LEADER:
498 wrbuf_printf(wr, "%s\n", n->u.leader);
501 wrbuf_puts(wr, "\n");
505 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
507 if (mt->enable_collection == collection_second)
511 case YAZ_MARC_MARCXML:
512 wrbuf_printf(wr, "</collection>\n");
514 case YAZ_MARC_XCHANGE:
515 wrbuf_printf(wr, "</collection>\n");
522 void yaz_marc_enable_collection(yaz_marc_t mt)
524 mt->enable_collection = collection_first;
527 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
532 return yaz_marc_write_line(mt, wr);
533 case YAZ_MARC_MARCXML:
534 return yaz_marc_write_marcxml(mt, wr);
535 case YAZ_MARC_XCHANGE:
536 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
537 case YAZ_MARC_ISO2709:
538 return yaz_marc_write_iso2709(mt, wr);
540 return yaz_marc_write_check(mt, wr);
545 /** \brief common MARC XML/Xchange writer
547 \param wr WRBUF output
548 \param ns XMLNS for the elements
549 \param format record format (e.g. "MARC21")
550 \param type record type (e.g. "Bibliographic")
552 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
557 struct yaz_marc_node *n;
558 int identifier_length;
559 const char *leader = 0;
561 for (n = mt->nodes; n; n = n->next)
562 if (n->which == YAZ_MARC_LEADER)
564 leader = n->u.leader;
570 if (!atoi_n_check(leader+11, 1, &identifier_length))
573 if (mt->enable_collection != no_collection)
575 if (mt->enable_collection == collection_first)
576 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
577 mt->enable_collection = collection_second;
578 wrbuf_printf(wr, "<record");
582 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
585 wrbuf_printf(wr, " format=\"%.80s\"", format);
587 wrbuf_printf(wr, " type=\"%.80s\"", type);
588 wrbuf_printf(wr, ">\n");
589 for (n = mt->nodes; n; n = n->next)
591 struct yaz_marc_subfield *s;
595 case YAZ_MARC_DATAFIELD:
596 wrbuf_printf(wr, " <datafield tag=\"");
597 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
598 strlen(n->u.datafield.tag));
599 wrbuf_printf(wr, "\"");
600 if (n->u.datafield.indicator)
603 for (i = 0; n->u.datafield.indicator[i]; i++)
605 wrbuf_printf(wr, " ind%d=\"", i+1);
606 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
607 n->u.datafield.indicator+i, 1);
608 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
611 wrbuf_printf(wr, ">\n");
612 for (s = n->u.datafield.subfields; s; s = s->next)
614 /* if identifier length is 2 (most MARCs),
615 the code is a single character .. However we've
616 seen multibyte codes, so see how big it really is */
617 size_t using_code_len =
618 (identifier_length != 2) ? identifier_length - 1
620 cdata_one_character(mt, s->code_data);
622 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
623 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
624 s->code_data, using_code_len);
625 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
626 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
627 s->code_data + using_code_len,
628 strlen(s->code_data + using_code_len));
629 marc_iconv_reset(mt, wr);
630 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
631 wrbuf_puts(wr, "\n");
633 wrbuf_printf(wr, " </datafield>\n");
635 case YAZ_MARC_CONTROLFIELD:
636 wrbuf_printf(wr, " <controlfield tag=\"");
637 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
638 strlen(n->u.controlfield.tag));
639 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
640 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
641 n->u.controlfield.data,
642 strlen(n->u.controlfield.data));
644 marc_iconv_reset(mt, wr);
645 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
646 wrbuf_puts(wr, "\n");
648 case YAZ_MARC_COMMENT:
649 wrbuf_printf(wr, "<!-- ");
650 wrbuf_puts(wr, n->u.comment);
651 wrbuf_printf(wr, " -->\n");
653 case YAZ_MARC_LEADER:
654 wrbuf_printf(wr, " <leader>");
655 wrbuf_iconv_write_cdata(wr,
656 0 /* no charset conversion for leader */,
657 n->u.leader, strlen(n->u.leader));
658 wrbuf_printf(wr, "</leader>\n");
661 wrbuf_puts(wr, "</record>\n");
665 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
670 if (mt->write_using_libxml2)
676 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
680 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
683 xmlDocSetRootElement(doc, root_ptr);
684 xmlDocDumpMemory(doc, &buf_out, &len_out);
686 wrbuf_write(wr, (const char *) buf_out, len_out);
697 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
700 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
702 /* set leader 09 to 'a' for UNICODE */
703 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
704 if (!mt->leader_spec)
705 yaz_marc_modify_leader(mt, 9, "a");
706 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
710 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
714 return yaz_marc_write_marcxml_ns(mt, wr,
715 "http://www.bs.dk/standards/MarcXchange",
720 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
726 struct yaz_marc_node *n;
727 int identifier_length;
728 const char *leader = 0;
733 for (n = mt->nodes; n; n = n->next)
734 if (n->which == YAZ_MARC_LEADER)
736 leader = n->u.leader;
742 if (!atoi_n_check(leader+11, 1, &identifier_length))
745 wr_cdata = wrbuf_alloc();
747 record_ptr = xmlNewNode(0, BAD_CAST "record");
748 *root_ptr = record_ptr;
750 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
751 xmlSetNs(record_ptr, ns_record);
754 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
756 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
757 for (n = mt->nodes; n; n = n->next)
759 struct yaz_marc_subfield *s;
764 case YAZ_MARC_DATAFIELD:
765 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
766 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
767 if (n->u.datafield.indicator)
770 for (i = 0; n->u.datafield.indicator[i]; i++)
775 sprintf(ind_str, "ind%d", i+1);
776 ind_val[0] = n->u.datafield.indicator[i];
778 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
781 for (s = n->u.datafield.subfields; s; s = s->next)
783 xmlNode *ptr_subfield;
784 /* if identifier length is 2 (most MARCs),
785 the code is a single character .. However we've
786 seen multibyte codes, so see how big it really is */
787 size_t using_code_len =
788 (identifier_length != 2) ? identifier_length - 1
790 cdata_one_character(mt, s->code_data);
792 wrbuf_rewind(wr_cdata);
793 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
794 s->code_data + using_code_len);
795 marc_iconv_reset(mt, wr_cdata);
796 ptr_subfield = xmlNewTextChild(
798 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
800 wrbuf_rewind(wr_cdata);
801 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
802 s->code_data, using_code_len);
803 xmlNewProp(ptr_subfield, BAD_CAST "code",
804 BAD_CAST wrbuf_cstr(wr_cdata));
807 case YAZ_MARC_CONTROLFIELD:
808 wrbuf_rewind(wr_cdata);
809 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
810 marc_iconv_reset(mt, wr_cdata);
812 ptr = xmlNewTextChild(record_ptr, ns_record,
813 BAD_CAST "controlfield",
814 BAD_CAST wrbuf_cstr(wr_cdata));
816 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
818 case YAZ_MARC_COMMENT:
819 ptr = xmlNewComment(BAD_CAST n->u.comment);
820 xmlAddChild(record_ptr, ptr);
822 case YAZ_MARC_LEADER:
823 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
824 BAD_CAST n->u.leader);
828 wrbuf_destroy(wr_cdata);
835 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
837 struct yaz_marc_node *n;
838 int indicator_length;
839 int identifier_length;
840 int length_data_entry;
842 int length_implementation;
844 const char *leader = 0;
845 WRBUF wr_dir, wr_head, wr_data_tmp;
848 for (n = mt->nodes; n; n = n->next)
849 if (n->which == YAZ_MARC_LEADER)
850 leader = n->u.leader;
854 if (!atoi_n_check(leader+10, 1, &indicator_length))
856 if (!atoi_n_check(leader+11, 1, &identifier_length))
858 if (!atoi_n_check(leader+20, 1, &length_data_entry))
860 if (!atoi_n_check(leader+21, 1, &length_starting))
862 if (!atoi_n_check(leader+22, 1, &length_implementation))
865 wr_data_tmp = wrbuf_alloc();
866 wr_dir = wrbuf_alloc();
867 for (n = mt->nodes; n; n = n->next)
870 struct yaz_marc_subfield *s;
874 case YAZ_MARC_DATAFIELD:
875 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
876 data_length += indicator_length;
877 wrbuf_rewind(wr_data_tmp);
878 for (s = n->u.datafield.subfields; s; s = s->next)
880 /* write dummy IDFS + content */
881 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
882 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
883 marc_iconv_reset(mt, wr_data_tmp);
885 /* write dummy FS (makes MARC-8 to become ASCII) */
886 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
887 marc_iconv_reset(mt, wr_data_tmp);
888 data_length += wrbuf_len(wr_data_tmp);
890 case YAZ_MARC_CONTROLFIELD:
891 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
893 wrbuf_rewind(wr_data_tmp);
894 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
895 n->u.controlfield.data);
896 marc_iconv_reset(mt, wr_data_tmp);
897 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
898 marc_iconv_reset(mt, wr_data_tmp);
899 data_length += wrbuf_len(wr_data_tmp);
901 case YAZ_MARC_COMMENT:
903 case YAZ_MARC_LEADER:
908 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
909 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
910 data_offset += data_length;
913 /* mark end of directory */
914 wrbuf_putc(wr_dir, ISO2709_FS);
916 /* base address of data (comes after leader+directory) */
917 base_address = 24 + wrbuf_len(wr_dir);
919 wr_head = wrbuf_alloc();
921 /* write record length */
922 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
923 /* from "original" leader */
924 wrbuf_write(wr_head, leader+5, 7);
925 /* base address of data */
926 wrbuf_printf(wr_head, "%05d", base_address);
927 /* from "original" leader */
928 wrbuf_write(wr_head, leader+17, 7);
930 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
931 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
932 wrbuf_destroy(wr_head);
933 wrbuf_destroy(wr_dir);
934 wrbuf_destroy(wr_data_tmp);
936 for (n = mt->nodes; n; n = n->next)
938 struct yaz_marc_subfield *s;
942 case YAZ_MARC_DATAFIELD:
943 wrbuf_printf(wr, "%.*s", indicator_length,
944 n->u.datafield.indicator);
945 for (s = n->u.datafield.subfields; s; s = s->next)
947 wrbuf_putc(wr, ISO2709_IDFS);
948 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
949 marc_iconv_reset(mt, wr);
951 wrbuf_putc(wr, ISO2709_FS);
953 case YAZ_MARC_CONTROLFIELD:
954 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
955 marc_iconv_reset(mt, wr);
956 wrbuf_putc(wr, ISO2709_FS);
958 case YAZ_MARC_COMMENT:
960 case YAZ_MARC_LEADER:
964 wrbuf_printf(wr, "%c", ISO2709_RS);
969 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
971 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
974 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
976 return -1; /* error */
977 return r; /* OK, return length > 0 */
980 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
981 const char **result, size_t *rsize)
985 wrbuf_rewind(mt->m_wr);
986 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
988 *result = wrbuf_cstr(mt->m_wr);
990 *rsize = wrbuf_len(mt->m_wr);
994 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
1000 void yaz_marc_debug(yaz_marc_t mt, int level)
1006 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1011 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1013 return mt->iconv_cd;
1016 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1018 struct yaz_marc_node *n;
1020 for (n = mt->nodes; n; n = n->next)
1021 if (n->which == YAZ_MARC_LEADER)
1023 leader = n->u.leader;
1024 memcpy(leader+off, str, strlen(str));
1029 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1031 xfree(mt->leader_spec);
1032 mt->leader_spec = 0;
1035 char dummy_leader[24];
1036 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1038 mt->leader_spec = xstrdup(leader_spec);
1043 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1045 const char *cp = leader_spec;
1050 int no_read = 0, no = 0;
1052 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1053 if (no < 2 || no_read < 3)
1055 if (pos < 0 || pos >= size)
1060 const char *vp = strchr(val+1, '\'');
1066 if (len + pos > size)
1068 memcpy(leader + pos, val+1, len);
1070 else if (*val >= '0' && *val <= '9')
1086 int yaz_marc_decode_formatstr(const char *arg)
1089 if (!strcmp(arg, "marc"))
1090 mode = YAZ_MARC_ISO2709;
1091 if (!strcmp(arg, "marcxml"))
1092 mode = YAZ_MARC_MARCXML;
1093 if (!strcmp(arg, "marcxchange"))
1094 mode = YAZ_MARC_XCHANGE;
1095 if (!strcmp(arg, "line"))
1096 mode = YAZ_MARC_LINE;
1100 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1102 mt->write_using_libxml2 = enable;
1108 * indent-tabs-mode: nil
1110 * vim: shiftwidth=4 tabstop=8 expandtab