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
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");
438 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
440 struct yaz_marc_node *n;
441 int identifier_length;
442 const char *leader = 0;
444 for (n = mt->nodes; n; n = n->next)
445 if (n->which == YAZ_MARC_LEADER)
447 leader = n->u.leader;
453 if (!atoi_n_check(leader+11, 1, &identifier_length))
456 for (n = mt->nodes; n; n = n->next)
458 struct yaz_marc_subfield *s;
461 case YAZ_MARC_DATAFIELD:
462 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
463 n->u.datafield.indicator);
464 for (s = n->u.datafield.subfields; s; s = s->next)
466 /* if identifier length is 2 (most MARCs),
467 the code is a single character .. However we've
468 seen multibyte codes, so see how big it really is */
469 size_t using_code_len =
470 (identifier_length != 2) ? identifier_length - 1
472 cdata_one_character(mt, s->code_data);
474 wrbuf_puts (wr, mt->subfield_str);
475 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
477 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
478 wrbuf_iconv_puts(wr, mt->iconv_cd,
479 s->code_data + using_code_len);
480 marc_iconv_reset(mt, wr);
482 wrbuf_puts (wr, mt->endline_str);
484 case YAZ_MARC_CONTROLFIELD:
485 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
486 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
487 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
488 marc_iconv_reset(mt, wr);
489 wrbuf_puts (wr, mt->endline_str);
491 case YAZ_MARC_COMMENT:
493 wrbuf_iconv_write(wr, mt->iconv_cd,
494 n->u.comment, strlen(n->u.comment));
495 marc_iconv_reset(mt, wr);
496 wrbuf_puts(wr, ")\n");
498 case YAZ_MARC_LEADER:
499 wrbuf_printf(wr, "%s\n", n->u.leader);
502 wrbuf_puts(wr, "\n");
506 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
508 if (mt->enable_collection == collection_second)
512 case YAZ_MARC_MARCXML:
513 wrbuf_printf(wr, "</collection>\n");
515 case YAZ_MARC_XCHANGE:
516 wrbuf_printf(wr, "</collection>\n");
523 void yaz_marc_enable_collection(yaz_marc_t mt)
525 mt->enable_collection = collection_first;
528 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
533 return yaz_marc_write_line(mt, wr);
534 case YAZ_MARC_MARCXML:
535 return yaz_marc_write_marcxml(mt, wr);
536 case YAZ_MARC_XCHANGE:
537 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
538 case YAZ_MARC_ISO2709:
539 return yaz_marc_write_iso2709(mt, wr);
541 return yaz_marc_write_check(mt, wr);
546 /** \brief common MARC XML/Xchange writer
548 \param wr WRBUF output
549 \param ns XMLNS for the elements
550 \param format record format (e.g. "MARC21")
551 \param type record type (e.g. "Bibliographic")
553 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
558 struct yaz_marc_node *n;
559 int identifier_length;
560 const char *leader = 0;
562 for (n = mt->nodes; n; n = n->next)
563 if (n->which == YAZ_MARC_LEADER)
565 leader = n->u.leader;
571 if (!atoi_n_check(leader+11, 1, &identifier_length))
574 if (mt->enable_collection != no_collection)
576 if (mt->enable_collection == collection_first)
577 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
578 mt->enable_collection = collection_second;
579 wrbuf_printf(wr, "<record");
583 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
586 wrbuf_printf(wr, " format=\"%.80s\"", format);
588 wrbuf_printf(wr, " type=\"%.80s\"", type);
589 wrbuf_printf(wr, ">\n");
590 for (n = mt->nodes; n; n = n->next)
592 struct yaz_marc_subfield *s;
596 case YAZ_MARC_DATAFIELD:
597 wrbuf_printf(wr, " <datafield tag=\"");
598 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
599 strlen(n->u.datafield.tag));
600 wrbuf_printf(wr, "\"");
601 if (n->u.datafield.indicator)
604 for (i = 0; n->u.datafield.indicator[i]; i++)
606 wrbuf_printf(wr, " ind%d=\"", i+1);
607 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
608 n->u.datafield.indicator+i, 1);
609 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
612 wrbuf_printf(wr, ">\n");
613 for (s = n->u.datafield.subfields; s; s = s->next)
615 /* if identifier length is 2 (most MARCs),
616 the code is a single character .. However we've
617 seen multibyte codes, so see how big it really is */
618 size_t using_code_len =
619 (identifier_length != 2) ? identifier_length - 1
621 cdata_one_character(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 /* if identifier length is 2 (most MARCs),
786 the code is a single character .. However we've
787 seen multibyte codes, so see how big it really is */
788 size_t using_code_len =
789 (identifier_length != 2) ? identifier_length - 1
791 cdata_one_character(mt, s->code_data);
793 wrbuf_rewind(wr_cdata);
794 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
795 s->code_data + using_code_len);
796 marc_iconv_reset(mt, wr_cdata);
797 ptr_subfield = xmlNewTextChild(
799 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
801 wrbuf_rewind(wr_cdata);
802 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
803 s->code_data, using_code_len);
804 xmlNewProp(ptr_subfield, BAD_CAST "code",
805 BAD_CAST wrbuf_cstr(wr_cdata));
808 case YAZ_MARC_CONTROLFIELD:
809 wrbuf_rewind(wr_cdata);
810 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
811 marc_iconv_reset(mt, wr_cdata);
813 ptr = xmlNewTextChild(record_ptr, ns_record,
814 BAD_CAST "controlfield",
815 BAD_CAST wrbuf_cstr(wr_cdata));
817 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
819 case YAZ_MARC_COMMENT:
820 ptr = xmlNewComment(BAD_CAST n->u.comment);
821 xmlAddChild(record_ptr, ptr);
823 case YAZ_MARC_LEADER:
824 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
825 BAD_CAST n->u.leader);
829 wrbuf_destroy(wr_cdata);
834 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
836 struct yaz_marc_node *n;
837 int indicator_length;
838 int identifier_length;
839 int length_data_entry;
841 int length_implementation;
843 const char *leader = 0;
844 WRBUF wr_dir, wr_head, wr_data_tmp;
847 for (n = mt->nodes; n; n = n->next)
848 if (n->which == YAZ_MARC_LEADER)
849 leader = n->u.leader;
853 if (!atoi_n_check(leader+10, 1, &indicator_length))
855 if (!atoi_n_check(leader+11, 1, &identifier_length))
857 if (!atoi_n_check(leader+20, 1, &length_data_entry))
859 if (!atoi_n_check(leader+21, 1, &length_starting))
861 if (!atoi_n_check(leader+22, 1, &length_implementation))
864 wr_data_tmp = wrbuf_alloc();
865 wr_dir = wrbuf_alloc();
866 for (n = mt->nodes; n; n = n->next)
869 struct yaz_marc_subfield *s;
873 case YAZ_MARC_DATAFIELD:
874 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
875 data_length += indicator_length;
876 wrbuf_rewind(wr_data_tmp);
877 for (s = n->u.datafield.subfields; s; s = s->next)
879 /* write dummy IDFS + content */
880 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
881 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
882 marc_iconv_reset(mt, wr_data_tmp);
884 /* write dummy FS (makes MARC-8 to become ASCII) */
885 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
886 marc_iconv_reset(mt, wr_data_tmp);
887 data_length += wrbuf_len(wr_data_tmp);
889 case YAZ_MARC_CONTROLFIELD:
890 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
892 wrbuf_rewind(wr_data_tmp);
893 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
894 n->u.controlfield.data);
895 marc_iconv_reset(mt, wr_data_tmp);
896 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
897 marc_iconv_reset(mt, wr_data_tmp);
898 data_length += wrbuf_len(wr_data_tmp);
900 case YAZ_MARC_COMMENT:
902 case YAZ_MARC_LEADER:
907 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
908 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
909 data_offset += data_length;
912 /* mark end of directory */
913 wrbuf_putc(wr_dir, ISO2709_FS);
915 /* base address of data (comes after leader+directory) */
916 base_address = 24 + wrbuf_len(wr_dir);
918 wr_head = wrbuf_alloc();
920 /* write record length */
921 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
922 /* from "original" leader */
923 wrbuf_write(wr_head, leader+5, 7);
924 /* base address of data */
925 wrbuf_printf(wr_head, "%05d", base_address);
926 /* from "original" leader */
927 wrbuf_write(wr_head, leader+17, 7);
929 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
930 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
931 wrbuf_destroy(wr_head);
932 wrbuf_destroy(wr_dir);
933 wrbuf_destroy(wr_data_tmp);
935 for (n = mt->nodes; n; n = n->next)
937 struct yaz_marc_subfield *s;
941 case YAZ_MARC_DATAFIELD:
942 wrbuf_printf(wr, "%.*s", indicator_length,
943 n->u.datafield.indicator);
944 for (s = n->u.datafield.subfields; s; s = s->next)
946 wrbuf_putc(wr, ISO2709_IDFS);
947 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
948 marc_iconv_reset(mt, wr);
950 wrbuf_putc(wr, ISO2709_FS);
952 case YAZ_MARC_CONTROLFIELD:
953 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
954 marc_iconv_reset(mt, wr);
955 wrbuf_putc(wr, ISO2709_FS);
957 case YAZ_MARC_COMMENT:
959 case YAZ_MARC_LEADER:
963 wrbuf_printf(wr, "%c", ISO2709_RS);
968 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
970 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
973 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
975 return -1; /* error */
976 return r; /* OK, return length > 0 */
979 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
980 const char **result, size_t *rsize)
984 wrbuf_rewind(mt->m_wr);
985 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
987 *result = wrbuf_cstr(mt->m_wr);
989 *rsize = wrbuf_len(mt->m_wr);
993 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
999 void yaz_marc_debug(yaz_marc_t mt, int level)
1005 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
1010 yaz_iconv_t yaz_marc_get_iconv(yaz_marc_t mt)
1012 return mt->iconv_cd;
1015 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1017 struct yaz_marc_node *n;
1019 for (n = mt->nodes; n; n = n->next)
1020 if (n->which == YAZ_MARC_LEADER)
1022 leader = n->u.leader;
1023 memcpy(leader+off, str, strlen(str));
1028 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1030 xfree(mt->leader_spec);
1031 mt->leader_spec = 0;
1034 char dummy_leader[24];
1035 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1037 mt->leader_spec = xstrdup(leader_spec);
1042 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1044 const char *cp = leader_spec;
1049 int no_read = 0, no = 0;
1051 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1052 if (no < 2 || no_read < 3)
1054 if (pos < 0 || pos >= size)
1059 const char *vp = strchr(val+1, '\'');
1065 if (len + pos > size)
1067 memcpy(leader + pos, val+1, len);
1069 else if (*val >= '0' && *val <= '9')
1085 int yaz_marc_decode_formatstr(const char *arg)
1088 if (!strcmp(arg, "marc"))
1089 mode = YAZ_MARC_ISO2709;
1090 if (!strcmp(arg, "marcxml"))
1091 mode = YAZ_MARC_MARCXML;
1092 if (!strcmp(arg, "marcxchange"))
1093 mode = YAZ_MARC_XCHANGE;
1094 if (!strcmp(arg, "line"))
1095 mode = YAZ_MARC_LINE;
1099 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1101 mt->write_using_libxml2 = enable;
1107 * indent-tabs-mode: nil
1109 * vim: shiftwidth=4 tabstop=8 expandtab