2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.49 2007-03-20 21:37:32 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 /** \brief node types for yaz_marc_node */
37 enum YAZ_MARC_NODE_TYPE
40 YAZ_MARC_CONTROLFIELD,
45 /** \brief represets a data field */
46 struct yaz_marc_datafield {
49 struct yaz_marc_subfield *subfields;
52 /** \brief represents a control field */
53 struct yaz_marc_controlfield {
58 /** \brief a comment node */
59 struct yaz_marc_comment {
63 /** \brief MARC node */
64 struct yaz_marc_node {
65 enum YAZ_MARC_NODE_TYPE which;
67 struct yaz_marc_datafield datafield;
68 struct yaz_marc_controlfield controlfield;
72 struct yaz_marc_node *next;
75 /** \brief represents a subfield */
76 struct yaz_marc_subfield {
78 struct yaz_marc_subfield *next;
81 /** \brief the internals of a yaz_marc_t handle */
87 int write_using_libxml2;
92 struct yaz_marc_node *nodes;
93 struct yaz_marc_node **nodes_pp;
94 struct yaz_marc_subfield **subfield_pp;
97 yaz_marc_t yaz_marc_create(void)
99 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
100 mt->xml = YAZ_MARC_LINE;
102 mt->write_using_libxml2 = 0;
103 mt->m_wr = wrbuf_alloc();
106 strcpy(mt->subfield_str, " $");
107 strcpy(mt->endline_str, "\n");
109 mt->nmem = nmem_create();
114 void yaz_marc_destroy(yaz_marc_t mt)
118 nmem_destroy(mt->nmem);
119 wrbuf_destroy(mt->m_wr);
120 xfree(mt->leader_spec);
124 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
129 static void marc_iconv_reset(yaz_marc_t mt, WRBUF wr)
131 wrbuf_iconv_reset(wr, mt->iconv_cd);
134 static int marc_exec_leader(const char *leader_spec, char *leader,
138 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
140 struct yaz_marc_node *n = nmem_malloc(mt->nmem, sizeof(*n));
143 mt->nodes_pp = &n->next;
148 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
149 const xmlNode *ptr_data)
151 struct yaz_marc_node *n = yaz_marc_add_node(mt);
152 n->which = YAZ_MARC_CONTROLFIELD;
153 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
154 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
159 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
161 struct yaz_marc_node *n = yaz_marc_add_node(mt);
162 n->which = YAZ_MARC_COMMENT;
163 n->u.comment = nmem_strdup(mt->nmem, comment);
166 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
172 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
173 yaz_marc_add_comment(mt, buf);
177 int yaz_marc_get_debug(yaz_marc_t mt)
182 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
184 struct yaz_marc_node *n = yaz_marc_add_node(mt);
185 n->which = YAZ_MARC_LEADER;
186 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
187 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
190 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
191 const char *data, size_t data_len)
193 struct yaz_marc_node *n = yaz_marc_add_node(mt);
194 n->which = YAZ_MARC_CONTROLFIELD;
195 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
196 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
202 sprintf(msg, "controlfield:");
203 for (i = 0; i < 16 && i < data_len; i++)
204 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
206 sprintf(msg + strlen(msg), " ..");
207 yaz_marc_add_comment(mt, msg);
211 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
212 const char *indicator, size_t indicator_len)
214 struct yaz_marc_node *n = yaz_marc_add_node(mt);
215 n->which = YAZ_MARC_DATAFIELD;
216 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
217 n->u.datafield.indicator =
218 nmem_strdupn(mt->nmem, indicator, indicator_len);
219 n->u.datafield.subfields = 0;
221 /* make subfield_pp the current (last one) */
222 mt->subfield_pp = &n->u.datafield.subfields;
226 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
227 const char *indicator, size_t indicator_len)
229 struct yaz_marc_node *n = yaz_marc_add_node(mt);
230 n->which = YAZ_MARC_DATAFIELD;
231 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
232 n->u.datafield.indicator =
233 nmem_strdupn(mt->nmem, indicator, indicator_len);
234 n->u.datafield.subfields = 0;
236 /* make subfield_pp the current (last one) */
237 mt->subfield_pp = &n->u.datafield.subfields;
241 void yaz_marc_add_subfield(yaz_marc_t mt,
242 const char *code_data, size_t code_data_len)
249 sprintf(msg, "subfield:");
250 for (i = 0; i < 16 && i < code_data_len; i++)
251 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
252 if (i < code_data_len)
253 sprintf(msg + strlen(msg), " ..");
254 yaz_marc_add_comment(mt, msg);
259 struct yaz_marc_subfield *n = nmem_malloc(mt->nmem, sizeof(*n));
260 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
262 /* mark subfield_pp to point to this one, so we append here next */
263 *mt->subfield_pp = n;
264 mt->subfield_pp = &n->next;
268 int atoi_n_check(const char *buf, int size, int *val)
271 for (i = 0; i < size; i++)
272 if (!isdigit(i[(const unsigned char *) buf]))
274 *val = atoi_n(buf, size);
278 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
279 int *indicator_length,
280 int *identifier_length,
282 int *length_data_entry,
283 int *length_starting,
284 int *length_implementation)
288 memcpy(leader, leader_c, 24);
290 if (!atoi_n_check(leader+10, 1, indicator_length))
293 "Indicator length at offset 10 should hold a digit."
296 *indicator_length = 2;
298 if (!atoi_n_check(leader+11, 1, identifier_length))
301 "Identifier length at offset 11 should hold a digit."
304 *identifier_length = 2;
306 if (!atoi_n_check(leader+12, 5, base_address))
309 "Base address at offsets 12..16 should hold a number."
313 if (!atoi_n_check(leader+20, 1, length_data_entry))
316 "Length data entry at offset 20 should hold a digit."
318 *length_data_entry = 4;
321 if (!atoi_n_check(leader+21, 1, length_starting))
324 "Length starting at offset 21 should hold a digit."
326 *length_starting = 5;
329 if (!atoi_n_check(leader+22, 1, length_implementation))
332 "Length implementation at offset 22 should hold a digit."
334 *length_implementation = 0;
340 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
341 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
342 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
343 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
344 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
345 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
347 yaz_marc_add_leader(mt, leader, 24);
350 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
352 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
353 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
356 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
358 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
359 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
362 /* try to guess how many bytes the identifier really is! */
363 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
368 for (i = 1; i<5; i++)
371 size_t outbytesleft = sizeof(outbuf);
373 const char *inp = buf;
375 size_t inbytesleft = i;
376 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
377 &outp, &outbytesleft);
378 if (r != (size_t) (-1))
379 return i; /* got a complete sequence */
381 return 1; /* giving up */
383 return 1; /* we don't know */
386 void yaz_marc_reset(yaz_marc_t mt)
388 nmem_reset(mt->nmem);
390 mt->nodes_pp = &mt->nodes;
394 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
396 struct yaz_marc_node *n;
397 int identifier_length;
398 const char *leader = 0;
400 for (n = mt->nodes; n; n = n->next)
401 if (n->which == YAZ_MARC_LEADER)
403 leader = n->u.leader;
409 if (!atoi_n_check(leader+11, 1, &identifier_length))
412 for (n = mt->nodes; n; n = n->next)
416 case YAZ_MARC_COMMENT:
417 wrbuf_iconv_write(wr, mt->iconv_cd,
418 n->u.comment, strlen(n->u.comment));
419 wrbuf_puts(wr, ")\n");
429 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
431 struct yaz_marc_node *n;
432 int identifier_length;
433 const char *leader = 0;
435 for (n = mt->nodes; n; n = n->next)
436 if (n->which == YAZ_MARC_LEADER)
438 leader = n->u.leader;
444 if (!atoi_n_check(leader+11, 1, &identifier_length))
447 for (n = mt->nodes; n; n = n->next)
449 struct yaz_marc_subfield *s;
452 case YAZ_MARC_DATAFIELD:
453 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
454 n->u.datafield.indicator);
455 for (s = n->u.datafield.subfields; s; s = s->next)
457 /* if identifier length is 2 (most MARCs),
458 the code is a single character .. However we've
459 seen multibyte codes, so see how big it really is */
460 size_t using_code_len =
461 (identifier_length != 2) ? identifier_length - 1
463 cdata_one_character(mt, s->code_data);
465 wrbuf_puts (wr, mt->subfield_str);
466 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
468 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
469 wrbuf_iconv_puts(wr, mt->iconv_cd,
470 s->code_data + using_code_len);
471 marc_iconv_reset(mt, wr);
473 wrbuf_puts (wr, mt->endline_str);
475 case YAZ_MARC_CONTROLFIELD:
476 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
477 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
478 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
479 marc_iconv_reset(mt, wr);
480 wrbuf_puts (wr, mt->endline_str);
482 case YAZ_MARC_COMMENT:
484 wrbuf_iconv_write(wr, mt->iconv_cd,
485 n->u.comment, strlen(n->u.comment));
486 marc_iconv_reset(mt, wr);
487 wrbuf_puts(wr, ")\n");
489 case YAZ_MARC_LEADER:
490 wrbuf_printf(wr, "%s\n", n->u.leader);
493 wrbuf_puts(wr, "\n");
497 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
502 return yaz_marc_write_line(mt, wr);
503 case YAZ_MARC_MARCXML:
504 return yaz_marc_write_marcxml(mt, wr);
505 case YAZ_MARC_XCHANGE:
506 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
507 case YAZ_MARC_ISO2709:
508 return yaz_marc_write_iso2709(mt, wr);
510 return yaz_marc_write_check(mt, wr);
515 /** \brief common MARC XML/Xchange writer
517 \param wr WRBUF output
518 \param ns XMLNS for the elements
519 \param format record format (e.g. "MARC21")
520 \param type record type (e.g. "Bibliographic")
522 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
527 struct yaz_marc_node *n;
528 int identifier_length;
529 const char *leader = 0;
531 for (n = mt->nodes; n; n = n->next)
532 if (n->which == YAZ_MARC_LEADER)
534 leader = n->u.leader;
540 if (!atoi_n_check(leader+11, 1, &identifier_length))
543 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
545 wrbuf_printf(wr, " format=\"%.80s\"", format);
547 wrbuf_printf(wr, " type=\"%.80s\"", type);
548 wrbuf_printf(wr, ">\n");
549 for (n = mt->nodes; n; n = n->next)
551 struct yaz_marc_subfield *s;
555 case YAZ_MARC_DATAFIELD:
556 wrbuf_printf(wr, " <datafield tag=\"");
557 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
558 strlen(n->u.datafield.tag));
559 wrbuf_printf(wr, "\"");
560 if (n->u.datafield.indicator)
563 for (i = 0; n->u.datafield.indicator[i]; i++)
565 wrbuf_printf(wr, " ind%d=\"", i+1);
566 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
567 n->u.datafield.indicator+i, 1);
568 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
571 wrbuf_printf(wr, ">\n");
572 for (s = n->u.datafield.subfields; s; s = s->next)
574 /* if identifier length is 2 (most MARCs),
575 the code is a single character .. However we've
576 seen multibyte codes, so see how big it really is */
577 size_t using_code_len =
578 (identifier_length != 2) ? identifier_length - 1
580 cdata_one_character(mt, s->code_data);
582 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
583 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
584 s->code_data, using_code_len);
585 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
586 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
587 s->code_data + using_code_len,
588 strlen(s->code_data + using_code_len));
589 marc_iconv_reset(mt, wr);
590 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
591 wrbuf_puts(wr, "\n");
593 wrbuf_printf(wr, " </datafield>\n");
595 case YAZ_MARC_CONTROLFIELD:
596 wrbuf_printf(wr, " <controlfield tag=\"");
597 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
598 strlen(n->u.controlfield.tag));
599 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
600 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
602 marc_iconv_reset(mt, wr);
603 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
604 wrbuf_puts(wr, "\n");
606 case YAZ_MARC_COMMENT:
607 wrbuf_printf(wr, "<!-- ");
608 wrbuf_puts(wr, n->u.comment);
609 wrbuf_printf(wr, " -->\n");
611 case YAZ_MARC_LEADER:
612 wrbuf_printf(wr, " <leader>");
613 wrbuf_iconv_write_cdata(wr,
614 0 /* no charset conversion for leader */,
615 n->u.leader, strlen(n->u.leader));
616 wrbuf_printf(wr, "</leader>\n");
619 wrbuf_puts(wr, "</record>\n");
623 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
628 if (mt->write_using_libxml2)
634 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
638 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
641 xmlDocSetRootElement(doc, root_ptr);
642 xmlDocDumpMemory(doc, &buf_out, &len_out);
644 wrbuf_write(wr, (const char *) buf_out, len_out);
655 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
658 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
660 if (!mt->leader_spec)
661 yaz_marc_modify_leader(mt, 9, "a");
662 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
666 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
670 return yaz_marc_write_marcxml_ns(mt, wr,
671 "http://www.bs.dk/standards/MarcXchange",
676 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
682 struct yaz_marc_node *n;
683 int identifier_length;
684 const char *leader = 0;
689 for (n = mt->nodes; n; n = n->next)
690 if (n->which == YAZ_MARC_LEADER)
692 leader = n->u.leader;
698 if (!atoi_n_check(leader+11, 1, &identifier_length))
701 wr_cdata = wrbuf_alloc();
703 record_ptr = xmlNewNode(0, BAD_CAST "record");
704 *root_ptr = record_ptr;
706 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
707 xmlSetNs(record_ptr, ns_record);
710 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
712 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
713 for (n = mt->nodes; n; n = n->next)
715 struct yaz_marc_subfield *s;
720 case YAZ_MARC_DATAFIELD:
721 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
722 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
723 if (n->u.datafield.indicator)
726 for (i = 0; n->u.datafield.indicator[i]; i++)
731 sprintf(ind_str, "ind%d", i+1);
732 ind_val[0] = n->u.datafield.indicator[i];
734 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
737 for (s = n->u.datafield.subfields; s; s = s->next)
739 xmlNode *ptr_subfield;
740 /* if identifier length is 2 (most MARCs),
741 the code is a single character .. However we've
742 seen multibyte codes, so see how big it really is */
743 size_t using_code_len =
744 (identifier_length != 2) ? identifier_length - 1
746 cdata_one_character(mt, s->code_data);
748 wrbuf_rewind(wr_cdata);
749 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
750 s->code_data + using_code_len);
751 marc_iconv_reset(mt, wr_cdata);
752 ptr_subfield = xmlNewTextChild(
754 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
756 wrbuf_rewind(wr_cdata);
757 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
758 s->code_data, using_code_len);
759 xmlNewProp(ptr_subfield, BAD_CAST "code",
760 BAD_CAST wrbuf_cstr(wr_cdata));
763 case YAZ_MARC_CONTROLFIELD:
764 wrbuf_rewind(wr_cdata);
765 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
766 marc_iconv_reset(mt, wr_cdata);
768 ptr = xmlNewTextChild(record_ptr, ns_record,
769 BAD_CAST "controlfield",
770 BAD_CAST wrbuf_cstr(wr_cdata));
772 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
774 case YAZ_MARC_COMMENT:
775 ptr = xmlNewComment(BAD_CAST n->u.comment);
776 xmlAddChild(record_ptr, ptr);
778 case YAZ_MARC_LEADER:
779 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
780 BAD_CAST n->u.leader);
784 wrbuf_destroy(wr_cdata);
791 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
793 struct yaz_marc_node *n;
794 int indicator_length;
795 int identifier_length;
796 int length_data_entry;
798 int length_implementation;
800 const char *leader = 0;
801 WRBUF wr_dir, wr_head, wr_data_tmp;
804 for (n = mt->nodes; n; n = n->next)
805 if (n->which == YAZ_MARC_LEADER)
806 leader = n->u.leader;
810 if (!atoi_n_check(leader+10, 1, &indicator_length))
812 if (!atoi_n_check(leader+11, 1, &identifier_length))
814 if (!atoi_n_check(leader+20, 1, &length_data_entry))
816 if (!atoi_n_check(leader+21, 1, &length_starting))
818 if (!atoi_n_check(leader+22, 1, &length_implementation))
821 wr_data_tmp = wrbuf_alloc();
822 wr_dir = wrbuf_alloc();
823 for (n = mt->nodes; n; n = n->next)
826 struct yaz_marc_subfield *s;
830 case YAZ_MARC_DATAFIELD:
831 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
832 data_length += indicator_length;
833 wrbuf_rewind(wr_data_tmp);
834 for (s = n->u.datafield.subfields; s; s = s->next)
836 /* write dummy IDFS + content */
837 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
838 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
839 marc_iconv_reset(mt, wr_data_tmp);
841 /* write dummy FS (makes MARC-8 to become ASCII) */
842 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
843 marc_iconv_reset(mt, wr_data_tmp);
844 data_length += wrbuf_len(wr_data_tmp);
846 case YAZ_MARC_CONTROLFIELD:
847 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
849 wrbuf_rewind(wr_data_tmp);
850 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
851 n->u.controlfield.data);
852 marc_iconv_reset(mt, wr_data_tmp);
853 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
854 marc_iconv_reset(mt, wr_data_tmp);
855 data_length += wrbuf_len(wr_data_tmp);
857 case YAZ_MARC_COMMENT:
859 case YAZ_MARC_LEADER:
864 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
865 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
866 data_offset += data_length;
869 /* mark end of directory */
870 wrbuf_putc(wr_dir, ISO2709_FS);
872 /* base address of data (comes after leader+directory) */
873 base_address = 24 + wrbuf_len(wr_dir);
875 wr_head = wrbuf_alloc();
877 /* write record length */
878 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
879 /* from "original" leader */
880 wrbuf_write(wr_head, leader+5, 7);
881 /* base address of data */
882 wrbuf_printf(wr_head, "%05d", base_address);
883 /* from "original" leader */
884 wrbuf_write(wr_head, leader+17, 7);
886 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
887 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
888 wrbuf_destroy(wr_head);
889 wrbuf_destroy(wr_dir);
890 wrbuf_destroy(wr_data_tmp);
892 for (n = mt->nodes; n; n = n->next)
894 struct yaz_marc_subfield *s;
898 case YAZ_MARC_DATAFIELD:
899 wrbuf_printf(wr, "%.*s", indicator_length,
900 n->u.datafield.indicator);
901 for (s = n->u.datafield.subfields; s; s = s->next)
903 wrbuf_putc(wr, ISO2709_IDFS);
904 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
905 marc_iconv_reset(mt, wr);
907 wrbuf_putc(wr, ISO2709_FS);
909 case YAZ_MARC_CONTROLFIELD:
910 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
911 marc_iconv_reset(mt, wr);
912 wrbuf_putc(wr, ISO2709_FS);
914 case YAZ_MARC_COMMENT:
916 case YAZ_MARC_LEADER:
920 wrbuf_printf(wr, "%c", ISO2709_RS);
925 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
927 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
930 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
932 return -1; /* error */
933 return r; /* OK, return length > 0 */
936 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
937 const char **result, size_t *rsize)
941 wrbuf_rewind(mt->m_wr);
942 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
944 *result = wrbuf_cstr(mt->m_wr);
946 *rsize = wrbuf_len(mt->m_wr);
950 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
956 void yaz_marc_debug(yaz_marc_t mt, int level)
962 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
967 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
969 struct yaz_marc_node *n;
971 for (n = mt->nodes; n; n = n->next)
972 if (n->which == YAZ_MARC_LEADER)
974 leader = n->u.leader;
975 memcpy(leader+off, str, strlen(str));
980 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
982 xfree(mt->leader_spec);
986 char dummy_leader[24];
987 if (marc_exec_leader(leader_spec, dummy_leader, 24))
989 mt->leader_spec = xstrdup(leader_spec);
994 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
996 const char *cp = leader_spec;
1001 int no_read = 0, no = 0;
1003 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1004 if (no < 2 || no_read < 3)
1006 if (pos < 0 || pos >= size)
1011 const char *vp = strchr(val+1, '\'');
1017 if (len + pos > size)
1019 memcpy(leader + pos, val+1, len);
1021 else if (*val >= '0' && *val <= '9')
1037 int yaz_marc_decode_formatstr(const char *arg)
1040 if (!strcmp(arg, "marc"))
1041 mode = YAZ_MARC_ISO2709;
1042 if (!strcmp(arg, "marcxml"))
1043 mode = YAZ_MARC_MARCXML;
1044 if (!strcmp(arg, "marcxchange"))
1045 mode = YAZ_MARC_XCHANGE;
1046 if (!strcmp(arg, "line"))
1047 mode = YAZ_MARC_LINE;
1051 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1053 mt->write_using_libxml2 = enable;
1059 * indent-tabs-mode: nil
1061 * vim: shiftwidth=4 tabstop=8 expandtab