1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2010 Index Data
3 * See the file LICENSE for details.
8 * \brief Implements MARC conversion utilities
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>
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
35 enum yaz_collection_state {
41 /** \brief node types for yaz_marc_node */
42 enum YAZ_MARC_NODE_TYPE
45 YAZ_MARC_CONTROLFIELD,
50 /** \brief represets a data field */
51 struct yaz_marc_datafield {
54 struct yaz_marc_subfield *subfields;
57 /** \brief represents a control field */
58 struct yaz_marc_controlfield {
63 /** \brief a comment node */
64 struct yaz_marc_comment {
68 /** \brief MARC node */
69 struct yaz_marc_node {
70 enum YAZ_MARC_NODE_TYPE which;
72 struct yaz_marc_datafield datafield;
73 struct yaz_marc_controlfield controlfield;
77 struct yaz_marc_node *next;
80 /** \brief represents a subfield */
81 struct yaz_marc_subfield {
83 struct yaz_marc_subfield *next;
86 /** \brief the internals of a yaz_marc_t handle */
92 int write_using_libxml2;
93 enum yaz_collection_state enable_collection;
98 struct yaz_marc_node *nodes;
99 struct yaz_marc_node **nodes_pp;
100 struct yaz_marc_subfield **subfield_pp;
103 yaz_marc_t yaz_marc_create(void)
105 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
106 mt->xml = YAZ_MARC_LINE;
108 mt->write_using_libxml2 = 0;
109 mt->enable_collection = no_collection;
110 mt->m_wr = wrbuf_alloc();
113 strcpy(mt->subfield_str, " $");
114 strcpy(mt->endline_str, "\n");
116 mt->nmem = nmem_create();
121 void yaz_marc_destroy(yaz_marc_t mt)
125 nmem_destroy(mt->nmem);
126 wrbuf_destroy(mt->m_wr);
127 xfree(mt->leader_spec);
131 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
136 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
138 wrbuf_iconv_reset(wr, mt->iconv_cd);
141 static int marc_exec_leader(const char *leader_spec, char *leader,
145 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
147 struct yaz_marc_node *n = (struct yaz_marc_node *)
148 nmem_malloc(mt->nmem, sizeof(*n));
151 mt->nodes_pp = &n->next;
156 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
157 const xmlNode *ptr_data)
159 struct yaz_marc_node *n = yaz_marc_add_node(mt);
160 n->which = YAZ_MARC_CONTROLFIELD;
161 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
162 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
167 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
169 struct yaz_marc_node *n = yaz_marc_add_node(mt);
170 n->which = YAZ_MARC_COMMENT;
171 n->u.comment = nmem_strdup(mt->nmem, comment);
174 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
180 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
181 yaz_marc_add_comment(mt, buf);
185 int yaz_marc_get_debug(yaz_marc_t mt)
190 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
192 struct yaz_marc_node *n = yaz_marc_add_node(mt);
193 n->which = YAZ_MARC_LEADER;
194 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
195 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
198 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
199 const char *data, size_t data_len)
201 struct yaz_marc_node *n = yaz_marc_add_node(mt);
202 n->which = YAZ_MARC_CONTROLFIELD;
203 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
204 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
210 sprintf(msg, "controlfield:");
211 for (i = 0; i < 16 && i < data_len; i++)
212 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
214 sprintf(msg + strlen(msg), " ..");
215 yaz_marc_add_comment(mt, msg);
219 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
220 const char *indicator, size_t indicator_len)
222 struct yaz_marc_node *n = yaz_marc_add_node(mt);
223 n->which = YAZ_MARC_DATAFIELD;
224 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
225 n->u.datafield.indicator =
226 nmem_strdupn(mt->nmem, indicator, indicator_len);
227 n->u.datafield.subfields = 0;
229 /* make subfield_pp the current (last one) */
230 mt->subfield_pp = &n->u.datafield.subfields;
234 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
235 const char *indicator, size_t indicator_len)
237 struct yaz_marc_node *n = yaz_marc_add_node(mt);
238 n->which = YAZ_MARC_DATAFIELD;
239 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
240 n->u.datafield.indicator =
241 nmem_strdupn(mt->nmem, indicator, indicator_len);
242 n->u.datafield.subfields = 0;
244 /* make subfield_pp the current (last one) */
245 mt->subfield_pp = &n->u.datafield.subfields;
249 void yaz_marc_add_subfield(yaz_marc_t mt,
250 const char *code_data, size_t code_data_len)
257 sprintf(msg, "subfield:");
258 for (i = 0; i < 16 && i < code_data_len; i++)
259 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
260 if (i < code_data_len)
261 sprintf(msg + strlen(msg), " ..");
262 yaz_marc_add_comment(mt, msg);
267 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
268 nmem_malloc(mt->nmem, sizeof(*n));
269 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
271 /* mark subfield_pp to point to this one, so we append here next */
272 *mt->subfield_pp = n;
273 mt->subfield_pp = &n->next;
277 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
278 int *indicator_length,
279 int *identifier_length,
281 int *length_data_entry,
282 int *length_starting,
283 int *length_implementation)
287 memcpy(leader, leader_c, 24);
289 if (!atoi_n_check(leader+10, 1, indicator_length))
292 "Indicator length at offset 10 should hold a digit."
295 *indicator_length = 2;
297 if (!atoi_n_check(leader+11, 1, identifier_length))
300 "Identifier length at offset 11 should hold a digit."
303 *identifier_length = 2;
305 if (!atoi_n_check(leader+12, 5, base_address))
308 "Base address at offsets 12..16 should hold a number."
312 if (!atoi_n_check(leader+20, 1, length_data_entry))
315 "Length data entry at offset 20 should hold a digit."
317 *length_data_entry = 4;
320 if (!atoi_n_check(leader+21, 1, length_starting))
323 "Length starting at offset 21 should hold a digit."
325 *length_starting = 5;
328 if (!atoi_n_check(leader+22, 1, length_implementation))
331 "Length implementation at offset 22 should hold a digit."
333 *length_implementation = 0;
339 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
340 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
341 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
342 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
343 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
344 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
346 yaz_marc_add_leader(mt, leader, 24);
349 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
351 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
352 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
355 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
357 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
358 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
361 /* try to guess how many bytes the identifier really is! */
362 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
367 for (i = 1; i<5; i++)
370 size_t outbytesleft = sizeof(outbuf);
372 const char *inp = buf;
374 size_t inbytesleft = i;
375 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
376 &outp, &outbytesleft);
377 if (r != (size_t) (-1))
378 return i; /* got a complete sequence */
380 return 1; /* giving up */
382 return 1; /* we don't know */
385 void yaz_marc_reset(yaz_marc_t mt)
387 nmem_reset(mt->nmem);
389 mt->nodes_pp = &mt->nodes;
393 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
395 struct yaz_marc_node *n;
396 int identifier_length;
397 const char *leader = 0;
399 for (n = mt->nodes; n; n = n->next)
400 if (n->which == YAZ_MARC_LEADER)
402 leader = n->u.leader;
408 if (!atoi_n_check(leader+11, 1, &identifier_length))
411 for (n = mt->nodes; n; n = n->next)
415 case YAZ_MARC_COMMENT:
416 wrbuf_iconv_write(wr, mt->iconv_cd,
417 n->u.comment, strlen(n->u.comment));
418 wrbuf_puts(wr, "\n");
427 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
428 int identifier_length)
430 /* if identifier length is 2 (most MARCs) or less (probably an error),
431 the code is a single character .. However we've
432 seen multibyte codes, so see how big it really is */
433 if (identifier_length > 2)
434 return identifier_length - 1;
436 return cdata_one_character(mt, data);
439 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
441 struct yaz_marc_node *n;
442 int identifier_length;
443 const char *leader = 0;
445 for (n = mt->nodes; n; n = n->next)
446 if (n->which == YAZ_MARC_LEADER)
448 leader = n->u.leader;
454 if (!atoi_n_check(leader+11, 1, &identifier_length))
457 for (n = mt->nodes; n; n = n->next)
459 struct yaz_marc_subfield *s;
462 case YAZ_MARC_DATAFIELD:
463 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
464 n->u.datafield.indicator);
465 for (s = n->u.datafield.subfields; s; s = s->next)
467 size_t using_code_len = get_subfield_len(mt, s->code_data,
470 wrbuf_puts (wr, mt->subfield_str);
471 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
473 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
474 wrbuf_iconv_puts(wr, mt->iconv_cd,
475 s->code_data + using_code_len);
476 marc_iconv_reset(mt, wr);
478 wrbuf_puts (wr, mt->endline_str);
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 marc_iconv_reset(mt, wr);
485 wrbuf_puts (wr, mt->endline_str);
487 case YAZ_MARC_COMMENT:
489 wrbuf_iconv_write(wr, mt->iconv_cd,
490 n->u.comment, strlen(n->u.comment));
491 marc_iconv_reset(mt, wr);
492 wrbuf_puts(wr, ")\n");
494 case YAZ_MARC_LEADER:
495 wrbuf_printf(wr, "%s\n", n->u.leader);
498 wrbuf_puts(wr, "\n");
502 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
504 if (mt->enable_collection == collection_second)
508 case YAZ_MARC_MARCXML:
509 wrbuf_printf(wr, "</collection>\n");
511 case YAZ_MARC_XCHANGE:
512 wrbuf_printf(wr, "</collection>\n");
519 void yaz_marc_enable_collection(yaz_marc_t mt)
521 mt->enable_collection = collection_first;
524 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
529 return yaz_marc_write_line(mt, wr);
530 case YAZ_MARC_MARCXML:
531 return yaz_marc_write_marcxml(mt, wr);
532 case YAZ_MARC_XCHANGE:
533 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
534 case YAZ_MARC_ISO2709:
535 return yaz_marc_write_iso2709(mt, wr);
537 return yaz_marc_write_check(mt, wr);
542 /** \brief common MARC XML/Xchange writer
544 \param wr WRBUF output
545 \param ns XMLNS for the elements
546 \param format record format (e.g. "MARC21")
547 \param type record type (e.g. "Bibliographic")
549 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
554 struct yaz_marc_node *n;
555 int identifier_length;
556 const char *leader = 0;
558 for (n = mt->nodes; n; n = n->next)
559 if (n->which == YAZ_MARC_LEADER)
561 leader = n->u.leader;
567 if (!atoi_n_check(leader+11, 1, &identifier_length))
570 if (mt->enable_collection != no_collection)
572 if (mt->enable_collection == collection_first)
573 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
574 mt->enable_collection = collection_second;
575 wrbuf_printf(wr, "<record");
579 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
582 wrbuf_printf(wr, " format=\"%.80s\"", format);
584 wrbuf_printf(wr, " type=\"%.80s\"", type);
585 wrbuf_printf(wr, ">\n");
586 for (n = mt->nodes; n; n = n->next)
588 struct yaz_marc_subfield *s;
592 case YAZ_MARC_DATAFIELD:
593 wrbuf_printf(wr, " <datafield tag=\"");
594 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
595 strlen(n->u.datafield.tag));
596 wrbuf_printf(wr, "\"");
597 if (n->u.datafield.indicator)
600 for (i = 0; n->u.datafield.indicator[i]; i++)
602 wrbuf_printf(wr, " ind%d=\"", i+1);
603 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
604 n->u.datafield.indicator+i, 1);
605 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
608 wrbuf_printf(wr, ">\n");
609 for (s = n->u.datafield.subfields; s; s = s->next)
611 size_t using_code_len = get_subfield_len(mt, s->code_data,
613 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
614 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
615 s->code_data, using_code_len);
616 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
617 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
618 s->code_data + using_code_len,
619 strlen(s->code_data + using_code_len));
620 marc_iconv_reset(mt, wr);
621 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
622 wrbuf_puts(wr, "\n");
624 wrbuf_printf(wr, " </datafield>\n");
626 case YAZ_MARC_CONTROLFIELD:
627 wrbuf_printf(wr, " <controlfield tag=\"");
628 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
629 strlen(n->u.controlfield.tag));
630 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
631 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
632 n->u.controlfield.data,
633 strlen(n->u.controlfield.data));
635 marc_iconv_reset(mt, wr);
636 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
637 wrbuf_puts(wr, "\n");
639 case YAZ_MARC_COMMENT:
640 wrbuf_printf(wr, "<!-- ");
641 wrbuf_puts(wr, n->u.comment);
642 wrbuf_printf(wr, " -->\n");
644 case YAZ_MARC_LEADER:
645 wrbuf_printf(wr, " <leader>");
646 wrbuf_iconv_write_cdata(wr,
647 0 /* no charset conversion for leader */,
648 n->u.leader, strlen(n->u.leader));
649 wrbuf_printf(wr, "</leader>\n");
652 wrbuf_puts(wr, "</record>\n");
656 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
661 if (mt->write_using_libxml2)
667 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
671 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
674 xmlDocSetRootElement(doc, root_ptr);
675 xmlDocDumpMemory(doc, &buf_out, &len_out);
677 wrbuf_write(wr, (const char *) buf_out, len_out);
688 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
691 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
693 /* set leader 09 to 'a' for UNICODE */
694 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
695 if (!mt->leader_spec)
696 yaz_marc_modify_leader(mt, 9, "a");
697 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
701 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
705 return yaz_marc_write_marcxml_ns(mt, wr,
706 "info:lc/xmlns/marcxchange-v1",
712 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
717 struct yaz_marc_node *n;
718 int identifier_length;
719 const char *leader = 0;
724 for (n = mt->nodes; n; n = n->next)
725 if (n->which == YAZ_MARC_LEADER)
727 leader = n->u.leader;
733 if (!atoi_n_check(leader+11, 1, &identifier_length))
736 wr_cdata = wrbuf_alloc();
738 record_ptr = xmlNewNode(0, BAD_CAST "record");
739 *root_ptr = record_ptr;
741 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
742 xmlSetNs(record_ptr, ns_record);
745 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
747 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
748 for (n = mt->nodes; n; n = n->next)
750 struct yaz_marc_subfield *s;
755 case YAZ_MARC_DATAFIELD:
756 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
757 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
758 if (n->u.datafield.indicator)
761 for (i = 0; n->u.datafield.indicator[i]; i++)
766 sprintf(ind_str, "ind%d", i+1);
767 ind_val[0] = n->u.datafield.indicator[i];
769 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
772 for (s = n->u.datafield.subfields; s; s = s->next)
774 xmlNode *ptr_subfield;
775 size_t using_code_len = get_subfield_len(mt, s->code_data,
777 wrbuf_rewind(wr_cdata);
778 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
779 s->code_data + using_code_len);
780 marc_iconv_reset(mt, wr_cdata);
781 ptr_subfield = xmlNewTextChild(
783 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
785 wrbuf_rewind(wr_cdata);
786 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
787 s->code_data, using_code_len);
788 xmlNewProp(ptr_subfield, BAD_CAST "code",
789 BAD_CAST wrbuf_cstr(wr_cdata));
792 case YAZ_MARC_CONTROLFIELD:
793 wrbuf_rewind(wr_cdata);
794 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
795 marc_iconv_reset(mt, wr_cdata);
797 ptr = xmlNewTextChild(record_ptr, ns_record,
798 BAD_CAST "controlfield",
799 BAD_CAST wrbuf_cstr(wr_cdata));
801 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
803 case YAZ_MARC_COMMENT:
804 ptr = xmlNewComment(BAD_CAST n->u.comment);
805 xmlAddChild(record_ptr, ptr);
807 case YAZ_MARC_LEADER:
808 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
809 BAD_CAST n->u.leader);
813 wrbuf_destroy(wr_cdata);
818 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
820 struct yaz_marc_node *n;
821 int indicator_length;
822 int identifier_length;
823 int length_data_entry;
825 int length_implementation;
827 const char *leader = 0;
828 WRBUF wr_dir, wr_head, wr_data_tmp;
831 for (n = mt->nodes; n; n = n->next)
832 if (n->which == YAZ_MARC_LEADER)
833 leader = n->u.leader;
837 if (!atoi_n_check(leader+10, 1, &indicator_length))
839 if (!atoi_n_check(leader+11, 1, &identifier_length))
841 if (!atoi_n_check(leader+20, 1, &length_data_entry))
843 if (!atoi_n_check(leader+21, 1, &length_starting))
845 if (!atoi_n_check(leader+22, 1, &length_implementation))
848 wr_data_tmp = wrbuf_alloc();
849 wr_dir = wrbuf_alloc();
850 for (n = mt->nodes; n; n = n->next)
853 struct yaz_marc_subfield *s;
857 case YAZ_MARC_DATAFIELD:
858 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
859 data_length += indicator_length;
860 wrbuf_rewind(wr_data_tmp);
861 for (s = n->u.datafield.subfields; s; s = s->next)
863 /* write dummy IDFS + content */
864 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
865 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
866 marc_iconv_reset(mt, wr_data_tmp);
868 /* write dummy FS (makes MARC-8 to become ASCII) */
869 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
870 marc_iconv_reset(mt, wr_data_tmp);
871 data_length += wrbuf_len(wr_data_tmp);
873 case YAZ_MARC_CONTROLFIELD:
874 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
876 wrbuf_rewind(wr_data_tmp);
877 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
878 n->u.controlfield.data);
879 marc_iconv_reset(mt, wr_data_tmp);
880 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
881 marc_iconv_reset(mt, wr_data_tmp);
882 data_length += wrbuf_len(wr_data_tmp);
884 case YAZ_MARC_COMMENT:
886 case YAZ_MARC_LEADER:
891 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
892 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
893 data_offset += data_length;
896 /* mark end of directory */
897 wrbuf_putc(wr_dir, ISO2709_FS);
899 /* base address of data (comes after leader+directory) */
900 base_address = 24 + wrbuf_len(wr_dir);
902 wr_head = wrbuf_alloc();
904 /* write record length */
905 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
906 /* from "original" leader */
907 wrbuf_write(wr_head, leader+5, 7);
908 /* base address of data */
909 wrbuf_printf(wr_head, "%05d", base_address);
910 /* from "original" leader */
911 wrbuf_write(wr_head, leader+17, 7);
913 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
914 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
915 wrbuf_destroy(wr_head);
916 wrbuf_destroy(wr_dir);
917 wrbuf_destroy(wr_data_tmp);
919 for (n = mt->nodes; n; n = n->next)
921 struct yaz_marc_subfield *s;
925 case YAZ_MARC_DATAFIELD:
926 wrbuf_printf(wr, "%.*s", indicator_length,
927 n->u.datafield.indicator);
928 for (s = n->u.datafield.subfields; s; s = s->next)
930 wrbuf_putc(wr, ISO2709_IDFS);
931 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
932 marc_iconv_reset(mt, wr);
934 wrbuf_putc(wr, ISO2709_FS);
936 case YAZ_MARC_CONTROLFIELD:
937 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
938 marc_iconv_reset(mt, wr);
939 wrbuf_putc(wr, ISO2709_FS);
941 case YAZ_MARC_COMMENT:
943 case YAZ_MARC_LEADER:
947 wrbuf_printf(wr, "%c", ISO2709_RS);
952 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
954 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
957 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
959 return -1; /* error */
960 return r; /* OK, return length > 0 */
963 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
964 const char **result, size_t *rsize)
968 wrbuf_rewind(mt->m_wr);
969 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
971 *result = wrbuf_cstr(mt->m_wr);
973 *rsize = wrbuf_len(mt->m_wr);
977 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
983 void yaz_marc_debug(yaz_marc_t mt, int level)
989 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
994 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
999 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1001 struct yaz_marc_node *n;
1003 for (n = mt->nodes; n; n = n->next)
1004 if (n->which == YAZ_MARC_LEADER)
1006 leader = n->u.leader;
1007 memcpy(leader+off, str, strlen(str));
1012 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1014 xfree(mt->leader_spec);
1015 mt->leader_spec = 0;
1018 char dummy_leader[24];
1019 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1021 mt->leader_spec = xstrdup(leader_spec);
1026 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1028 const char *cp = leader_spec;
1033 int no_read = 0, no = 0;
1035 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1036 if (no < 2 || no_read < 3)
1038 if (pos < 0 || (size_t) pos >= size)
1043 const char *vp = strchr(val+1, '\'');
1049 if (len + pos > size)
1051 memcpy(leader + pos, val+1, len);
1053 else if (*val >= '0' && *val <= '9')
1069 int yaz_marc_decode_formatstr(const char *arg)
1072 if (!strcmp(arg, "marc"))
1073 mode = YAZ_MARC_ISO2709;
1074 if (!strcmp(arg, "marcxml"))
1075 mode = YAZ_MARC_MARCXML;
1076 if (!strcmp(arg, "marcxchange"))
1077 mode = YAZ_MARC_XCHANGE;
1078 if (!strcmp(arg, "line"))
1079 mode = YAZ_MARC_LINE;
1083 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1085 mt->write_using_libxml2 = enable;
1091 * c-file-style: "Stroustrup"
1092 * indent-tabs-mode: nil
1094 * vim: shiftwidth=4 tabstop=8 expandtab