1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2009 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 int atoi_n_check(const char *buf, int size, int *val)
280 for (i = 0; i < size; i++)
281 if (!isdigit(i[(const unsigned char *) buf]))
283 *val = atoi_n(buf, size);
287 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
288 int *indicator_length,
289 int *identifier_length,
291 int *length_data_entry,
292 int *length_starting,
293 int *length_implementation)
297 memcpy(leader, leader_c, 24);
299 if (!atoi_n_check(leader+10, 1, indicator_length))
302 "Indicator length at offset 10 should hold a digit."
305 *indicator_length = 2;
307 if (!atoi_n_check(leader+11, 1, identifier_length))
310 "Identifier length at offset 11 should hold a digit."
313 *identifier_length = 2;
315 if (!atoi_n_check(leader+12, 5, base_address))
318 "Base address at offsets 12..16 should hold a number."
322 if (!atoi_n_check(leader+20, 1, length_data_entry))
325 "Length data entry at offset 20 should hold a digit."
327 *length_data_entry = 4;
330 if (!atoi_n_check(leader+21, 1, length_starting))
333 "Length starting at offset 21 should hold a digit."
335 *length_starting = 5;
338 if (!atoi_n_check(leader+22, 1, length_implementation))
341 "Length implementation at offset 22 should hold a digit."
343 *length_implementation = 0;
349 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
350 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
351 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
352 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
353 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
354 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
356 yaz_marc_add_leader(mt, leader, 24);
359 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
361 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
362 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
365 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
367 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
368 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
371 /* try to guess how many bytes the identifier really is! */
372 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
377 for (i = 1; i<5; i++)
380 size_t outbytesleft = sizeof(outbuf);
382 const char *inp = buf;
384 size_t inbytesleft = i;
385 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
386 &outp, &outbytesleft);
387 if (r != (size_t) (-1))
388 return i; /* got a complete sequence */
390 return 1; /* giving up */
392 return 1; /* we don't know */
395 void yaz_marc_reset(yaz_marc_t mt)
397 nmem_reset(mt->nmem);
399 mt->nodes_pp = &mt->nodes;
403 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
405 struct yaz_marc_node *n;
406 int identifier_length;
407 const char *leader = 0;
409 for (n = mt->nodes; n; n = n->next)
410 if (n->which == YAZ_MARC_LEADER)
412 leader = n->u.leader;
418 if (!atoi_n_check(leader+11, 1, &identifier_length))
421 for (n = mt->nodes; n; n = n->next)
425 case YAZ_MARC_COMMENT:
426 wrbuf_iconv_write(wr, mt->iconv_cd,
427 n->u.comment, strlen(n->u.comment));
428 wrbuf_puts(wr, ")\n");
437 static size_t get_subfield_len(yaz_marc_t mt, const char *data,
438 int identifier_length)
440 /* if identifier length is 2 (most MARCs) or less (probably an error),
441 the code is a single character .. However we've
442 seen multibyte codes, so see how big it really is */
443 if (identifier_length > 2)
444 return identifier_length - 1;
446 return cdata_one_character(mt, data);
449 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
451 struct yaz_marc_node *n;
452 int identifier_length;
453 const char *leader = 0;
455 for (n = mt->nodes; n; n = n->next)
456 if (n->which == YAZ_MARC_LEADER)
458 leader = n->u.leader;
464 if (!atoi_n_check(leader+11, 1, &identifier_length))
467 for (n = mt->nodes; n; n = n->next)
469 struct yaz_marc_subfield *s;
472 case YAZ_MARC_DATAFIELD:
473 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
474 n->u.datafield.indicator);
475 for (s = n->u.datafield.subfields; s; s = s->next)
477 size_t using_code_len = get_subfield_len(mt, s->code_data,
480 wrbuf_puts (wr, mt->subfield_str);
481 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
483 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
484 wrbuf_iconv_puts(wr, mt->iconv_cd,
485 s->code_data + using_code_len);
486 marc_iconv_reset(mt, wr);
488 wrbuf_puts (wr, mt->endline_str);
490 case YAZ_MARC_CONTROLFIELD:
491 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
492 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
493 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
494 marc_iconv_reset(mt, wr);
495 wrbuf_puts (wr, mt->endline_str);
497 case YAZ_MARC_COMMENT:
499 wrbuf_iconv_write(wr, mt->iconv_cd,
500 n->u.comment, strlen(n->u.comment));
501 marc_iconv_reset(mt, wr);
502 wrbuf_puts(wr, ")\n");
504 case YAZ_MARC_LEADER:
505 wrbuf_printf(wr, "%s\n", n->u.leader);
508 wrbuf_puts(wr, "\n");
512 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
514 if (mt->enable_collection == collection_second)
518 case YAZ_MARC_MARCXML:
519 wrbuf_printf(wr, "</collection>\n");
521 case YAZ_MARC_XCHANGE:
522 wrbuf_printf(wr, "</collection>\n");
529 void yaz_marc_enable_collection(yaz_marc_t mt)
531 mt->enable_collection = collection_first;
534 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
539 return yaz_marc_write_line(mt, wr);
540 case YAZ_MARC_MARCXML:
541 return yaz_marc_write_marcxml(mt, wr);
542 case YAZ_MARC_XCHANGE:
543 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
544 case YAZ_MARC_ISO2709:
545 return yaz_marc_write_iso2709(mt, wr);
547 return yaz_marc_write_check(mt, wr);
552 /** \brief common MARC XML/Xchange writer
554 \param wr WRBUF output
555 \param ns XMLNS for the elements
556 \param format record format (e.g. "MARC21")
557 \param type record type (e.g. "Bibliographic")
559 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
564 struct yaz_marc_node *n;
565 int identifier_length;
566 const char *leader = 0;
568 for (n = mt->nodes; n; n = n->next)
569 if (n->which == YAZ_MARC_LEADER)
571 leader = n->u.leader;
577 if (!atoi_n_check(leader+11, 1, &identifier_length))
580 if (mt->enable_collection != no_collection)
582 if (mt->enable_collection == collection_first)
583 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
584 mt->enable_collection = collection_second;
585 wrbuf_printf(wr, "<record");
589 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
592 wrbuf_printf(wr, " format=\"%.80s\"", format);
594 wrbuf_printf(wr, " type=\"%.80s\"", type);
595 wrbuf_printf(wr, ">\n");
596 for (n = mt->nodes; n; n = n->next)
598 struct yaz_marc_subfield *s;
602 case YAZ_MARC_DATAFIELD:
603 wrbuf_printf(wr, " <datafield tag=\"");
604 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
605 strlen(n->u.datafield.tag));
606 wrbuf_printf(wr, "\"");
607 if (n->u.datafield.indicator)
610 for (i = 0; n->u.datafield.indicator[i]; i++)
612 wrbuf_printf(wr, " ind%d=\"", i+1);
613 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
614 n->u.datafield.indicator+i, 1);
615 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
618 wrbuf_printf(wr, ">\n");
619 for (s = n->u.datafield.subfields; s; s = s->next)
621 size_t using_code_len = get_subfield_len(mt, s->code_data,
623 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
624 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
625 s->code_data, using_code_len);
626 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
627 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
628 s->code_data + using_code_len,
629 strlen(s->code_data + using_code_len));
630 marc_iconv_reset(mt, wr);
631 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
632 wrbuf_puts(wr, "\n");
634 wrbuf_printf(wr, " </datafield>\n");
636 case YAZ_MARC_CONTROLFIELD:
637 wrbuf_printf(wr, " <controlfield tag=\"");
638 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
639 strlen(n->u.controlfield.tag));
640 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
641 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
642 n->u.controlfield.data,
643 strlen(n->u.controlfield.data));
645 marc_iconv_reset(mt, wr);
646 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
647 wrbuf_puts(wr, "\n");
649 case YAZ_MARC_COMMENT:
650 wrbuf_printf(wr, "<!-- ");
651 wrbuf_puts(wr, n->u.comment);
652 wrbuf_printf(wr, " -->\n");
654 case YAZ_MARC_LEADER:
655 wrbuf_printf(wr, " <leader>");
656 wrbuf_iconv_write_cdata(wr,
657 0 /* no charset conversion for leader */,
658 n->u.leader, strlen(n->u.leader));
659 wrbuf_printf(wr, "</leader>\n");
662 wrbuf_puts(wr, "</record>\n");
666 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
671 if (mt->write_using_libxml2)
677 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
681 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
684 xmlDocSetRootElement(doc, root_ptr);
685 xmlDocDumpMemory(doc, &buf_out, &len_out);
687 wrbuf_write(wr, (const char *) buf_out, len_out);
698 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
701 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
703 /* set leader 09 to 'a' for UNICODE */
704 /* http://www.loc.gov/marc/bibliographic/ecbdldrd.html#mrcblea */
705 if (!mt->leader_spec)
706 yaz_marc_modify_leader(mt, 9, "a");
707 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
711 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
715 return yaz_marc_write_marcxml_ns(mt, wr,
716 "http://www.bs.dk/standards/MarcXchange",
722 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
727 struct yaz_marc_node *n;
728 int identifier_length;
729 const char *leader = 0;
734 for (n = mt->nodes; n; n = n->next)
735 if (n->which == YAZ_MARC_LEADER)
737 leader = n->u.leader;
743 if (!atoi_n_check(leader+11, 1, &identifier_length))
746 wr_cdata = wrbuf_alloc();
748 record_ptr = xmlNewNode(0, BAD_CAST "record");
749 *root_ptr = record_ptr;
751 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
752 xmlSetNs(record_ptr, ns_record);
755 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
757 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
758 for (n = mt->nodes; n; n = n->next)
760 struct yaz_marc_subfield *s;
765 case YAZ_MARC_DATAFIELD:
766 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
767 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
768 if (n->u.datafield.indicator)
771 for (i = 0; n->u.datafield.indicator[i]; i++)
776 sprintf(ind_str, "ind%d", i+1);
777 ind_val[0] = n->u.datafield.indicator[i];
779 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
782 for (s = n->u.datafield.subfields; s; s = s->next)
784 xmlNode *ptr_subfield;
785 size_t using_code_len = get_subfield_len(mt, s->code_data,
787 wrbuf_rewind(wr_cdata);
788 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
789 s->code_data + using_code_len);
790 marc_iconv_reset(mt, wr_cdata);
791 ptr_subfield = xmlNewTextChild(
793 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
795 wrbuf_rewind(wr_cdata);
796 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
797 s->code_data, using_code_len);
798 xmlNewProp(ptr_subfield, BAD_CAST "code",
799 BAD_CAST wrbuf_cstr(wr_cdata));
802 case YAZ_MARC_CONTROLFIELD:
803 wrbuf_rewind(wr_cdata);
804 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
805 marc_iconv_reset(mt, wr_cdata);
807 ptr = xmlNewTextChild(record_ptr, ns_record,
808 BAD_CAST "controlfield",
809 BAD_CAST wrbuf_cstr(wr_cdata));
811 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
813 case YAZ_MARC_COMMENT:
814 ptr = xmlNewComment(BAD_CAST n->u.comment);
815 xmlAddChild(record_ptr, ptr);
817 case YAZ_MARC_LEADER:
818 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
819 BAD_CAST n->u.leader);
823 wrbuf_destroy(wr_cdata);
828 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
830 struct yaz_marc_node *n;
831 int indicator_length;
832 int identifier_length;
833 int length_data_entry;
835 int length_implementation;
837 const char *leader = 0;
838 WRBUF wr_dir, wr_head, wr_data_tmp;
841 for (n = mt->nodes; n; n = n->next)
842 if (n->which == YAZ_MARC_LEADER)
843 leader = n->u.leader;
847 if (!atoi_n_check(leader+10, 1, &indicator_length))
849 if (!atoi_n_check(leader+11, 1, &identifier_length))
851 if (!atoi_n_check(leader+20, 1, &length_data_entry))
853 if (!atoi_n_check(leader+21, 1, &length_starting))
855 if (!atoi_n_check(leader+22, 1, &length_implementation))
858 wr_data_tmp = wrbuf_alloc();
859 wr_dir = wrbuf_alloc();
860 for (n = mt->nodes; n; n = n->next)
863 struct yaz_marc_subfield *s;
867 case YAZ_MARC_DATAFIELD:
868 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
869 data_length += indicator_length;
870 wrbuf_rewind(wr_data_tmp);
871 for (s = n->u.datafield.subfields; s; s = s->next)
873 /* write dummy IDFS + content */
874 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
875 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
876 marc_iconv_reset(mt, wr_data_tmp);
878 /* write dummy FS (makes MARC-8 to become ASCII) */
879 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
880 marc_iconv_reset(mt, wr_data_tmp);
881 data_length += wrbuf_len(wr_data_tmp);
883 case YAZ_MARC_CONTROLFIELD:
884 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
886 wrbuf_rewind(wr_data_tmp);
887 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
888 n->u.controlfield.data);
889 marc_iconv_reset(mt, wr_data_tmp);
890 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
891 marc_iconv_reset(mt, wr_data_tmp);
892 data_length += wrbuf_len(wr_data_tmp);
894 case YAZ_MARC_COMMENT:
896 case YAZ_MARC_LEADER:
901 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
902 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
903 data_offset += data_length;
906 /* mark end of directory */
907 wrbuf_putc(wr_dir, ISO2709_FS);
909 /* base address of data (comes after leader+directory) */
910 base_address = 24 + wrbuf_len(wr_dir);
912 wr_head = wrbuf_alloc();
914 /* write record length */
915 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
916 /* from "original" leader */
917 wrbuf_write(wr_head, leader+5, 7);
918 /* base address of data */
919 wrbuf_printf(wr_head, "%05d", base_address);
920 /* from "original" leader */
921 wrbuf_write(wr_head, leader+17, 7);
923 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
924 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
925 wrbuf_destroy(wr_head);
926 wrbuf_destroy(wr_dir);
927 wrbuf_destroy(wr_data_tmp);
929 for (n = mt->nodes; n; n = n->next)
931 struct yaz_marc_subfield *s;
935 case YAZ_MARC_DATAFIELD:
936 wrbuf_printf(wr, "%.*s", indicator_length,
937 n->u.datafield.indicator);
938 for (s = n->u.datafield.subfields; s; s = s->next)
940 wrbuf_putc(wr, ISO2709_IDFS);
941 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
942 marc_iconv_reset(mt, wr);
944 wrbuf_putc(wr, ISO2709_FS);
946 case YAZ_MARC_CONTROLFIELD:
947 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
948 marc_iconv_reset(mt, wr);
949 wrbuf_putc(wr, ISO2709_FS);
951 case YAZ_MARC_COMMENT:
953 case YAZ_MARC_LEADER:
957 wrbuf_printf(wr, "%c", ISO2709_RS);
962 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
964 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
967 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
969 return -1; /* error */
970 return r; /* OK, return length > 0 */
973 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
974 const char **result, size_t *rsize)
978 wrbuf_rewind(mt->m_wr);
979 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
981 *result = wrbuf_cstr(mt->m_wr);
983 *rsize = wrbuf_len(mt->m_wr);
987 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
993 void yaz_marc_debug(yaz_marc_t mt, int level)
999 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1004 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1006 return mt->iconv_cd;
1009 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1011 struct yaz_marc_node *n;
1013 for (n = mt->nodes; n; n = n->next)
1014 if (n->which == YAZ_MARC_LEADER)
1016 leader = n->u.leader;
1017 memcpy(leader+off, str, strlen(str));
1022 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1024 xfree(mt->leader_spec);
1025 mt->leader_spec = 0;
1028 char dummy_leader[24];
1029 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1031 mt->leader_spec = xstrdup(leader_spec);
1036 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1038 const char *cp = leader_spec;
1043 int no_read = 0, no = 0;
1045 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1046 if (no < 2 || no_read < 3)
1048 if (pos < 0 || (size_t) pos >= size)
1053 const char *vp = strchr(val+1, '\'');
1059 if (len + pos > size)
1061 memcpy(leader + pos, val+1, len);
1063 else if (*val >= '0' && *val <= '9')
1079 int yaz_marc_decode_formatstr(const char *arg)
1082 if (!strcmp(arg, "marc"))
1083 mode = YAZ_MARC_ISO2709;
1084 if (!strcmp(arg, "marcxml"))
1085 mode = YAZ_MARC_MARCXML;
1086 if (!strcmp(arg, "marcxchange"))
1087 mode = YAZ_MARC_XCHANGE;
1088 if (!strcmp(arg, "line"))
1089 mode = YAZ_MARC_LINE;
1093 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1095 mt->write_using_libxml2 = enable;
1101 * c-file-style: "Stroustrup"
1102 * indent-tabs-mode: nil
1104 * vim: shiftwidth=4 tabstop=8 expandtab