2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.44 2007-01-18 14:45:05 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>
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
35 /** \brief node types for yaz_marc_node */
36 enum YAZ_MARC_NODE_TYPE
39 YAZ_MARC_CONTROLFIELD,
44 /** \brief represets a data field */
45 struct yaz_marc_datafield {
48 struct yaz_marc_subfield *subfields;
51 /** \brief represents a control field */
52 struct yaz_marc_controlfield {
57 /** \brief a comment node */
58 struct yaz_marc_comment {
62 /** \brief MARC node */
63 struct yaz_marc_node {
64 enum YAZ_MARC_NODE_TYPE which;
66 struct yaz_marc_datafield datafield;
67 struct yaz_marc_controlfield controlfield;
71 struct yaz_marc_node *next;
74 /** \brief represents a subfield */
75 struct yaz_marc_subfield {
77 struct yaz_marc_subfield *next;
80 /** \brief the internals of a yaz_marc_t handle */
86 int write_using_libxml2;
91 struct yaz_marc_node *nodes;
92 struct yaz_marc_node **nodes_pp;
93 struct yaz_marc_subfield **subfield_pp;
96 yaz_marc_t yaz_marc_create(void)
98 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
99 mt->xml = YAZ_MARC_LINE;
101 mt->write_using_libxml2 = 0;
102 mt->m_wr = wrbuf_alloc();
105 strcpy(mt->subfield_str, " $");
106 strcpy(mt->endline_str, "\n");
108 mt->nmem = nmem_create();
113 void yaz_marc_destroy(yaz_marc_t mt)
117 nmem_destroy(mt->nmem);
118 wrbuf_free(mt->m_wr, 1);
119 xfree(mt->leader_spec);
123 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
128 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
134 size_t outbytesleft = sizeof(outbuf);
136 size_t r = yaz_iconv(mt->iconv_cd, 0, 0, &outp, &outbytesleft);
137 if (r != (size_t) (-1))
138 wrbuf_write(wr, outbuf, outp - outbuf);
141 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
144 yaz_iconv(mt->iconv_cd, 0, 0, 0, 0);
149 static int marc_exec_leader(const char *leader_spec, char *leader,
153 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
155 struct yaz_marc_node *n = nmem_malloc(mt->nmem, sizeof(*n));
158 mt->nodes_pp = &n->next;
163 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
164 const xmlNode *ptr_data)
166 struct yaz_marc_node *n = yaz_marc_add_node(mt);
167 n->which = YAZ_MARC_CONTROLFIELD;
168 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
169 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
174 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
176 struct yaz_marc_node *n = yaz_marc_add_node(mt);
177 n->which = YAZ_MARC_COMMENT;
178 n->u.comment = nmem_strdup(mt->nmem, comment);
181 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
188 _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
192 vsnprintf(buf, sizeof(buf), fmt, ap);
194 vsprintf(buf, fmt, ap);
198 yaz_marc_add_comment(mt, buf);
202 int yaz_marc_get_debug(yaz_marc_t mt)
207 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
209 struct yaz_marc_node *n = yaz_marc_add_node(mt);
210 n->which = YAZ_MARC_LEADER;
211 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
212 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
215 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
216 const char *data, size_t data_len)
218 struct yaz_marc_node *n = yaz_marc_add_node(mt);
219 n->which = YAZ_MARC_CONTROLFIELD;
220 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
221 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
227 sprintf(msg, "controlfield:");
228 for (i = 0; i < 16 && i < data_len; i++)
229 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
231 sprintf(msg + strlen(msg), " ..");
232 yaz_marc_add_comment(mt, msg);
236 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
237 const char *indicator, size_t indicator_len)
239 struct yaz_marc_node *n = yaz_marc_add_node(mt);
240 n->which = YAZ_MARC_DATAFIELD;
241 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
242 n->u.datafield.indicator =
243 nmem_strdupn(mt->nmem, indicator, indicator_len);
244 n->u.datafield.subfields = 0;
246 /* make subfield_pp the current (last one) */
247 mt->subfield_pp = &n->u.datafield.subfields;
251 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
252 const char *indicator, size_t indicator_len)
254 struct yaz_marc_node *n = yaz_marc_add_node(mt);
255 n->which = YAZ_MARC_DATAFIELD;
256 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
257 n->u.datafield.indicator =
258 nmem_strdupn(mt->nmem, indicator, indicator_len);
259 n->u.datafield.subfields = 0;
261 /* make subfield_pp the current (last one) */
262 mt->subfield_pp = &n->u.datafield.subfields;
266 void yaz_marc_add_subfield(yaz_marc_t mt,
267 const char *code_data, size_t code_data_len)
274 sprintf(msg, "subfield:");
275 for (i = 0; i < 16 && i < code_data_len; i++)
276 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
277 if (i < code_data_len)
278 sprintf(msg + strlen(msg), " ..");
279 yaz_marc_add_comment(mt, msg);
284 struct yaz_marc_subfield *n = nmem_malloc(mt->nmem, sizeof(*n));
285 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
287 /* mark subfield_pp to point to this one, so we append here next */
288 *mt->subfield_pp = n;
289 mt->subfield_pp = &n->next;
293 int atoi_n_check(const char *buf, int size, int *val)
296 for (i = 0; i < size; i++)
297 if (!isdigit(i[(const unsigned char *) buf]))
299 *val = atoi_n(buf, size);
303 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
304 int *indicator_length,
305 int *identifier_length,
307 int *length_data_entry,
308 int *length_starting,
309 int *length_implementation)
313 memcpy(leader, leader_c, 24);
315 if (!atoi_n_check(leader+10, 1, indicator_length))
318 "Indicator length at offset 10 should hold a digit."
321 *indicator_length = 2;
323 if (!atoi_n_check(leader+11, 1, identifier_length))
326 "Identifier length at offset 11 should hold a digit."
329 *identifier_length = 2;
331 if (!atoi_n_check(leader+12, 5, base_address))
334 "Base address at offsets 12..16 should hold a number."
338 if (!atoi_n_check(leader+20, 1, length_data_entry))
341 "Length data entry at offset 20 should hold a digit."
343 *length_data_entry = 4;
346 if (!atoi_n_check(leader+21, 1, length_starting))
349 "Length starting at offset 21 should hold a digit."
351 *length_starting = 5;
354 if (!atoi_n_check(leader+22, 1, length_implementation))
357 "Length implementation at offset 22 should hold a digit."
359 *length_implementation = 0;
365 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
366 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
367 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
368 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
369 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
370 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
372 yaz_marc_add_leader(mt, leader, 24);
375 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
377 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
378 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
381 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
383 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
384 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
387 /* try to guess how many bytes the identifier really is! */
388 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
393 for (i = 1; i<5; i++)
396 size_t outbytesleft = sizeof(outbuf);
398 const char *inp = buf;
400 size_t inbytesleft = i;
401 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
402 &outp, &outbytesleft);
403 if (r != (size_t) (-1))
404 return i; /* got a complete sequence */
406 return 1; /* giving up */
408 return 1; /* we don't know */
411 void yaz_marc_reset(yaz_marc_t mt)
413 nmem_reset(mt->nmem);
415 mt->nodes_pp = &mt->nodes;
419 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
421 struct yaz_marc_node *n;
422 int identifier_length;
423 const char *leader = 0;
425 for (n = mt->nodes; n; n = n->next)
426 if (n->which == YAZ_MARC_LEADER)
428 leader = n->u.leader;
434 if (!atoi_n_check(leader+11, 1, &identifier_length))
437 for (n = mt->nodes; n; n = n->next)
441 case YAZ_MARC_COMMENT:
442 wrbuf_iconv_write(wr, mt->iconv_cd,
443 n->u.comment, strlen(n->u.comment));
444 wrbuf_puts(wr, ")\n");
454 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
456 struct yaz_marc_node *n;
457 int identifier_length;
458 const char *leader = 0;
460 for (n = mt->nodes; n; n = n->next)
461 if (n->which == YAZ_MARC_LEADER)
463 leader = n->u.leader;
469 if (!atoi_n_check(leader+11, 1, &identifier_length))
472 for (n = mt->nodes; n; n = n->next)
474 struct yaz_marc_subfield *s;
477 case YAZ_MARC_DATAFIELD:
478 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
479 n->u.datafield.indicator);
480 for (s = n->u.datafield.subfields; s; s = s->next)
482 /* if identifier length is 2 (most MARCs),
483 the code is a single character .. However we've
484 seen multibyte codes, so see how big it really is */
485 size_t using_code_len =
486 (identifier_length != 2) ? identifier_length - 1
488 cdata_one_character(mt, s->code_data);
490 wrbuf_puts (wr, mt->subfield_str);
491 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
493 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
494 wrbuf_iconv_puts(wr, mt->iconv_cd,
495 s->code_data + using_code_len);
496 marc_iconv_reset(mt, wr);
498 wrbuf_puts (wr, mt->endline_str);
500 case YAZ_MARC_CONTROLFIELD:
501 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
502 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
503 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
504 marc_iconv_reset(mt, wr);
505 wrbuf_puts (wr, mt->endline_str);
507 case YAZ_MARC_COMMENT:
509 wrbuf_iconv_write(wr, mt->iconv_cd,
510 n->u.comment, strlen(n->u.comment));
511 wrbuf_puts(wr, ")\n");
513 case YAZ_MARC_LEADER:
514 wrbuf_printf(wr, "%s\n", n->u.leader);
517 wrbuf_puts(wr, "\n");
521 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
526 return yaz_marc_write_line(mt, wr);
527 case YAZ_MARC_MARCXML:
528 return yaz_marc_write_marcxml(mt, wr);
529 case YAZ_MARC_XCHANGE:
530 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
531 case YAZ_MARC_ISO2709:
532 return yaz_marc_write_iso2709(mt, wr);
534 return yaz_marc_write_check(mt, wr);
539 /** \brief common MARC XML/Xchange writer
541 \param wr WRBUF output
542 \param ns XMLNS for the elements
543 \param format record format (e.g. "MARC21")
544 \param type record type (e.g. "Bibliographic")
546 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
551 struct yaz_marc_node *n;
552 int identifier_length;
553 const char *leader = 0;
555 for (n = mt->nodes; n; n = n->next)
556 if (n->which == YAZ_MARC_LEADER)
558 leader = n->u.leader;
564 if (!atoi_n_check(leader+11, 1, &identifier_length))
567 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
569 wrbuf_printf(wr, " format=\"%.80s\"", format);
571 wrbuf_printf(wr, " type=\"%.80s\"", type);
572 wrbuf_printf(wr, ">\n");
573 for (n = mt->nodes; n; n = n->next)
575 struct yaz_marc_subfield *s;
579 case YAZ_MARC_DATAFIELD:
580 wrbuf_printf(wr, " <datafield tag=\"");
581 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
582 strlen(n->u.datafield.tag));
583 wrbuf_printf(wr, "\"");
584 if (n->u.datafield.indicator)
587 for (i = 0; n->u.datafield.indicator[i]; i++)
589 wrbuf_printf(wr, " ind%d=\"", i+1);
590 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
591 n->u.datafield.indicator+i, 1);
592 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
595 wrbuf_printf(wr, ">\n");
596 for (s = n->u.datafield.subfields; s; s = s->next)
598 /* if identifier length is 2 (most MARCs),
599 the code is a single character .. However we've
600 seen multibyte codes, so see how big it really is */
601 size_t using_code_len =
602 (identifier_length != 2) ? identifier_length - 1
604 cdata_one_character(mt, s->code_data);
606 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
607 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
608 s->code_data, using_code_len);
609 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
610 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
611 s->code_data + using_code_len,
612 strlen(s->code_data + using_code_len));
613 marc_iconv_reset(mt, wr);
614 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
615 wrbuf_puts(wr, "\n");
617 wrbuf_printf(wr, " </datafield>\n");
619 case YAZ_MARC_CONTROLFIELD:
620 wrbuf_printf(wr, " <controlfield tag=\"");
621 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
622 strlen(n->u.controlfield.tag));
623 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
624 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
626 marc_iconv_reset(mt, wr);
627 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
628 wrbuf_puts(wr, "\n");
630 case YAZ_MARC_COMMENT:
631 wrbuf_printf(wr, "<!-- ");
632 wrbuf_puts(wr, n->u.comment);
633 wrbuf_printf(wr, " -->\n");
635 case YAZ_MARC_LEADER:
636 wrbuf_printf(wr, " <leader>");
637 wrbuf_iconv_write_cdata(wr,
638 0 /* no charset conversion for leader */,
639 n->u.leader, strlen(n->u.leader));
640 wrbuf_printf(wr, "</leader>\n");
643 wrbuf_puts(wr, "</record>\n");
647 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
652 if (mt->write_using_libxml2)
657 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
661 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
664 xmlDocSetRootElement(doc, root_ptr);
665 xmlDocDumpMemory(doc, &buf_out, &len_out);
667 wrbuf_write(wr, (const char *) buf_out, len_out);
675 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
678 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
680 if (!mt->leader_spec)
681 yaz_marc_modify_leader(mt, 9, "a");
682 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
686 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
690 return yaz_marc_write_marcxml_ns(mt, wr,
691 "http://www.bs.dk/standards/MarcXchange",
696 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
702 struct yaz_marc_node *n;
703 int identifier_length;
704 const char *leader = 0;
709 for (n = mt->nodes; n; n = n->next)
710 if (n->which == YAZ_MARC_LEADER)
712 leader = n->u.leader;
718 if (!atoi_n_check(leader+11, 1, &identifier_length))
721 wr_cdata = wrbuf_alloc();
723 record_ptr = xmlNewNode(0, BAD_CAST "record");
724 *root_ptr = record_ptr;
726 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
727 xmlSetNs(record_ptr, ns_record);
730 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
732 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
733 for (n = mt->nodes; n; n = n->next)
735 struct yaz_marc_subfield *s;
740 case YAZ_MARC_DATAFIELD:
741 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
742 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
743 if (n->u.datafield.indicator)
746 for (i = 0; n->u.datafield.indicator[i]; i++)
751 sprintf(ind_str, "ind%d", i+1);
752 ind_val[0] = n->u.datafield.indicator[i];
754 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
757 for (s = n->u.datafield.subfields; s; s = s->next)
759 xmlNode *ptr_subfield;
760 /* if identifier length is 2 (most MARCs),
761 the code is a single character .. However we've
762 seen multibyte codes, so see how big it really is */
763 size_t using_code_len =
764 (identifier_length != 2) ? identifier_length - 1
766 cdata_one_character(mt, s->code_data);
768 wrbuf_rewind(wr_cdata);
769 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
770 s->code_data + using_code_len);
771 marc_iconv_reset(mt, wr_cdata);
772 ptr_subfield = xmlNewTextChild(
774 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
776 wrbuf_rewind(wr_cdata);
777 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
778 s->code_data, using_code_len);
779 xmlNewProp(ptr_subfield, BAD_CAST "code",
780 BAD_CAST wrbuf_cstr(wr_cdata));
783 case YAZ_MARC_CONTROLFIELD:
784 wrbuf_rewind(wr_cdata);
785 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
786 marc_iconv_reset(mt, wr_cdata);
788 ptr = xmlNewTextChild(record_ptr, ns_record,
789 BAD_CAST "controlfield",
790 BAD_CAST wrbuf_cstr(wr_cdata));
792 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
794 case YAZ_MARC_COMMENT:
795 ptr = xmlNewComment(BAD_CAST n->u.comment);
796 xmlAddChild(record_ptr, ptr);
798 case YAZ_MARC_LEADER:
799 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
800 BAD_CAST n->u.leader);
804 wrbuf_destroy(wr_cdata);
811 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
813 struct yaz_marc_node *n;
814 int indicator_length;
815 int identifier_length;
816 int length_data_entry;
818 int length_implementation;
820 const char *leader = 0;
821 WRBUF wr_dir, wr_head, wr_data_tmp;
824 for (n = mt->nodes; n; n = n->next)
825 if (n->which == YAZ_MARC_LEADER)
826 leader = n->u.leader;
830 if (!atoi_n_check(leader+10, 1, &indicator_length))
832 if (!atoi_n_check(leader+11, 1, &identifier_length))
834 if (!atoi_n_check(leader+20, 1, &length_data_entry))
836 if (!atoi_n_check(leader+21, 1, &length_starting))
838 if (!atoi_n_check(leader+22, 1, &length_implementation))
841 wr_data_tmp = wrbuf_alloc();
842 wr_dir = wrbuf_alloc();
843 for (n = mt->nodes; n; n = n->next)
846 struct yaz_marc_subfield *s;
850 case YAZ_MARC_DATAFIELD:
851 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
852 data_length += indicator_length;
853 wrbuf_rewind(wr_data_tmp);
854 for (s = n->u.datafield.subfields; s; s = s->next)
856 /* write dummy IDFS + content */
857 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
858 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
859 marc_iconv_reset(mt, wr_data_tmp);
861 /* write dummy FS (makes MARC-8 to become ASCII) */
862 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
863 data_length += wrbuf_len(wr_data_tmp);
865 case YAZ_MARC_CONTROLFIELD:
866 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
868 wrbuf_rewind(wr_data_tmp);
869 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
870 n->u.controlfield.data);
871 marc_iconv_reset(mt, wr_data_tmp);
872 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
873 data_length += wrbuf_len(wr_data_tmp);
875 case YAZ_MARC_COMMENT:
877 case YAZ_MARC_LEADER:
882 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
883 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
884 data_offset += data_length;
887 /* mark end of directory */
888 wrbuf_putc(wr_dir, ISO2709_FS);
890 /* base address of data (comes after leader+directory) */
891 base_address = 24 + wrbuf_len(wr_dir);
893 wr_head = wrbuf_alloc();
895 /* write record length */
896 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
897 /* from "original" leader */
898 wrbuf_write(wr_head, leader+5, 7);
899 /* base address of data */
900 wrbuf_printf(wr_head, "%05d", base_address);
901 /* from "original" leader */
902 wrbuf_write(wr_head, leader+17, 7);
904 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
905 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
906 wrbuf_free(wr_head, 1);
907 wrbuf_free(wr_dir, 1);
908 wrbuf_free(wr_data_tmp, 1);
910 for (n = mt->nodes; n; n = n->next)
912 struct yaz_marc_subfield *s;
916 case YAZ_MARC_DATAFIELD:
917 wrbuf_printf(wr, "%.*s", indicator_length,
918 n->u.datafield.indicator);
919 for (s = n->u.datafield.subfields; s; s = s->next)
921 wrbuf_putc(wr, ISO2709_IDFS);
922 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
923 marc_iconv_reset(mt, wr);
925 wrbuf_putc(wr, ISO2709_FS);
927 case YAZ_MARC_CONTROLFIELD:
928 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
929 marc_iconv_reset(mt, wr);
930 wrbuf_putc(wr, ISO2709_FS);
932 case YAZ_MARC_COMMENT:
934 case YAZ_MARC_LEADER:
938 wrbuf_printf(wr, "%c", ISO2709_RS);
943 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
945 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
948 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
950 return -1; /* error */
951 return r; /* OK, return length > 0 */
954 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
955 char **result, int *rsize)
959 wrbuf_rewind(mt->m_wr);
960 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
962 *result = wrbuf_buf(mt->m_wr);
964 *rsize = wrbuf_len(mt->m_wr);
968 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
974 void yaz_marc_debug(yaz_marc_t mt, int level)
980 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
985 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
987 struct yaz_marc_node *n;
989 for (n = mt->nodes; n; n = n->next)
990 if (n->which == YAZ_MARC_LEADER)
992 leader = n->u.leader;
993 memcpy(leader+off, str, strlen(str));
999 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
1001 yaz_marc_t mt = yaz_marc_create();
1006 r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
1007 yaz_marc_destroy(mt);
1012 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
1014 return yaz_marc_decode(buf, wr, debug, bsize, 0);
1018 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
1020 yaz_marc_t mt = yaz_marc_create();
1024 r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
1028 fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1029 yaz_marc_destroy(mt);
1034 int marc_display_ex (const char *buf, FILE *outf, int debug)
1036 return marc_display_exl (buf, outf, debug, -1);
1040 int marc_display (const char *buf, FILE *outf)
1042 return marc_display_ex (buf, outf, 0);
1045 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1047 xfree(mt->leader_spec);
1048 mt->leader_spec = 0;
1051 char dummy_leader[24];
1052 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1054 mt->leader_spec = xstrdup(leader_spec);
1059 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1061 const char *cp = leader_spec;
1066 int no_read = 0, no = 0;
1068 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1069 if (no < 2 || no_read < 3)
1071 if (pos < 0 || pos >= size)
1076 const char *vp = strchr(val+1, '\'');
1082 if (len + pos > size)
1084 memcpy(leader + pos, val+1, len);
1086 else if (*val >= '0' && *val <= '9')
1102 int yaz_marc_decode_formatstr(const char *arg)
1105 if (!strcmp(arg, "marc"))
1106 mode = YAZ_MARC_ISO2709;
1107 if (!strcmp(arg, "marcxml"))
1108 mode = YAZ_MARC_MARCXML;
1109 if (!strcmp(arg, "marcxchange"))
1110 mode = YAZ_MARC_XCHANGE;
1111 if (!strcmp(arg, "line"))
1112 mode = YAZ_MARC_LINE;
1116 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1118 mt->write_using_libxml2 = enable;
1124 * indent-tabs-mode: nil
1126 * vim: shiftwidth=4 tabstop=8 expandtab