2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.52 2007-12-17 20:59:30 adam Exp $
10 * \brief Implements MARC conversion utilities
25 #include <yaz/marcdisp.h>
26 #include <yaz/wrbuf.h>
27 #include <yaz/yaz-util.h>
28 #include <yaz/nmem_xml.h>
29 #include <yaz/snprintf.h>
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
36 enum yaz_collection_state {
42 /** \brief node types for yaz_marc_node */
43 enum YAZ_MARC_NODE_TYPE
46 YAZ_MARC_CONTROLFIELD,
51 /** \brief represets a data field */
52 struct yaz_marc_datafield {
55 struct yaz_marc_subfield *subfields;
58 /** \brief represents a control field */
59 struct yaz_marc_controlfield {
64 /** \brief a comment node */
65 struct yaz_marc_comment {
69 /** \brief MARC node */
70 struct yaz_marc_node {
71 enum YAZ_MARC_NODE_TYPE which;
73 struct yaz_marc_datafield datafield;
74 struct yaz_marc_controlfield controlfield;
78 struct yaz_marc_node *next;
81 /** \brief represents a subfield */
82 struct yaz_marc_subfield {
84 struct yaz_marc_subfield *next;
87 /** \brief the internals of a yaz_marc_t handle */
93 int write_using_libxml2;
94 enum yaz_collection_state enable_collection;
99 struct yaz_marc_node *nodes;
100 struct yaz_marc_node **nodes_pp;
101 struct yaz_marc_subfield **subfield_pp;
104 yaz_marc_t yaz_marc_create(void)
106 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
107 mt->xml = YAZ_MARC_LINE;
109 mt->write_using_libxml2 = 0;
110 mt->enable_collection = no_collection;
111 mt->m_wr = wrbuf_alloc();
114 strcpy(mt->subfield_str, " $");
115 strcpy(mt->endline_str, "\n");
117 mt->nmem = nmem_create();
122 void yaz_marc_destroy(yaz_marc_t mt)
126 nmem_destroy(mt->nmem);
127 wrbuf_destroy(mt->m_wr);
128 xfree(mt->leader_spec);
132 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
137 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
139 wrbuf_iconv_reset(wr, mt->iconv_cd);
142 static int marc_exec_leader(const char *leader_spec, char *leader,
146 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
148 struct yaz_marc_node *n = (struct yaz_marc_node *)
149 nmem_malloc(mt->nmem, sizeof(*n));
152 mt->nodes_pp = &n->next;
157 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
158 const xmlNode *ptr_data)
160 struct yaz_marc_node *n = yaz_marc_add_node(mt);
161 n->which = YAZ_MARC_CONTROLFIELD;
162 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
163 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
168 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
170 struct yaz_marc_node *n = yaz_marc_add_node(mt);
171 n->which = YAZ_MARC_COMMENT;
172 n->u.comment = nmem_strdup(mt->nmem, comment);
175 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
181 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
182 yaz_marc_add_comment(mt, buf);
186 int yaz_marc_get_debug(yaz_marc_t mt)
191 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
193 struct yaz_marc_node *n = yaz_marc_add_node(mt);
194 n->which = YAZ_MARC_LEADER;
195 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
196 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
199 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
200 const char *data, size_t data_len)
202 struct yaz_marc_node *n = yaz_marc_add_node(mt);
203 n->which = YAZ_MARC_CONTROLFIELD;
204 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
205 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
211 sprintf(msg, "controlfield:");
212 for (i = 0; i < 16 && i < data_len; i++)
213 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
215 sprintf(msg + strlen(msg), " ..");
216 yaz_marc_add_comment(mt, msg);
220 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
221 const char *indicator, size_t indicator_len)
223 struct yaz_marc_node *n = yaz_marc_add_node(mt);
224 n->which = YAZ_MARC_DATAFIELD;
225 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
226 n->u.datafield.indicator =
227 nmem_strdupn(mt->nmem, indicator, indicator_len);
228 n->u.datafield.subfields = 0;
230 /* make subfield_pp the current (last one) */
231 mt->subfield_pp = &n->u.datafield.subfields;
235 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
236 const char *indicator, size_t indicator_len)
238 struct yaz_marc_node *n = yaz_marc_add_node(mt);
239 n->which = YAZ_MARC_DATAFIELD;
240 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
241 n->u.datafield.indicator =
242 nmem_strdupn(mt->nmem, indicator, indicator_len);
243 n->u.datafield.subfields = 0;
245 /* make subfield_pp the current (last one) */
246 mt->subfield_pp = &n->u.datafield.subfields;
250 void yaz_marc_add_subfield(yaz_marc_t mt,
251 const char *code_data, size_t code_data_len)
258 sprintf(msg, "subfield:");
259 for (i = 0; i < 16 && i < code_data_len; i++)
260 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
261 if (i < code_data_len)
262 sprintf(msg + strlen(msg), " ..");
263 yaz_marc_add_comment(mt, msg);
268 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
269 nmem_malloc(mt->nmem, sizeof(*n));
270 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
272 /* mark subfield_pp to point to this one, so we append here next */
273 *mt->subfield_pp = n;
274 mt->subfield_pp = &n->next;
278 int atoi_n_check(const char *buf, int size, int *val)
281 for (i = 0; i < size; i++)
282 if (!isdigit(i[(const unsigned char *) buf]))
284 *val = atoi_n(buf, size);
288 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
289 int *indicator_length,
290 int *identifier_length,
292 int *length_data_entry,
293 int *length_starting,
294 int *length_implementation)
298 memcpy(leader, leader_c, 24);
300 if (!atoi_n_check(leader+10, 1, indicator_length))
303 "Indicator length at offset 10 should hold a digit."
306 *indicator_length = 2;
308 if (!atoi_n_check(leader+11, 1, identifier_length))
311 "Identifier length at offset 11 should hold a digit."
314 *identifier_length = 2;
316 if (!atoi_n_check(leader+12, 5, base_address))
319 "Base address at offsets 12..16 should hold a number."
323 if (!atoi_n_check(leader+20, 1, length_data_entry))
326 "Length data entry at offset 20 should hold a digit."
328 *length_data_entry = 4;
331 if (!atoi_n_check(leader+21, 1, length_starting))
334 "Length starting at offset 21 should hold a digit."
336 *length_starting = 5;
339 if (!atoi_n_check(leader+22, 1, length_implementation))
342 "Length implementation at offset 22 should hold a digit."
344 *length_implementation = 0;
350 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
351 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
352 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
353 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
354 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
355 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
357 yaz_marc_add_leader(mt, leader, 24);
360 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
362 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
363 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
366 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
368 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
369 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
372 /* try to guess how many bytes the identifier really is! */
373 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
378 for (i = 1; i<5; i++)
381 size_t outbytesleft = sizeof(outbuf);
383 const char *inp = buf;
385 size_t inbytesleft = i;
386 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
387 &outp, &outbytesleft);
388 if (r != (size_t) (-1))
389 return i; /* got a complete sequence */
391 return 1; /* giving up */
393 return 1; /* we don't know */
396 void yaz_marc_reset(yaz_marc_t mt)
398 nmem_reset(mt->nmem);
400 mt->nodes_pp = &mt->nodes;
404 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
406 struct yaz_marc_node *n;
407 int identifier_length;
408 const char *leader = 0;
410 for (n = mt->nodes; n; n = n->next)
411 if (n->which == YAZ_MARC_LEADER)
413 leader = n->u.leader;
419 if (!atoi_n_check(leader+11, 1, &identifier_length))
422 for (n = mt->nodes; n; n = n->next)
426 case YAZ_MARC_COMMENT:
427 wrbuf_iconv_write(wr, mt->iconv_cd,
428 n->u.comment, strlen(n->u.comment));
429 wrbuf_puts(wr, ")\n");
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 /* if identifier length is 2 (most MARCs),
468 the code is a single character .. However we've
469 seen multibyte codes, so see how big it really is */
470 size_t using_code_len =
471 (identifier_length != 2) ? identifier_length - 1
473 cdata_one_character(mt, s->code_data);
475 wrbuf_puts (wr, mt->subfield_str);
476 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
478 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
479 wrbuf_iconv_puts(wr, mt->iconv_cd,
480 s->code_data + using_code_len);
481 marc_iconv_reset(mt, wr);
483 wrbuf_puts (wr, mt->endline_str);
485 case YAZ_MARC_CONTROLFIELD:
486 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
487 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
488 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
489 marc_iconv_reset(mt, wr);
490 wrbuf_puts (wr, mt->endline_str);
492 case YAZ_MARC_COMMENT:
494 wrbuf_iconv_write(wr, mt->iconv_cd,
495 n->u.comment, strlen(n->u.comment));
496 marc_iconv_reset(mt, wr);
497 wrbuf_puts(wr, ")\n");
499 case YAZ_MARC_LEADER:
500 wrbuf_printf(wr, "%s\n", n->u.leader);
503 wrbuf_puts(wr, "\n");
507 int yaz_marc_write_trailer(yaz_marc_t mt, WRBUF wr)
509 if (mt->enable_collection == collection_second)
513 case YAZ_MARC_MARCXML:
514 wrbuf_printf(wr, "</collection>\n");
516 case YAZ_MARC_XCHANGE:
517 wrbuf_printf(wr, "</collection>\n");
524 void yaz_marc_enable_collection(yaz_marc_t mt)
526 mt->enable_collection = collection_first;
529 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
534 return yaz_marc_write_line(mt, wr);
535 case YAZ_MARC_MARCXML:
536 return yaz_marc_write_marcxml(mt, wr);
537 case YAZ_MARC_XCHANGE:
538 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
539 case YAZ_MARC_ISO2709:
540 return yaz_marc_write_iso2709(mt, wr);
542 return yaz_marc_write_check(mt, wr);
547 /** \brief common MARC XML/Xchange writer
549 \param wr WRBUF output
550 \param ns XMLNS for the elements
551 \param format record format (e.g. "MARC21")
552 \param type record type (e.g. "Bibliographic")
554 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
559 struct yaz_marc_node *n;
560 int identifier_length;
561 const char *leader = 0;
563 for (n = mt->nodes; n; n = n->next)
564 if (n->which == YAZ_MARC_LEADER)
566 leader = n->u.leader;
572 if (!atoi_n_check(leader+11, 1, &identifier_length))
575 if (mt->enable_collection != no_collection)
577 if (mt->enable_collection == collection_first)
578 wrbuf_printf(wr, "<collection xmlns=\"%s\">\n", ns);
579 mt->enable_collection = collection_second;
580 wrbuf_printf(wr, "<record");
584 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
587 wrbuf_printf(wr, " format=\"%.80s\"", format);
589 wrbuf_printf(wr, " type=\"%.80s\"", type);
590 wrbuf_printf(wr, ">\n");
591 for (n = mt->nodes; n; n = n->next)
593 struct yaz_marc_subfield *s;
597 case YAZ_MARC_DATAFIELD:
598 wrbuf_printf(wr, " <datafield tag=\"");
599 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
600 strlen(n->u.datafield.tag));
601 wrbuf_printf(wr, "\"");
602 if (n->u.datafield.indicator)
605 for (i = 0; n->u.datafield.indicator[i]; i++)
607 wrbuf_printf(wr, " ind%d=\"", i+1);
608 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
609 n->u.datafield.indicator+i, 1);
610 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
613 wrbuf_printf(wr, ">\n");
614 for (s = n->u.datafield.subfields; s; s = s->next)
616 /* if identifier length is 2 (most MARCs),
617 the code is a single character .. However we've
618 seen multibyte codes, so see how big it really is */
619 size_t using_code_len =
620 (identifier_length != 2) ? identifier_length - 1
622 cdata_one_character(mt, s->code_data);
624 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
625 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
626 s->code_data, using_code_len);
627 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
628 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
629 s->code_data + using_code_len,
630 strlen(s->code_data + using_code_len));
631 marc_iconv_reset(mt, wr);
632 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
633 wrbuf_puts(wr, "\n");
635 wrbuf_printf(wr, " </datafield>\n");
637 case YAZ_MARC_CONTROLFIELD:
638 wrbuf_printf(wr, " <controlfield tag=\"");
639 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
640 strlen(n->u.controlfield.tag));
641 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
642 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
643 n->u.controlfield.data,
644 strlen(n->u.controlfield.data));
646 marc_iconv_reset(mt, wr);
647 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
648 wrbuf_puts(wr, "\n");
650 case YAZ_MARC_COMMENT:
651 wrbuf_printf(wr, "<!-- ");
652 wrbuf_puts(wr, n->u.comment);
653 wrbuf_printf(wr, " -->\n");
655 case YAZ_MARC_LEADER:
656 wrbuf_printf(wr, " <leader>");
657 wrbuf_iconv_write_cdata(wr,
658 0 /* no charset conversion for leader */,
659 n->u.leader, strlen(n->u.leader));
660 wrbuf_printf(wr, "</leader>\n");
663 wrbuf_puts(wr, "</record>\n");
667 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
672 if (mt->write_using_libxml2)
678 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
682 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
685 xmlDocSetRootElement(doc, root_ptr);
686 xmlDocDumpMemory(doc, &buf_out, &len_out);
688 wrbuf_write(wr, (const char *) buf_out, len_out);
699 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
702 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
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 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
1013 struct yaz_marc_node *n;
1015 for (n = mt->nodes; n; n = n->next)
1016 if (n->which == YAZ_MARC_LEADER)
1018 leader = n->u.leader;
1019 memcpy(leader+off, str, strlen(str));
1024 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1026 xfree(mt->leader_spec);
1027 mt->leader_spec = 0;
1030 char dummy_leader[24];
1031 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1033 mt->leader_spec = xstrdup(leader_spec);
1038 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1040 const char *cp = leader_spec;
1045 int no_read = 0, no = 0;
1047 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1048 if (no < 2 || no_read < 3)
1050 if (pos < 0 || pos >= size)
1055 const char *vp = strchr(val+1, '\'');
1061 if (len + pos > size)
1063 memcpy(leader + pos, val+1, len);
1065 else if (*val >= '0' && *val <= '9')
1081 int yaz_marc_decode_formatstr(const char *arg)
1084 if (!strcmp(arg, "marc"))
1085 mode = YAZ_MARC_ISO2709;
1086 if (!strcmp(arg, "marcxml"))
1087 mode = YAZ_MARC_MARCXML;
1088 if (!strcmp(arg, "marcxchange"))
1089 mode = YAZ_MARC_XCHANGE;
1090 if (!strcmp(arg, "line"))
1091 mode = YAZ_MARC_LINE;
1095 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1097 mt->write_using_libxml2 = enable;
1103 * indent-tabs-mode: nil
1105 * vim: shiftwidth=4 tabstop=8 expandtab