2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.45 2007-01-22 09:21:16 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)
649 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
653 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
656 xmlDocSetRootElement(doc, root_ptr);
657 xmlDocDumpMemory(doc, &buf_out, &len_out);
659 wrbuf_write(wr, (const char *) buf_out, len_out);
667 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
670 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
672 if (!mt->leader_spec)
673 yaz_marc_modify_leader(mt, 9, "a");
674 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
678 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
682 return yaz_marc_write_marcxml_ns(mt, wr,
683 "http://www.bs.dk/standards/MarcXchange",
688 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
694 struct yaz_marc_node *n;
695 int identifier_length;
696 const char *leader = 0;
701 for (n = mt->nodes; n; n = n->next)
702 if (n->which == YAZ_MARC_LEADER)
704 leader = n->u.leader;
710 if (!atoi_n_check(leader+11, 1, &identifier_length))
713 wr_cdata = wrbuf_alloc();
715 record_ptr = xmlNewNode(0, BAD_CAST "record");
716 *root_ptr = record_ptr;
718 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
719 xmlSetNs(record_ptr, ns_record);
722 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
724 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
725 for (n = mt->nodes; n; n = n->next)
727 struct yaz_marc_subfield *s;
732 case YAZ_MARC_DATAFIELD:
733 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
734 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
735 if (n->u.datafield.indicator)
738 for (i = 0; n->u.datafield.indicator[i]; i++)
743 sprintf(ind_str, "ind%d", i+1);
744 ind_val[0] = n->u.datafield.indicator[i];
746 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
749 for (s = n->u.datafield.subfields; s; s = s->next)
751 xmlNode *ptr_subfield;
752 /* if identifier length is 2 (most MARCs),
753 the code is a single character .. However we've
754 seen multibyte codes, so see how big it really is */
755 size_t using_code_len =
756 (identifier_length != 2) ? identifier_length - 1
758 cdata_one_character(mt, s->code_data);
760 wrbuf_rewind(wr_cdata);
761 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
762 s->code_data + using_code_len);
763 marc_iconv_reset(mt, wr_cdata);
764 ptr_subfield = xmlNewTextChild(
766 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
768 wrbuf_rewind(wr_cdata);
769 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
770 s->code_data, using_code_len);
771 xmlNewProp(ptr_subfield, BAD_CAST "code",
772 BAD_CAST wrbuf_cstr(wr_cdata));
775 case YAZ_MARC_CONTROLFIELD:
776 wrbuf_rewind(wr_cdata);
777 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
778 marc_iconv_reset(mt, wr_cdata);
780 ptr = xmlNewTextChild(record_ptr, ns_record,
781 BAD_CAST "controlfield",
782 BAD_CAST wrbuf_cstr(wr_cdata));
784 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
786 case YAZ_MARC_COMMENT:
787 ptr = xmlNewComment(BAD_CAST n->u.comment);
788 xmlAddChild(record_ptr, ptr);
790 case YAZ_MARC_LEADER:
791 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
792 BAD_CAST n->u.leader);
796 wrbuf_destroy(wr_cdata);
803 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
805 struct yaz_marc_node *n;
806 int indicator_length;
807 int identifier_length;
808 int length_data_entry;
810 int length_implementation;
812 const char *leader = 0;
813 WRBUF wr_dir, wr_head, wr_data_tmp;
816 for (n = mt->nodes; n; n = n->next)
817 if (n->which == YAZ_MARC_LEADER)
818 leader = n->u.leader;
822 if (!atoi_n_check(leader+10, 1, &indicator_length))
824 if (!atoi_n_check(leader+11, 1, &identifier_length))
826 if (!atoi_n_check(leader+20, 1, &length_data_entry))
828 if (!atoi_n_check(leader+21, 1, &length_starting))
830 if (!atoi_n_check(leader+22, 1, &length_implementation))
833 wr_data_tmp = wrbuf_alloc();
834 wr_dir = wrbuf_alloc();
835 for (n = mt->nodes; n; n = n->next)
838 struct yaz_marc_subfield *s;
842 case YAZ_MARC_DATAFIELD:
843 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
844 data_length += indicator_length;
845 wrbuf_rewind(wr_data_tmp);
846 for (s = n->u.datafield.subfields; s; s = s->next)
848 /* write dummy IDFS + content */
849 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
850 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
851 marc_iconv_reset(mt, wr_data_tmp);
853 /* write dummy FS (makes MARC-8 to become ASCII) */
854 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
855 data_length += wrbuf_len(wr_data_tmp);
857 case YAZ_MARC_CONTROLFIELD:
858 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
860 wrbuf_rewind(wr_data_tmp);
861 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
862 n->u.controlfield.data);
863 marc_iconv_reset(mt, wr_data_tmp);
864 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
865 data_length += wrbuf_len(wr_data_tmp);
867 case YAZ_MARC_COMMENT:
869 case YAZ_MARC_LEADER:
874 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
875 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
876 data_offset += data_length;
879 /* mark end of directory */
880 wrbuf_putc(wr_dir, ISO2709_FS);
882 /* base address of data (comes after leader+directory) */
883 base_address = 24 + wrbuf_len(wr_dir);
885 wr_head = wrbuf_alloc();
887 /* write record length */
888 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
889 /* from "original" leader */
890 wrbuf_write(wr_head, leader+5, 7);
891 /* base address of data */
892 wrbuf_printf(wr_head, "%05d", base_address);
893 /* from "original" leader */
894 wrbuf_write(wr_head, leader+17, 7);
896 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
897 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
898 wrbuf_free(wr_head, 1);
899 wrbuf_free(wr_dir, 1);
900 wrbuf_free(wr_data_tmp, 1);
902 for (n = mt->nodes; n; n = n->next)
904 struct yaz_marc_subfield *s;
908 case YAZ_MARC_DATAFIELD:
909 wrbuf_printf(wr, "%.*s", indicator_length,
910 n->u.datafield.indicator);
911 for (s = n->u.datafield.subfields; s; s = s->next)
913 wrbuf_putc(wr, ISO2709_IDFS);
914 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
915 marc_iconv_reset(mt, wr);
917 wrbuf_putc(wr, ISO2709_FS);
919 case YAZ_MARC_CONTROLFIELD:
920 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
921 marc_iconv_reset(mt, wr);
922 wrbuf_putc(wr, ISO2709_FS);
924 case YAZ_MARC_COMMENT:
926 case YAZ_MARC_LEADER:
930 wrbuf_printf(wr, "%c", ISO2709_RS);
935 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
937 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
940 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
942 return -1; /* error */
943 return r; /* OK, return length > 0 */
946 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
947 char **result, int *rsize)
951 wrbuf_rewind(mt->m_wr);
952 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
954 *result = wrbuf_buf(mt->m_wr);
956 *rsize = wrbuf_len(mt->m_wr);
960 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
966 void yaz_marc_debug(yaz_marc_t mt, int level)
972 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
977 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
979 struct yaz_marc_node *n;
981 for (n = mt->nodes; n; n = n->next)
982 if (n->which == YAZ_MARC_LEADER)
984 leader = n->u.leader;
985 memcpy(leader+off, str, strlen(str));
991 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
993 yaz_marc_t mt = yaz_marc_create();
998 r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
999 yaz_marc_destroy(mt);
1004 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
1006 return yaz_marc_decode(buf, wr, debug, bsize, 0);
1010 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
1012 yaz_marc_t mt = yaz_marc_create();
1016 r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
1020 fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1021 yaz_marc_destroy(mt);
1026 int marc_display_ex (const char *buf, FILE *outf, int debug)
1028 return marc_display_exl (buf, outf, debug, -1);
1032 int marc_display (const char *buf, FILE *outf)
1034 return marc_display_ex (buf, outf, 0);
1037 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1039 xfree(mt->leader_spec);
1040 mt->leader_spec = 0;
1043 char dummy_leader[24];
1044 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1046 mt->leader_spec = xstrdup(leader_spec);
1051 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1053 const char *cp = leader_spec;
1058 int no_read = 0, no = 0;
1060 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1061 if (no < 2 || no_read < 3)
1063 if (pos < 0 || pos >= size)
1068 const char *vp = strchr(val+1, '\'');
1074 if (len + pos > size)
1076 memcpy(leader + pos, val+1, len);
1078 else if (*val >= '0' && *val <= '9')
1094 int yaz_marc_decode_formatstr(const char *arg)
1097 if (!strcmp(arg, "marc"))
1098 mode = YAZ_MARC_ISO2709;
1099 if (!strcmp(arg, "marcxml"))
1100 mode = YAZ_MARC_MARCXML;
1101 if (!strcmp(arg, "marcxchange"))
1102 mode = YAZ_MARC_XCHANGE;
1103 if (!strcmp(arg, "line"))
1104 mode = YAZ_MARC_LINE;
1108 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1110 mt->write_using_libxml2 = enable;
1116 * indent-tabs-mode: nil
1118 * vim: shiftwidth=4 tabstop=8 expandtab