2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.46 2007-02-17 10:53: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)
133 size_t outbytesleft = sizeof(outbuf);
135 size_t r = yaz_iconv(mt->iconv_cd, 0, 0, &outp, &outbytesleft);
136 if (r != (size_t) (-1))
137 wrbuf_write(wr, outbuf, outp - outbuf);
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 = nmem_malloc(mt->nmem, sizeof(*n));
150 mt->nodes_pp = &n->next;
155 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
156 const xmlNode *ptr_data)
158 struct yaz_marc_node *n = yaz_marc_add_node(mt);
159 n->which = YAZ_MARC_CONTROLFIELD;
160 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
161 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
166 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
168 struct yaz_marc_node *n = yaz_marc_add_node(mt);
169 n->which = YAZ_MARC_COMMENT;
170 n->u.comment = nmem_strdup(mt->nmem, comment);
173 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
180 _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
184 vsnprintf(buf, sizeof(buf), fmt, ap);
186 vsprintf(buf, fmt, ap);
190 yaz_marc_add_comment(mt, buf);
194 int yaz_marc_get_debug(yaz_marc_t mt)
199 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
201 struct yaz_marc_node *n = yaz_marc_add_node(mt);
202 n->which = YAZ_MARC_LEADER;
203 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
204 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
207 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
208 const char *data, size_t data_len)
210 struct yaz_marc_node *n = yaz_marc_add_node(mt);
211 n->which = YAZ_MARC_CONTROLFIELD;
212 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
213 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
219 sprintf(msg, "controlfield:");
220 for (i = 0; i < 16 && i < data_len; i++)
221 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
223 sprintf(msg + strlen(msg), " ..");
224 yaz_marc_add_comment(mt, msg);
228 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
229 const char *indicator, size_t indicator_len)
231 struct yaz_marc_node *n = yaz_marc_add_node(mt);
232 n->which = YAZ_MARC_DATAFIELD;
233 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
234 n->u.datafield.indicator =
235 nmem_strdupn(mt->nmem, indicator, indicator_len);
236 n->u.datafield.subfields = 0;
238 /* make subfield_pp the current (last one) */
239 mt->subfield_pp = &n->u.datafield.subfields;
243 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
244 const char *indicator, size_t indicator_len)
246 struct yaz_marc_node *n = yaz_marc_add_node(mt);
247 n->which = YAZ_MARC_DATAFIELD;
248 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
249 n->u.datafield.indicator =
250 nmem_strdupn(mt->nmem, indicator, indicator_len);
251 n->u.datafield.subfields = 0;
253 /* make subfield_pp the current (last one) */
254 mt->subfield_pp = &n->u.datafield.subfields;
258 void yaz_marc_add_subfield(yaz_marc_t mt,
259 const char *code_data, size_t code_data_len)
266 sprintf(msg, "subfield:");
267 for (i = 0; i < 16 && i < code_data_len; i++)
268 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
269 if (i < code_data_len)
270 sprintf(msg + strlen(msg), " ..");
271 yaz_marc_add_comment(mt, msg);
276 struct yaz_marc_subfield *n = nmem_malloc(mt->nmem, sizeof(*n));
277 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
279 /* mark subfield_pp to point to this one, so we append here next */
280 *mt->subfield_pp = n;
281 mt->subfield_pp = &n->next;
285 int atoi_n_check(const char *buf, int size, int *val)
288 for (i = 0; i < size; i++)
289 if (!isdigit(i[(const unsigned char *) buf]))
291 *val = atoi_n(buf, size);
295 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
296 int *indicator_length,
297 int *identifier_length,
299 int *length_data_entry,
300 int *length_starting,
301 int *length_implementation)
305 memcpy(leader, leader_c, 24);
307 if (!atoi_n_check(leader+10, 1, indicator_length))
310 "Indicator length at offset 10 should hold a digit."
313 *indicator_length = 2;
315 if (!atoi_n_check(leader+11, 1, identifier_length))
318 "Identifier length at offset 11 should hold a digit."
321 *identifier_length = 2;
323 if (!atoi_n_check(leader+12, 5, base_address))
326 "Base address at offsets 12..16 should hold a number."
330 if (!atoi_n_check(leader+20, 1, length_data_entry))
333 "Length data entry at offset 20 should hold a digit."
335 *length_data_entry = 4;
338 if (!atoi_n_check(leader+21, 1, length_starting))
341 "Length starting at offset 21 should hold a digit."
343 *length_starting = 5;
346 if (!atoi_n_check(leader+22, 1, length_implementation))
349 "Length implementation at offset 22 should hold a digit."
351 *length_implementation = 0;
357 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
358 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
359 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
360 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
361 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
362 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
364 yaz_marc_add_leader(mt, leader, 24);
367 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
369 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
370 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
373 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
375 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
376 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
379 /* try to guess how many bytes the identifier really is! */
380 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
385 for (i = 1; i<5; i++)
388 size_t outbytesleft = sizeof(outbuf);
390 const char *inp = buf;
392 size_t inbytesleft = i;
393 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
394 &outp, &outbytesleft);
395 if (r != (size_t) (-1))
396 return i; /* got a complete sequence */
398 return 1; /* giving up */
400 return 1; /* we don't know */
403 void yaz_marc_reset(yaz_marc_t mt)
405 nmem_reset(mt->nmem);
407 mt->nodes_pp = &mt->nodes;
411 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
413 struct yaz_marc_node *n;
414 int identifier_length;
415 const char *leader = 0;
417 for (n = mt->nodes; n; n = n->next)
418 if (n->which == YAZ_MARC_LEADER)
420 leader = n->u.leader;
426 if (!atoi_n_check(leader+11, 1, &identifier_length))
429 for (n = mt->nodes; n; n = n->next)
433 case YAZ_MARC_COMMENT:
434 wrbuf_iconv_write(wr, mt->iconv_cd,
435 n->u.comment, strlen(n->u.comment));
436 wrbuf_puts(wr, ")\n");
446 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
448 struct yaz_marc_node *n;
449 int identifier_length;
450 const char *leader = 0;
452 for (n = mt->nodes; n; n = n->next)
453 if (n->which == YAZ_MARC_LEADER)
455 leader = n->u.leader;
461 if (!atoi_n_check(leader+11, 1, &identifier_length))
464 for (n = mt->nodes; n; n = n->next)
466 struct yaz_marc_subfield *s;
469 case YAZ_MARC_DATAFIELD:
470 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
471 n->u.datafield.indicator);
472 for (s = n->u.datafield.subfields; s; s = s->next)
474 /* if identifier length is 2 (most MARCs),
475 the code is a single character .. However we've
476 seen multibyte codes, so see how big it really is */
477 size_t using_code_len =
478 (identifier_length != 2) ? identifier_length - 1
480 cdata_one_character(mt, s->code_data);
482 wrbuf_puts (wr, mt->subfield_str);
483 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
485 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
486 wrbuf_iconv_puts(wr, mt->iconv_cd,
487 s->code_data + using_code_len);
488 marc_iconv_reset(mt, wr);
490 wrbuf_puts (wr, mt->endline_str);
492 case YAZ_MARC_CONTROLFIELD:
493 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
494 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
495 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
496 marc_iconv_reset(mt, wr);
497 wrbuf_puts (wr, mt->endline_str);
499 case YAZ_MARC_COMMENT:
501 wrbuf_iconv_write(wr, mt->iconv_cd,
502 n->u.comment, strlen(n->u.comment));
503 wrbuf_puts(wr, ")\n");
505 case YAZ_MARC_LEADER:
506 wrbuf_printf(wr, "%s\n", n->u.leader);
509 wrbuf_puts(wr, "\n");
513 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
518 return yaz_marc_write_line(mt, wr);
519 case YAZ_MARC_MARCXML:
520 return yaz_marc_write_marcxml(mt, wr);
521 case YAZ_MARC_XCHANGE:
522 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
523 case YAZ_MARC_ISO2709:
524 return yaz_marc_write_iso2709(mt, wr);
526 return yaz_marc_write_check(mt, wr);
531 /** \brief common MARC XML/Xchange writer
533 \param wr WRBUF output
534 \param ns XMLNS for the elements
535 \param format record format (e.g. "MARC21")
536 \param type record type (e.g. "Bibliographic")
538 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
543 struct yaz_marc_node *n;
544 int identifier_length;
545 const char *leader = 0;
547 for (n = mt->nodes; n; n = n->next)
548 if (n->which == YAZ_MARC_LEADER)
550 leader = n->u.leader;
556 if (!atoi_n_check(leader+11, 1, &identifier_length))
559 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
561 wrbuf_printf(wr, " format=\"%.80s\"", format);
563 wrbuf_printf(wr, " type=\"%.80s\"", type);
564 wrbuf_printf(wr, ">\n");
565 for (n = mt->nodes; n; n = n->next)
567 struct yaz_marc_subfield *s;
571 case YAZ_MARC_DATAFIELD:
572 wrbuf_printf(wr, " <datafield tag=\"");
573 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
574 strlen(n->u.datafield.tag));
575 wrbuf_printf(wr, "\"");
576 if (n->u.datafield.indicator)
579 for (i = 0; n->u.datafield.indicator[i]; i++)
581 wrbuf_printf(wr, " ind%d=\"", i+1);
582 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
583 n->u.datafield.indicator+i, 1);
584 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
587 wrbuf_printf(wr, ">\n");
588 for (s = n->u.datafield.subfields; s; s = s->next)
590 /* if identifier length is 2 (most MARCs),
591 the code is a single character .. However we've
592 seen multibyte codes, so see how big it really is */
593 size_t using_code_len =
594 (identifier_length != 2) ? identifier_length - 1
596 cdata_one_character(mt, s->code_data);
598 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
599 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
600 s->code_data, using_code_len);
601 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
602 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
603 s->code_data + using_code_len,
604 strlen(s->code_data + using_code_len));
605 marc_iconv_reset(mt, wr);
606 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
607 wrbuf_puts(wr, "\n");
609 wrbuf_printf(wr, " </datafield>\n");
611 case YAZ_MARC_CONTROLFIELD:
612 wrbuf_printf(wr, " <controlfield tag=\"");
613 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
614 strlen(n->u.controlfield.tag));
615 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
616 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
618 marc_iconv_reset(mt, wr);
619 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
620 wrbuf_puts(wr, "\n");
622 case YAZ_MARC_COMMENT:
623 wrbuf_printf(wr, "<!-- ");
624 wrbuf_puts(wr, n->u.comment);
625 wrbuf_printf(wr, " -->\n");
627 case YAZ_MARC_LEADER:
628 wrbuf_printf(wr, " <leader>");
629 wrbuf_iconv_write_cdata(wr,
630 0 /* no charset conversion for leader */,
631 n->u.leader, strlen(n->u.leader));
632 wrbuf_printf(wr, "</leader>\n");
635 wrbuf_puts(wr, "</record>\n");
639 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
644 if (mt->write_using_libxml2)
650 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
654 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
657 xmlDocSetRootElement(doc, root_ptr);
658 xmlDocDumpMemory(doc, &buf_out, &len_out);
660 wrbuf_write(wr, (const char *) buf_out, len_out);
671 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
674 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
676 if (!mt->leader_spec)
677 yaz_marc_modify_leader(mt, 9, "a");
678 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
682 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
686 return yaz_marc_write_marcxml_ns(mt, wr,
687 "http://www.bs.dk/standards/MarcXchange",
692 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
698 struct yaz_marc_node *n;
699 int identifier_length;
700 const char *leader = 0;
705 for (n = mt->nodes; n; n = n->next)
706 if (n->which == YAZ_MARC_LEADER)
708 leader = n->u.leader;
714 if (!atoi_n_check(leader+11, 1, &identifier_length))
717 wr_cdata = wrbuf_alloc();
719 record_ptr = xmlNewNode(0, BAD_CAST "record");
720 *root_ptr = record_ptr;
722 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
723 xmlSetNs(record_ptr, ns_record);
726 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
728 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
729 for (n = mt->nodes; n; n = n->next)
731 struct yaz_marc_subfield *s;
736 case YAZ_MARC_DATAFIELD:
737 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
738 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
739 if (n->u.datafield.indicator)
742 for (i = 0; n->u.datafield.indicator[i]; i++)
747 sprintf(ind_str, "ind%d", i+1);
748 ind_val[0] = n->u.datafield.indicator[i];
750 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
753 for (s = n->u.datafield.subfields; s; s = s->next)
755 xmlNode *ptr_subfield;
756 /* if identifier length is 2 (most MARCs),
757 the code is a single character .. However we've
758 seen multibyte codes, so see how big it really is */
759 size_t using_code_len =
760 (identifier_length != 2) ? identifier_length - 1
762 cdata_one_character(mt, s->code_data);
764 wrbuf_rewind(wr_cdata);
765 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
766 s->code_data + using_code_len);
767 marc_iconv_reset(mt, wr_cdata);
768 ptr_subfield = xmlNewTextChild(
770 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
772 wrbuf_rewind(wr_cdata);
773 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
774 s->code_data, using_code_len);
775 xmlNewProp(ptr_subfield, BAD_CAST "code",
776 BAD_CAST wrbuf_cstr(wr_cdata));
779 case YAZ_MARC_CONTROLFIELD:
780 wrbuf_rewind(wr_cdata);
781 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
782 marc_iconv_reset(mt, wr_cdata);
784 ptr = xmlNewTextChild(record_ptr, ns_record,
785 BAD_CAST "controlfield",
786 BAD_CAST wrbuf_cstr(wr_cdata));
788 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
790 case YAZ_MARC_COMMENT:
791 ptr = xmlNewComment(BAD_CAST n->u.comment);
792 xmlAddChild(record_ptr, ptr);
794 case YAZ_MARC_LEADER:
795 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
796 BAD_CAST n->u.leader);
800 wrbuf_destroy(wr_cdata);
807 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
809 struct yaz_marc_node *n;
810 int indicator_length;
811 int identifier_length;
812 int length_data_entry;
814 int length_implementation;
816 const char *leader = 0;
817 WRBUF wr_dir, wr_head, wr_data_tmp;
820 for (n = mt->nodes; n; n = n->next)
821 if (n->which == YAZ_MARC_LEADER)
822 leader = n->u.leader;
826 if (!atoi_n_check(leader+10, 1, &indicator_length))
828 if (!atoi_n_check(leader+11, 1, &identifier_length))
830 if (!atoi_n_check(leader+20, 1, &length_data_entry))
832 if (!atoi_n_check(leader+21, 1, &length_starting))
834 if (!atoi_n_check(leader+22, 1, &length_implementation))
837 wr_data_tmp = wrbuf_alloc();
838 wr_dir = wrbuf_alloc();
839 for (n = mt->nodes; n; n = n->next)
842 struct yaz_marc_subfield *s;
846 case YAZ_MARC_DATAFIELD:
847 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
848 data_length += indicator_length;
849 wrbuf_rewind(wr_data_tmp);
850 for (s = n->u.datafield.subfields; s; s = s->next)
852 /* write dummy IDFS + content */
853 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
854 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
855 marc_iconv_reset(mt, wr_data_tmp);
857 /* write dummy FS (makes MARC-8 to become ASCII) */
858 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
859 data_length += wrbuf_len(wr_data_tmp);
861 case YAZ_MARC_CONTROLFIELD:
862 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
864 wrbuf_rewind(wr_data_tmp);
865 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
866 n->u.controlfield.data);
867 marc_iconv_reset(mt, wr_data_tmp);
868 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
869 data_length += wrbuf_len(wr_data_tmp);
871 case YAZ_MARC_COMMENT:
873 case YAZ_MARC_LEADER:
878 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
879 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
880 data_offset += data_length;
883 /* mark end of directory */
884 wrbuf_putc(wr_dir, ISO2709_FS);
886 /* base address of data (comes after leader+directory) */
887 base_address = 24 + wrbuf_len(wr_dir);
889 wr_head = wrbuf_alloc();
891 /* write record length */
892 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
893 /* from "original" leader */
894 wrbuf_write(wr_head, leader+5, 7);
895 /* base address of data */
896 wrbuf_printf(wr_head, "%05d", base_address);
897 /* from "original" leader */
898 wrbuf_write(wr_head, leader+17, 7);
900 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
901 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
902 wrbuf_free(wr_head, 1);
903 wrbuf_free(wr_dir, 1);
904 wrbuf_free(wr_data_tmp, 1);
906 for (n = mt->nodes; n; n = n->next)
908 struct yaz_marc_subfield *s;
912 case YAZ_MARC_DATAFIELD:
913 wrbuf_printf(wr, "%.*s", indicator_length,
914 n->u.datafield.indicator);
915 for (s = n->u.datafield.subfields; s; s = s->next)
917 wrbuf_putc(wr, ISO2709_IDFS);
918 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
919 marc_iconv_reset(mt, wr);
921 wrbuf_putc(wr, ISO2709_FS);
923 case YAZ_MARC_CONTROLFIELD:
924 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
925 marc_iconv_reset(mt, wr);
926 wrbuf_putc(wr, ISO2709_FS);
928 case YAZ_MARC_COMMENT:
930 case YAZ_MARC_LEADER:
934 wrbuf_printf(wr, "%c", ISO2709_RS);
939 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
941 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
944 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
946 return -1; /* error */
947 return r; /* OK, return length > 0 */
950 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
951 char **result, int *rsize)
955 wrbuf_rewind(mt->m_wr);
956 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
958 *result = wrbuf_buf(mt->m_wr);
960 *rsize = wrbuf_len(mt->m_wr);
964 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
970 void yaz_marc_debug(yaz_marc_t mt, int level)
976 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
981 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
983 struct yaz_marc_node *n;
985 for (n = mt->nodes; n; n = n->next)
986 if (n->which == YAZ_MARC_LEADER)
988 leader = n->u.leader;
989 memcpy(leader+off, str, strlen(str));
995 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
997 yaz_marc_t mt = yaz_marc_create();
1002 r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
1003 yaz_marc_destroy(mt);
1008 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
1010 return yaz_marc_decode(buf, wr, debug, bsize, 0);
1014 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
1016 yaz_marc_t mt = yaz_marc_create();
1020 r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
1024 fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1025 yaz_marc_destroy(mt);
1030 int marc_display_ex (const char *buf, FILE *outf, int debug)
1032 return marc_display_exl (buf, outf, debug, -1);
1036 int marc_display (const char *buf, FILE *outf)
1038 return marc_display_ex (buf, outf, 0);
1041 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1043 xfree(mt->leader_spec);
1044 mt->leader_spec = 0;
1047 char dummy_leader[24];
1048 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1050 mt->leader_spec = xstrdup(leader_spec);
1055 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1057 const char *cp = leader_spec;
1062 int no_read = 0, no = 0;
1064 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1065 if (no < 2 || no_read < 3)
1067 if (pos < 0 || pos >= size)
1072 const char *vp = strchr(val+1, '\'');
1078 if (len + pos > size)
1080 memcpy(leader + pos, val+1, len);
1082 else if (*val >= '0' && *val <= '9')
1098 int yaz_marc_decode_formatstr(const char *arg)
1101 if (!strcmp(arg, "marc"))
1102 mode = YAZ_MARC_ISO2709;
1103 if (!strcmp(arg, "marcxml"))
1104 mode = YAZ_MARC_MARCXML;
1105 if (!strcmp(arg, "marcxchange"))
1106 mode = YAZ_MARC_XCHANGE;
1107 if (!strcmp(arg, "line"))
1108 mode = YAZ_MARC_LINE;
1112 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1114 mt->write_using_libxml2 = enable;
1120 * indent-tabs-mode: nil
1122 * vim: shiftwidth=4 tabstop=8 expandtab