2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.51 2007-09-20 17:22:45 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 = (struct yaz_marc_node *)
141 nmem_malloc(mt->nmem, sizeof(*n));
144 mt->nodes_pp = &n->next;
149 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
150 const xmlNode *ptr_data)
152 struct yaz_marc_node *n = yaz_marc_add_node(mt);
153 n->which = YAZ_MARC_CONTROLFIELD;
154 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
155 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
160 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
162 struct yaz_marc_node *n = yaz_marc_add_node(mt);
163 n->which = YAZ_MARC_COMMENT;
164 n->u.comment = nmem_strdup(mt->nmem, comment);
167 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
173 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
174 yaz_marc_add_comment(mt, buf);
178 int yaz_marc_get_debug(yaz_marc_t mt)
183 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
185 struct yaz_marc_node *n = yaz_marc_add_node(mt);
186 n->which = YAZ_MARC_LEADER;
187 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
188 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
191 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
192 const char *data, size_t data_len)
194 struct yaz_marc_node *n = yaz_marc_add_node(mt);
195 n->which = YAZ_MARC_CONTROLFIELD;
196 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
197 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
203 sprintf(msg, "controlfield:");
204 for (i = 0; i < 16 && i < data_len; i++)
205 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
207 sprintf(msg + strlen(msg), " ..");
208 yaz_marc_add_comment(mt, msg);
212 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
213 const char *indicator, size_t indicator_len)
215 struct yaz_marc_node *n = yaz_marc_add_node(mt);
216 n->which = YAZ_MARC_DATAFIELD;
217 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
218 n->u.datafield.indicator =
219 nmem_strdupn(mt->nmem, indicator, indicator_len);
220 n->u.datafield.subfields = 0;
222 /* make subfield_pp the current (last one) */
223 mt->subfield_pp = &n->u.datafield.subfields;
227 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
228 const char *indicator, size_t indicator_len)
230 struct yaz_marc_node *n = yaz_marc_add_node(mt);
231 n->which = YAZ_MARC_DATAFIELD;
232 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
233 n->u.datafield.indicator =
234 nmem_strdupn(mt->nmem, indicator, indicator_len);
235 n->u.datafield.subfields = 0;
237 /* make subfield_pp the current (last one) */
238 mt->subfield_pp = &n->u.datafield.subfields;
242 void yaz_marc_add_subfield(yaz_marc_t mt,
243 const char *code_data, size_t code_data_len)
250 sprintf(msg, "subfield:");
251 for (i = 0; i < 16 && i < code_data_len; i++)
252 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
253 if (i < code_data_len)
254 sprintf(msg + strlen(msg), " ..");
255 yaz_marc_add_comment(mt, msg);
260 struct yaz_marc_subfield *n = (struct yaz_marc_subfield *)
261 nmem_malloc(mt->nmem, sizeof(*n));
262 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
264 /* mark subfield_pp to point to this one, so we append here next */
265 *mt->subfield_pp = n;
266 mt->subfield_pp = &n->next;
270 int atoi_n_check(const char *buf, int size, int *val)
273 for (i = 0; i < size; i++)
274 if (!isdigit(i[(const unsigned char *) buf]))
276 *val = atoi_n(buf, size);
280 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
281 int *indicator_length,
282 int *identifier_length,
284 int *length_data_entry,
285 int *length_starting,
286 int *length_implementation)
290 memcpy(leader, leader_c, 24);
292 if (!atoi_n_check(leader+10, 1, indicator_length))
295 "Indicator length at offset 10 should hold a digit."
298 *indicator_length = 2;
300 if (!atoi_n_check(leader+11, 1, identifier_length))
303 "Identifier length at offset 11 should hold a digit."
306 *identifier_length = 2;
308 if (!atoi_n_check(leader+12, 5, base_address))
311 "Base address at offsets 12..16 should hold a number."
315 if (!atoi_n_check(leader+20, 1, length_data_entry))
318 "Length data entry at offset 20 should hold a digit."
320 *length_data_entry = 4;
323 if (!atoi_n_check(leader+21, 1, length_starting))
326 "Length starting at offset 21 should hold a digit."
328 *length_starting = 5;
331 if (!atoi_n_check(leader+22, 1, length_implementation))
334 "Length implementation at offset 22 should hold a digit."
336 *length_implementation = 0;
342 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
343 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
344 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
345 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
346 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
347 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
349 yaz_marc_add_leader(mt, leader, 24);
352 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
354 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
355 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
358 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
360 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
361 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
364 /* try to guess how many bytes the identifier really is! */
365 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
370 for (i = 1; i<5; i++)
373 size_t outbytesleft = sizeof(outbuf);
375 const char *inp = buf;
377 size_t inbytesleft = i;
378 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
379 &outp, &outbytesleft);
380 if (r != (size_t) (-1))
381 return i; /* got a complete sequence */
383 return 1; /* giving up */
385 return 1; /* we don't know */
388 void yaz_marc_reset(yaz_marc_t mt)
390 nmem_reset(mt->nmem);
392 mt->nodes_pp = &mt->nodes;
396 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
398 struct yaz_marc_node *n;
399 int identifier_length;
400 const char *leader = 0;
402 for (n = mt->nodes; n; n = n->next)
403 if (n->which == YAZ_MARC_LEADER)
405 leader = n->u.leader;
411 if (!atoi_n_check(leader+11, 1, &identifier_length))
414 for (n = mt->nodes; n; n = n->next)
418 case YAZ_MARC_COMMENT:
419 wrbuf_iconv_write(wr, mt->iconv_cd,
420 n->u.comment, strlen(n->u.comment));
421 wrbuf_puts(wr, ")\n");
431 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
433 struct yaz_marc_node *n;
434 int identifier_length;
435 const char *leader = 0;
437 for (n = mt->nodes; n; n = n->next)
438 if (n->which == YAZ_MARC_LEADER)
440 leader = n->u.leader;
446 if (!atoi_n_check(leader+11, 1, &identifier_length))
449 for (n = mt->nodes; n; n = n->next)
451 struct yaz_marc_subfield *s;
454 case YAZ_MARC_DATAFIELD:
455 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
456 n->u.datafield.indicator);
457 for (s = n->u.datafield.subfields; s; s = s->next)
459 /* if identifier length is 2 (most MARCs),
460 the code is a single character .. However we've
461 seen multibyte codes, so see how big it really is */
462 size_t using_code_len =
463 (identifier_length != 2) ? identifier_length - 1
465 cdata_one_character(mt, s->code_data);
467 wrbuf_puts (wr, mt->subfield_str);
468 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
470 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
471 wrbuf_iconv_puts(wr, mt->iconv_cd,
472 s->code_data + using_code_len);
473 marc_iconv_reset(mt, wr);
475 wrbuf_puts (wr, mt->endline_str);
477 case YAZ_MARC_CONTROLFIELD:
478 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
479 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
480 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
481 marc_iconv_reset(mt, wr);
482 wrbuf_puts (wr, mt->endline_str);
484 case YAZ_MARC_COMMENT:
486 wrbuf_iconv_write(wr, mt->iconv_cd,
487 n->u.comment, strlen(n->u.comment));
488 marc_iconv_reset(mt, wr);
489 wrbuf_puts(wr, ")\n");
491 case YAZ_MARC_LEADER:
492 wrbuf_printf(wr, "%s\n", n->u.leader);
495 wrbuf_puts(wr, "\n");
499 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
504 return yaz_marc_write_line(mt, wr);
505 case YAZ_MARC_MARCXML:
506 return yaz_marc_write_marcxml(mt, wr);
507 case YAZ_MARC_XCHANGE:
508 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
509 case YAZ_MARC_ISO2709:
510 return yaz_marc_write_iso2709(mt, wr);
512 return yaz_marc_write_check(mt, wr);
517 /** \brief common MARC XML/Xchange writer
519 \param wr WRBUF output
520 \param ns XMLNS for the elements
521 \param format record format (e.g. "MARC21")
522 \param type record type (e.g. "Bibliographic")
524 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
529 struct yaz_marc_node *n;
530 int identifier_length;
531 const char *leader = 0;
533 for (n = mt->nodes; n; n = n->next)
534 if (n->which == YAZ_MARC_LEADER)
536 leader = n->u.leader;
542 if (!atoi_n_check(leader+11, 1, &identifier_length))
545 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
547 wrbuf_printf(wr, " format=\"%.80s\"", format);
549 wrbuf_printf(wr, " type=\"%.80s\"", type);
550 wrbuf_printf(wr, ">\n");
551 for (n = mt->nodes; n; n = n->next)
553 struct yaz_marc_subfield *s;
557 case YAZ_MARC_DATAFIELD:
558 wrbuf_printf(wr, " <datafield tag=\"");
559 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
560 strlen(n->u.datafield.tag));
561 wrbuf_printf(wr, "\"");
562 if (n->u.datafield.indicator)
565 for (i = 0; n->u.datafield.indicator[i]; i++)
567 wrbuf_printf(wr, " ind%d=\"", i+1);
568 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
569 n->u.datafield.indicator+i, 1);
570 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
573 wrbuf_printf(wr, ">\n");
574 for (s = n->u.datafield.subfields; s; s = s->next)
576 /* if identifier length is 2 (most MARCs),
577 the code is a single character .. However we've
578 seen multibyte codes, so see how big it really is */
579 size_t using_code_len =
580 (identifier_length != 2) ? identifier_length - 1
582 cdata_one_character(mt, s->code_data);
584 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
585 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
586 s->code_data, using_code_len);
587 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
588 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
589 s->code_data + using_code_len,
590 strlen(s->code_data + using_code_len));
591 marc_iconv_reset(mt, wr);
592 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
593 wrbuf_puts(wr, "\n");
595 wrbuf_printf(wr, " </datafield>\n");
597 case YAZ_MARC_CONTROLFIELD:
598 wrbuf_printf(wr, " <controlfield tag=\"");
599 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
600 strlen(n->u.controlfield.tag));
601 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
602 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
603 n->u.controlfield.data,
604 strlen(n->u.controlfield.data));
606 marc_iconv_reset(mt, wr);
607 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
608 wrbuf_puts(wr, "\n");
610 case YAZ_MARC_COMMENT:
611 wrbuf_printf(wr, "<!-- ");
612 wrbuf_puts(wr, n->u.comment);
613 wrbuf_printf(wr, " -->\n");
615 case YAZ_MARC_LEADER:
616 wrbuf_printf(wr, " <leader>");
617 wrbuf_iconv_write_cdata(wr,
618 0 /* no charset conversion for leader */,
619 n->u.leader, strlen(n->u.leader));
620 wrbuf_printf(wr, "</leader>\n");
623 wrbuf_puts(wr, "</record>\n");
627 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
632 if (mt->write_using_libxml2)
638 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
642 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
645 xmlDocSetRootElement(doc, root_ptr);
646 xmlDocDumpMemory(doc, &buf_out, &len_out);
648 wrbuf_write(wr, (const char *) buf_out, len_out);
659 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
662 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
664 if (!mt->leader_spec)
665 yaz_marc_modify_leader(mt, 9, "a");
666 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
670 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
674 return yaz_marc_write_marcxml_ns(mt, wr,
675 "http://www.bs.dk/standards/MarcXchange",
680 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
686 struct yaz_marc_node *n;
687 int identifier_length;
688 const char *leader = 0;
693 for (n = mt->nodes; n; n = n->next)
694 if (n->which == YAZ_MARC_LEADER)
696 leader = n->u.leader;
702 if (!atoi_n_check(leader+11, 1, &identifier_length))
705 wr_cdata = wrbuf_alloc();
707 record_ptr = xmlNewNode(0, BAD_CAST "record");
708 *root_ptr = record_ptr;
710 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
711 xmlSetNs(record_ptr, ns_record);
714 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
716 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
717 for (n = mt->nodes; n; n = n->next)
719 struct yaz_marc_subfield *s;
724 case YAZ_MARC_DATAFIELD:
725 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
726 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
727 if (n->u.datafield.indicator)
730 for (i = 0; n->u.datafield.indicator[i]; i++)
735 sprintf(ind_str, "ind%d", i+1);
736 ind_val[0] = n->u.datafield.indicator[i];
738 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
741 for (s = n->u.datafield.subfields; s; s = s->next)
743 xmlNode *ptr_subfield;
744 /* if identifier length is 2 (most MARCs),
745 the code is a single character .. However we've
746 seen multibyte codes, so see how big it really is */
747 size_t using_code_len =
748 (identifier_length != 2) ? identifier_length - 1
750 cdata_one_character(mt, s->code_data);
752 wrbuf_rewind(wr_cdata);
753 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
754 s->code_data + using_code_len);
755 marc_iconv_reset(mt, wr_cdata);
756 ptr_subfield = xmlNewTextChild(
758 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
760 wrbuf_rewind(wr_cdata);
761 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
762 s->code_data, using_code_len);
763 xmlNewProp(ptr_subfield, BAD_CAST "code",
764 BAD_CAST wrbuf_cstr(wr_cdata));
767 case YAZ_MARC_CONTROLFIELD:
768 wrbuf_rewind(wr_cdata);
769 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
770 marc_iconv_reset(mt, wr_cdata);
772 ptr = xmlNewTextChild(record_ptr, ns_record,
773 BAD_CAST "controlfield",
774 BAD_CAST wrbuf_cstr(wr_cdata));
776 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
778 case YAZ_MARC_COMMENT:
779 ptr = xmlNewComment(BAD_CAST n->u.comment);
780 xmlAddChild(record_ptr, ptr);
782 case YAZ_MARC_LEADER:
783 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
784 BAD_CAST n->u.leader);
788 wrbuf_destroy(wr_cdata);
795 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
797 struct yaz_marc_node *n;
798 int indicator_length;
799 int identifier_length;
800 int length_data_entry;
802 int length_implementation;
804 const char *leader = 0;
805 WRBUF wr_dir, wr_head, wr_data_tmp;
808 for (n = mt->nodes; n; n = n->next)
809 if (n->which == YAZ_MARC_LEADER)
810 leader = n->u.leader;
814 if (!atoi_n_check(leader+10, 1, &indicator_length))
816 if (!atoi_n_check(leader+11, 1, &identifier_length))
818 if (!atoi_n_check(leader+20, 1, &length_data_entry))
820 if (!atoi_n_check(leader+21, 1, &length_starting))
822 if (!atoi_n_check(leader+22, 1, &length_implementation))
825 wr_data_tmp = wrbuf_alloc();
826 wr_dir = wrbuf_alloc();
827 for (n = mt->nodes; n; n = n->next)
830 struct yaz_marc_subfield *s;
834 case YAZ_MARC_DATAFIELD:
835 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
836 data_length += indicator_length;
837 wrbuf_rewind(wr_data_tmp);
838 for (s = n->u.datafield.subfields; s; s = s->next)
840 /* write dummy IDFS + content */
841 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
842 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
843 marc_iconv_reset(mt, wr_data_tmp);
845 /* write dummy FS (makes MARC-8 to become ASCII) */
846 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
847 marc_iconv_reset(mt, wr_data_tmp);
848 data_length += wrbuf_len(wr_data_tmp);
850 case YAZ_MARC_CONTROLFIELD:
851 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
853 wrbuf_rewind(wr_data_tmp);
854 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
855 n->u.controlfield.data);
856 marc_iconv_reset(mt, wr_data_tmp);
857 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
858 marc_iconv_reset(mt, wr_data_tmp);
859 data_length += wrbuf_len(wr_data_tmp);
861 case YAZ_MARC_COMMENT:
863 case YAZ_MARC_LEADER:
868 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
869 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
870 data_offset += data_length;
873 /* mark end of directory */
874 wrbuf_putc(wr_dir, ISO2709_FS);
876 /* base address of data (comes after leader+directory) */
877 base_address = 24 + wrbuf_len(wr_dir);
879 wr_head = wrbuf_alloc();
881 /* write record length */
882 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
883 /* from "original" leader */
884 wrbuf_write(wr_head, leader+5, 7);
885 /* base address of data */
886 wrbuf_printf(wr_head, "%05d", base_address);
887 /* from "original" leader */
888 wrbuf_write(wr_head, leader+17, 7);
890 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
891 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
892 wrbuf_destroy(wr_head);
893 wrbuf_destroy(wr_dir);
894 wrbuf_destroy(wr_data_tmp);
896 for (n = mt->nodes; n; n = n->next)
898 struct yaz_marc_subfield *s;
902 case YAZ_MARC_DATAFIELD:
903 wrbuf_printf(wr, "%.*s", indicator_length,
904 n->u.datafield.indicator);
905 for (s = n->u.datafield.subfields; s; s = s->next)
907 wrbuf_putc(wr, ISO2709_IDFS);
908 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
909 marc_iconv_reset(mt, wr);
911 wrbuf_putc(wr, ISO2709_FS);
913 case YAZ_MARC_CONTROLFIELD:
914 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
915 marc_iconv_reset(mt, wr);
916 wrbuf_putc(wr, ISO2709_FS);
918 case YAZ_MARC_COMMENT:
920 case YAZ_MARC_LEADER:
924 wrbuf_printf(wr, "%c", ISO2709_RS);
929 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
931 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
934 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
936 return -1; /* error */
937 return r; /* OK, return length > 0 */
940 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
941 const char **result, size_t *rsize)
945 wrbuf_rewind(mt->m_wr);
946 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
948 *result = wrbuf_cstr(mt->m_wr);
950 *rsize = wrbuf_len(mt->m_wr);
954 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
960 void yaz_marc_debug(yaz_marc_t mt, int level)
966 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
971 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
973 struct yaz_marc_node *n;
975 for (n = mt->nodes; n; n = n->next)
976 if (n->which == YAZ_MARC_LEADER)
978 leader = n->u.leader;
979 memcpy(leader+off, str, strlen(str));
984 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
986 xfree(mt->leader_spec);
990 char dummy_leader[24];
991 if (marc_exec_leader(leader_spec, dummy_leader, 24))
993 mt->leader_spec = xstrdup(leader_spec);
998 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1000 const char *cp = leader_spec;
1005 int no_read = 0, no = 0;
1007 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1008 if (no < 2 || no_read < 3)
1010 if (pos < 0 || pos >= size)
1015 const char *vp = strchr(val+1, '\'');
1021 if (len + pos > size)
1023 memcpy(leader + pos, val+1, len);
1025 else if (*val >= '0' && *val <= '9')
1041 int yaz_marc_decode_formatstr(const char *arg)
1044 if (!strcmp(arg, "marc"))
1045 mode = YAZ_MARC_ISO2709;
1046 if (!strcmp(arg, "marcxml"))
1047 mode = YAZ_MARC_MARCXML;
1048 if (!strcmp(arg, "marcxchange"))
1049 mode = YAZ_MARC_XCHANGE;
1050 if (!strcmp(arg, "line"))
1051 mode = YAZ_MARC_LINE;
1055 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1057 mt->write_using_libxml2 = enable;
1063 * indent-tabs-mode: nil
1065 * vim: shiftwidth=4 tabstop=8 expandtab