2 * Copyright (C) 1995-2006, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.41 2007-01-02 07:01:56 quinn 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);
702 xmlSetNs(record_ptr, ns_record);
705 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
707 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
708 for (n = mt->nodes; n; n = n->next)
710 struct yaz_marc_subfield *s;
715 case YAZ_MARC_DATAFIELD:
716 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
717 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
718 if (n->u.datafield.indicator)
721 for (i = 0; n->u.datafield.indicator[i]; i++)
726 sprintf(ind_str, "ind%d", i+1);
727 ind_val[0] = n->u.datafield.indicator[i];
729 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
732 for (s = n->u.datafield.subfields; s; s = s->next)
736 xmlNode *ptr_subfield;
737 /* if identifier length is 2 (most MARCs),
738 the code is a single character .. However we've
739 seen multibyte codes, so see how big it really is */
740 size_t using_code_len =
741 (identifier_length != 2) ? identifier_length - 1
743 cdata_one_character(mt, s->code_data);
745 if (using_code_len >= sizeof(code_val)-1)
748 ptr_subfield = xmlNewTextChild(
751 BAD_CAST (s->code_data + using_code_len));
753 memcpy(code_val, s->code_data, using_code_len);
754 code_val[using_code_len] = '\0';
756 xmlNewProp(ptr_subfield, BAD_CAST "code", BAD_CAST code_val);
759 case YAZ_MARC_CONTROLFIELD:
760 ptr = xmlNewTextChild(record_ptr, ns_record,
761 BAD_CAST "controlfield",
762 BAD_CAST n->u.controlfield.data);
764 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
766 case YAZ_MARC_COMMENT:
767 ptr = xmlNewComment(BAD_CAST n->u.comment);
768 xmlAddChild(record_ptr, ptr);
770 case YAZ_MARC_LEADER:
771 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
772 BAD_CAST n->u.leader);
782 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
784 struct yaz_marc_node *n;
785 int indicator_length;
786 int identifier_length;
787 int length_data_entry;
789 int length_implementation;
791 const char *leader = 0;
792 WRBUF wr_dir, wr_head, wr_data_tmp;
795 for (n = mt->nodes; n; n = n->next)
796 if (n->which == YAZ_MARC_LEADER)
797 leader = n->u.leader;
801 if (!atoi_n_check(leader+10, 1, &indicator_length))
803 if (!atoi_n_check(leader+11, 1, &identifier_length))
805 if (!atoi_n_check(leader+20, 1, &length_data_entry))
807 if (!atoi_n_check(leader+21, 1, &length_starting))
809 if (!atoi_n_check(leader+22, 1, &length_implementation))
812 wr_data_tmp = wrbuf_alloc();
813 wr_dir = wrbuf_alloc();
814 for (n = mt->nodes; n; n = n->next)
817 struct yaz_marc_subfield *s;
821 case YAZ_MARC_DATAFIELD:
822 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
823 data_length += indicator_length;
824 wrbuf_rewind(wr_data_tmp);
825 for (s = n->u.datafield.subfields; s; s = s->next)
827 /* write dummy IDFS + content */
828 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
829 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
831 /* write dummy FS (makes MARC-8 to become ASCII) */
832 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
833 data_length += wrbuf_len(wr_data_tmp);
835 case YAZ_MARC_CONTROLFIELD:
836 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
838 wrbuf_rewind(wr_data_tmp);
839 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
840 n->u.controlfield.data);
841 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
842 data_length += wrbuf_len(wr_data_tmp);
844 case YAZ_MARC_COMMENT:
846 case YAZ_MARC_LEADER:
851 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
852 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
853 data_offset += data_length;
856 /* mark end of directory */
857 wrbuf_putc(wr_dir, ISO2709_FS);
859 /* base address of data (comes after leader+directory) */
860 base_address = 24 + wrbuf_len(wr_dir);
862 wr_head = wrbuf_alloc();
864 /* write record length */
865 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
866 /* from "original" leader */
867 wrbuf_write(wr_head, leader+5, 7);
868 /* base address of data */
869 wrbuf_printf(wr_head, "%05d", base_address);
870 /* from "original" leader */
871 wrbuf_write(wr_head, leader+17, 7);
873 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
874 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
875 wrbuf_free(wr_head, 1);
876 wrbuf_free(wr_dir, 1);
877 wrbuf_free(wr_data_tmp, 1);
879 for (n = mt->nodes; n; n = n->next)
881 struct yaz_marc_subfield *s;
885 case YAZ_MARC_DATAFIELD:
886 wrbuf_printf(wr, "%.*s", indicator_length,
887 n->u.datafield.indicator);
888 for (s = n->u.datafield.subfields; s; s = s->next)
890 wrbuf_putc(wr, ISO2709_IDFS);
891 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
892 /* write dummy blank - makes MARC-8 to become ASCII */
893 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
896 wrbuf_putc(wr, ISO2709_FS);
898 case YAZ_MARC_CONTROLFIELD:
899 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
900 /* write dummy blank - makes MARC-8 to become ASCII */
901 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
903 wrbuf_putc(wr, ISO2709_FS);
905 case YAZ_MARC_COMMENT:
907 case YAZ_MARC_LEADER:
911 wrbuf_printf(wr, "%c", ISO2709_RS);
916 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
918 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
921 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
923 return -1; /* error */
924 return r; /* OK, return length > 0 */
927 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
928 char **result, int *rsize)
932 wrbuf_rewind(mt->m_wr);
933 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
935 *result = wrbuf_buf(mt->m_wr);
937 *rsize = wrbuf_len(mt->m_wr);
941 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
947 void yaz_marc_debug(yaz_marc_t mt, int level)
953 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
958 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
960 struct yaz_marc_node *n;
962 for (n = mt->nodes; n; n = n->next)
963 if (n->which == YAZ_MARC_LEADER)
965 leader = n->u.leader;
966 memcpy(leader+off, str, strlen(str));
972 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
974 yaz_marc_t mt = yaz_marc_create();
979 r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
980 yaz_marc_destroy(mt);
985 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
987 return yaz_marc_decode(buf, wr, debug, bsize, 0);
991 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
993 yaz_marc_t mt = yaz_marc_create();
997 r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
1001 fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1002 yaz_marc_destroy(mt);
1007 int marc_display_ex (const char *buf, FILE *outf, int debug)
1009 return marc_display_exl (buf, outf, debug, -1);
1013 int marc_display (const char *buf, FILE *outf)
1015 return marc_display_ex (buf, outf, 0);
1018 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1020 xfree(mt->leader_spec);
1021 mt->leader_spec = 0;
1024 char dummy_leader[24];
1025 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1027 mt->leader_spec = xstrdup(leader_spec);
1032 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1034 const char *cp = leader_spec;
1039 int no_read = 0, no = 0;
1041 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1042 if (no < 2 || no_read < 3)
1044 if (pos < 0 || pos >= size)
1049 const char *vp = strchr(val+1, '\'');
1055 if (len + pos > size)
1057 memcpy(leader + pos, val+1, len);
1059 else if (*val >= '0' && *val <= '9')
1075 int yaz_marc_decode_formatstr(const char *arg)
1078 if (!strcmp(arg, "marc"))
1079 mode = YAZ_MARC_ISO2709;
1080 if (!strcmp(arg, "marcxml"))
1081 mode = YAZ_MARC_MARCXML;
1082 if (!strcmp(arg, "marcxchange"))
1083 mode = YAZ_MARC_XCHANGE;
1084 if (!strcmp(arg, "line"))
1085 mode = YAZ_MARC_LINE;
1089 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1091 mt->write_using_libxml2 = enable;
1097 * indent-tabs-mode: nil
1099 * vim: shiftwidth=4 tabstop=8 expandtab