2 * Copyright (C) 1995-2006, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.40 2006-12-18 10:33:22 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 int marc_exec_leader(const char *leader_spec, char *leader,
132 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
134 struct yaz_marc_node *n = nmem_malloc(mt->nmem, sizeof(*n));
137 mt->nodes_pp = &n->next;
142 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
143 const xmlNode *ptr_data)
145 struct yaz_marc_node *n = yaz_marc_add_node(mt);
146 n->which = YAZ_MARC_CONTROLFIELD;
147 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
148 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
153 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
155 struct yaz_marc_node *n = yaz_marc_add_node(mt);
156 n->which = YAZ_MARC_COMMENT;
157 n->u.comment = nmem_strdup(mt->nmem, comment);
160 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
167 _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
171 vsnprintf(buf, sizeof(buf), fmt, ap);
173 vsprintf(buf, fmt, ap);
177 yaz_marc_add_comment(mt, buf);
181 int yaz_marc_get_debug(yaz_marc_t mt)
186 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
188 struct yaz_marc_node *n = yaz_marc_add_node(mt);
189 n->which = YAZ_MARC_LEADER;
190 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
191 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
194 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
195 const char *data, size_t data_len)
197 struct yaz_marc_node *n = yaz_marc_add_node(mt);
198 n->which = YAZ_MARC_CONTROLFIELD;
199 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
200 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
206 sprintf(msg, "controlfield:");
207 for (i = 0; i < 16 && i < data_len; i++)
208 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
210 sprintf(msg + strlen(msg), " ..");
211 yaz_marc_add_comment(mt, msg);
215 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
216 const char *indicator, size_t indicator_len)
218 struct yaz_marc_node *n = yaz_marc_add_node(mt);
219 n->which = YAZ_MARC_DATAFIELD;
220 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
221 n->u.datafield.indicator =
222 nmem_strdupn(mt->nmem, indicator, indicator_len);
223 n->u.datafield.subfields = 0;
225 /* make subfield_pp the current (last one) */
226 mt->subfield_pp = &n->u.datafield.subfields;
230 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
231 const char *indicator, size_t indicator_len)
233 struct yaz_marc_node *n = yaz_marc_add_node(mt);
234 n->which = YAZ_MARC_DATAFIELD;
235 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
236 n->u.datafield.indicator =
237 nmem_strdupn(mt->nmem, indicator, indicator_len);
238 n->u.datafield.subfields = 0;
240 /* make subfield_pp the current (last one) */
241 mt->subfield_pp = &n->u.datafield.subfields;
245 void yaz_marc_add_subfield(yaz_marc_t mt,
246 const char *code_data, size_t code_data_len)
253 sprintf(msg, "subfield:");
254 for (i = 0; i < 16 && i < code_data_len; i++)
255 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
256 if (i < code_data_len)
257 sprintf(msg + strlen(msg), " ..");
258 yaz_marc_add_comment(mt, msg);
263 struct yaz_marc_subfield *n = nmem_malloc(mt->nmem, sizeof(*n));
264 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
266 /* mark subfield_pp to point to this one, so we append here next */
267 *mt->subfield_pp = n;
268 mt->subfield_pp = &n->next;
272 int atoi_n_check(const char *buf, int size, int *val)
275 for (i = 0; i < size; i++)
276 if (!isdigit(i[(const unsigned char *) buf]))
278 *val = atoi_n(buf, size);
282 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
283 int *indicator_length,
284 int *identifier_length,
286 int *length_data_entry,
287 int *length_starting,
288 int *length_implementation)
292 memcpy(leader, leader_c, 24);
294 if (!atoi_n_check(leader+10, 1, indicator_length))
297 "Indicator length at offset 10 should hold a digit."
300 *indicator_length = 2;
302 if (!atoi_n_check(leader+11, 1, identifier_length))
305 "Identifier length at offset 11 should hold a digit."
308 *identifier_length = 2;
310 if (!atoi_n_check(leader+12, 5, base_address))
313 "Base address at offsets 12..16 should hold a number."
317 if (!atoi_n_check(leader+20, 1, length_data_entry))
320 "Length data entry at offset 20 should hold a digit."
322 *length_data_entry = 4;
325 if (!atoi_n_check(leader+21, 1, length_starting))
328 "Length starting at offset 21 should hold a digit."
330 *length_starting = 5;
333 if (!atoi_n_check(leader+22, 1, length_implementation))
336 "Length implementation at offset 22 should hold a digit."
338 *length_implementation = 0;
344 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
345 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
346 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
347 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
348 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
349 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
351 yaz_marc_add_leader(mt, leader, 24);
354 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
356 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
357 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
360 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
362 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
363 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
366 /* try to guess how many bytes the identifier really is! */
367 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
372 for (i = 1; i<5; i++)
375 size_t outbytesleft = sizeof(outbuf);
377 const char *inp = buf;
379 size_t inbytesleft = i;
380 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
381 &outp, &outbytesleft);
382 if (r != (size_t) (-1))
383 return i; /* got a complete sequence */
385 return 1; /* giving up */
387 return 1; /* we don't know */
390 void yaz_marc_reset(yaz_marc_t mt)
392 nmem_reset(mt->nmem);
394 mt->nodes_pp = &mt->nodes;
398 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
400 struct yaz_marc_node *n;
401 int identifier_length;
402 const char *leader = 0;
404 for (n = mt->nodes; n; n = n->next)
405 if (n->which == YAZ_MARC_LEADER)
407 leader = n->u.leader;
413 if (!atoi_n_check(leader+11, 1, &identifier_length))
416 for (n = mt->nodes; n; n = n->next)
420 case YAZ_MARC_COMMENT:
421 wrbuf_iconv_write(wr, mt->iconv_cd,
422 n->u.comment, strlen(n->u.comment));
423 wrbuf_puts(wr, ")\n");
433 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
435 struct yaz_marc_node *n;
436 int identifier_length;
437 const char *leader = 0;
439 for (n = mt->nodes; n; n = n->next)
440 if (n->which == YAZ_MARC_LEADER)
442 leader = n->u.leader;
448 if (!atoi_n_check(leader+11, 1, &identifier_length))
451 for (n = mt->nodes; n; n = n->next)
453 struct yaz_marc_subfield *s;
456 case YAZ_MARC_DATAFIELD:
457 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
458 n->u.datafield.indicator);
459 for (s = n->u.datafield.subfields; s; s = s->next)
461 /* if identifier length is 2 (most MARCs),
462 the code is a single character .. However we've
463 seen multibyte codes, so see how big it really is */
464 size_t using_code_len =
465 (identifier_length != 2) ? identifier_length - 1
467 cdata_one_character(mt, s->code_data);
469 wrbuf_puts (wr, mt->subfield_str);
470 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
472 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
473 wrbuf_iconv_puts(wr, mt->iconv_cd,
474 s->code_data + using_code_len);
475 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
478 wrbuf_puts (wr, mt->endline_str);
480 case YAZ_MARC_CONTROLFIELD:
481 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
482 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
483 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
484 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
486 wrbuf_puts (wr, mt->endline_str);
488 case YAZ_MARC_COMMENT:
490 wrbuf_iconv_write(wr, mt->iconv_cd,
491 n->u.comment, strlen(n->u.comment));
492 wrbuf_puts(wr, ")\n");
494 case YAZ_MARC_LEADER:
495 wrbuf_printf(wr, "%s\n", n->u.leader);
498 wrbuf_puts(wr, "\n");
502 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
507 return yaz_marc_write_line(mt, wr);
508 case YAZ_MARC_MARCXML:
509 return yaz_marc_write_marcxml(mt, wr);
510 case YAZ_MARC_XCHANGE:
511 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
512 case YAZ_MARC_ISO2709:
513 return yaz_marc_write_iso2709(mt, wr);
515 return yaz_marc_write_check(mt, wr);
520 /** \brief common MARC XML/Xchange writer
522 \param wr WRBUF output
523 \param ns XMLNS for the elements
524 \param format record format (e.g. "MARC21")
525 \param type record type (e.g. "Bibliographic")
527 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
532 struct yaz_marc_node *n;
533 int identifier_length;
534 const char *leader = 0;
536 for (n = mt->nodes; n; n = n->next)
537 if (n->which == YAZ_MARC_LEADER)
539 leader = n->u.leader;
545 if (!atoi_n_check(leader+11, 1, &identifier_length))
548 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
550 wrbuf_printf(wr, " format=\"%.80s\"", format);
552 wrbuf_printf(wr, " type=\"%.80s\"", type);
553 wrbuf_printf(wr, ">\n");
554 for (n = mt->nodes; n; n = n->next)
556 struct yaz_marc_subfield *s;
560 case YAZ_MARC_DATAFIELD:
561 wrbuf_printf(wr, " <datafield tag=\"");
562 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
563 strlen(n->u.datafield.tag));
564 wrbuf_printf(wr, "\"");
565 if (n->u.datafield.indicator)
568 for (i = 0; n->u.datafield.indicator[i]; i++)
570 wrbuf_printf(wr, " ind%d=\"", i+1);
571 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
572 n->u.datafield.indicator+i, 1);
573 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
576 wrbuf_printf(wr, ">\n");
577 for (s = n->u.datafield.subfields; s; s = s->next)
579 /* if identifier length is 2 (most MARCs),
580 the code is a single character .. However we've
581 seen multibyte codes, so see how big it really is */
582 size_t using_code_len =
583 (identifier_length != 2) ? identifier_length - 1
585 cdata_one_character(mt, s->code_data);
587 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
588 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
589 s->code_data, using_code_len);
590 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
591 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
592 s->code_data + using_code_len,
593 strlen(s->code_data + using_code_len));
594 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
595 wrbuf_puts(wr, "\n");
597 wrbuf_printf(wr, " </datafield>\n");
599 case YAZ_MARC_CONTROLFIELD:
600 wrbuf_printf(wr, " <controlfield tag=\"");
601 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
602 strlen(n->u.controlfield.tag));
603 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
604 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
605 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
606 wrbuf_puts(wr, "\n");
608 case YAZ_MARC_COMMENT:
609 wrbuf_printf(wr, "<!-- ");
610 wrbuf_puts(wr, n->u.comment);
611 wrbuf_printf(wr, " -->\n");
613 case YAZ_MARC_LEADER:
614 wrbuf_printf(wr, " <leader>");
615 wrbuf_iconv_write_cdata(wr,
616 0 /* no charset conversion for leader */,
617 n->u.leader, strlen(n->u.leader));
618 wrbuf_printf(wr, "</leader>\n");
621 wrbuf_puts(wr, "</record>\n");
625 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
630 if (mt->write_using_libxml2)
635 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
639 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
642 xmlDocSetRootElement(doc, root_ptr);
643 xmlDocDumpMemory(doc, &buf_out, &len_out);
645 wrbuf_write(wr, (const char *) buf_out, len_out);
653 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
656 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
658 if (!mt->leader_spec)
659 yaz_marc_modify_leader(mt, 9, "a");
660 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
664 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
668 return yaz_marc_write_marcxml_ns(mt, wr,
669 "http://www.bs.dk/standards/MarcXchange",
674 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
680 struct yaz_marc_node *n;
681 int identifier_length;
682 const char *leader = 0;
686 for (n = mt->nodes; n; n = n->next)
687 if (n->which == YAZ_MARC_LEADER)
689 leader = n->u.leader;
695 if (!atoi_n_check(leader+11, 1, &identifier_length))
698 record_ptr = xmlNewNode(0, BAD_CAST "record");
699 *root_ptr = record_ptr;
701 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
704 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
706 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
707 for (n = mt->nodes; n; n = n->next)
709 struct yaz_marc_subfield *s;
714 case YAZ_MARC_DATAFIELD:
715 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
716 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
717 if (n->u.datafield.indicator)
720 for (i = 0; n->u.datafield.indicator[i]; i++)
725 sprintf(ind_str, "ind%d", i+1);
726 ind_val[0] = n->u.datafield.indicator[i];
728 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
731 for (s = n->u.datafield.subfields; s; s = s->next)
735 xmlNode *ptr_subfield;
736 /* if identifier length is 2 (most MARCs),
737 the code is a single character .. However we've
738 seen multibyte codes, so see how big it really is */
739 size_t using_code_len =
740 (identifier_length != 2) ? identifier_length - 1
742 cdata_one_character(mt, s->code_data);
744 if (using_code_len >= sizeof(code_val)-1)
747 ptr_subfield = xmlNewTextChild(
750 BAD_CAST (s->code_data + using_code_len));
752 memcpy(code_val, s->code_data, using_code_len);
753 code_val[using_code_len] = '\0';
755 xmlNewProp(ptr_subfield, BAD_CAST "code", BAD_CAST code_val);
758 case YAZ_MARC_CONTROLFIELD:
759 ptr = xmlNewTextChild(record_ptr, ns_record,
760 BAD_CAST "controlfield",
761 BAD_CAST n->u.controlfield.data);
763 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
765 case YAZ_MARC_COMMENT:
766 ptr = xmlNewComment(BAD_CAST n->u.comment);
767 xmlAddChild(record_ptr, ptr);
769 case YAZ_MARC_LEADER:
770 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
771 BAD_CAST n->u.leader);
781 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
783 struct yaz_marc_node *n;
784 int indicator_length;
785 int identifier_length;
786 int length_data_entry;
788 int length_implementation;
790 const char *leader = 0;
791 WRBUF wr_dir, wr_head, wr_data_tmp;
794 for (n = mt->nodes; n; n = n->next)
795 if (n->which == YAZ_MARC_LEADER)
796 leader = n->u.leader;
800 if (!atoi_n_check(leader+10, 1, &indicator_length))
802 if (!atoi_n_check(leader+11, 1, &identifier_length))
804 if (!atoi_n_check(leader+20, 1, &length_data_entry))
806 if (!atoi_n_check(leader+21, 1, &length_starting))
808 if (!atoi_n_check(leader+22, 1, &length_implementation))
811 wr_data_tmp = wrbuf_alloc();
812 wr_dir = wrbuf_alloc();
813 for (n = mt->nodes; n; n = n->next)
816 struct yaz_marc_subfield *s;
820 case YAZ_MARC_DATAFIELD:
821 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
822 data_length += indicator_length;
823 wrbuf_rewind(wr_data_tmp);
824 for (s = n->u.datafield.subfields; s; s = s->next)
826 /* write dummy IDFS + content */
827 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
828 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
830 /* write dummy FS (makes MARC-8 to become ASCII) */
831 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
832 data_length += wrbuf_len(wr_data_tmp);
834 case YAZ_MARC_CONTROLFIELD:
835 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
837 wrbuf_rewind(wr_data_tmp);
838 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
839 n->u.controlfield.data);
840 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
841 data_length += wrbuf_len(wr_data_tmp);
843 case YAZ_MARC_COMMENT:
845 case YAZ_MARC_LEADER:
850 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
851 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
852 data_offset += data_length;
855 /* mark end of directory */
856 wrbuf_putc(wr_dir, ISO2709_FS);
858 /* base address of data (comes after leader+directory) */
859 base_address = 24 + wrbuf_len(wr_dir);
861 wr_head = wrbuf_alloc();
863 /* write record length */
864 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
865 /* from "original" leader */
866 wrbuf_write(wr_head, leader+5, 7);
867 /* base address of data */
868 wrbuf_printf(wr_head, "%05d", base_address);
869 /* from "original" leader */
870 wrbuf_write(wr_head, leader+17, 7);
872 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
873 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
874 wrbuf_free(wr_head, 1);
875 wrbuf_free(wr_dir, 1);
876 wrbuf_free(wr_data_tmp, 1);
878 for (n = mt->nodes; n; n = n->next)
880 struct yaz_marc_subfield *s;
884 case YAZ_MARC_DATAFIELD:
885 wrbuf_printf(wr, "%.*s", indicator_length,
886 n->u.datafield.indicator);
887 for (s = n->u.datafield.subfields; s; s = s->next)
889 wrbuf_putc(wr, ISO2709_IDFS);
890 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
891 /* write dummy blank - makes MARC-8 to become ASCII */
892 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
895 wrbuf_putc(wr, ISO2709_FS);
897 case YAZ_MARC_CONTROLFIELD:
898 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
899 /* write dummy blank - makes MARC-8 to become ASCII */
900 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
902 wrbuf_putc(wr, ISO2709_FS);
904 case YAZ_MARC_COMMENT:
906 case YAZ_MARC_LEADER:
910 wrbuf_printf(wr, "%c", ISO2709_RS);
915 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
917 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
920 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
922 return -1; /* error */
923 return r; /* OK, return length > 0 */
926 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
927 char **result, int *rsize)
931 wrbuf_rewind(mt->m_wr);
932 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
934 *result = wrbuf_buf(mt->m_wr);
936 *rsize = wrbuf_len(mt->m_wr);
940 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
946 void yaz_marc_debug(yaz_marc_t mt, int level)
952 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
957 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
959 struct yaz_marc_node *n;
961 for (n = mt->nodes; n; n = n->next)
962 if (n->which == YAZ_MARC_LEADER)
964 leader = n->u.leader;
965 memcpy(leader+off, str, strlen(str));
971 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
973 yaz_marc_t mt = yaz_marc_create();
978 r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
979 yaz_marc_destroy(mt);
984 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
986 return yaz_marc_decode(buf, wr, debug, bsize, 0);
990 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
992 yaz_marc_t mt = yaz_marc_create();
996 r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
1000 fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1001 yaz_marc_destroy(mt);
1006 int marc_display_ex (const char *buf, FILE *outf, int debug)
1008 return marc_display_exl (buf, outf, debug, -1);
1012 int marc_display (const char *buf, FILE *outf)
1014 return marc_display_ex (buf, outf, 0);
1017 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1019 xfree(mt->leader_spec);
1020 mt->leader_spec = 0;
1023 char dummy_leader[24];
1024 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1026 mt->leader_spec = xstrdup(leader_spec);
1031 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1033 const char *cp = leader_spec;
1038 int no_read = 0, no = 0;
1040 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1041 if (no < 2 || no_read < 3)
1043 if (pos < 0 || pos >= size)
1048 const char *vp = strchr(val+1, '\'');
1054 if (len + pos > size)
1056 memcpy(leader + pos, val+1, len);
1058 else if (*val >= '0' && *val <= '9')
1074 int yaz_marc_decode_formatstr(const char *arg)
1077 if (!strcmp(arg, "marc"))
1078 mode = YAZ_MARC_ISO2709;
1079 if (!strcmp(arg, "marcxml"))
1080 mode = YAZ_MARC_MARCXML;
1081 if (!strcmp(arg, "marcxchange"))
1082 mode = YAZ_MARC_XCHANGE;
1083 if (!strcmp(arg, "line"))
1084 mode = YAZ_MARC_LINE;
1088 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1090 mt->write_using_libxml2 = enable;
1096 * indent-tabs-mode: nil
1098 * vim: shiftwidth=4 tabstop=8 expandtab