2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.43 2007-01-06 16:08:04 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;
687 for (n = mt->nodes; n; n = n->next)
688 if (n->which == YAZ_MARC_LEADER)
690 leader = n->u.leader;
696 if (!atoi_n_check(leader+11, 1, &identifier_length))
699 wr_cdata = wrbuf_alloc();
701 record_ptr = xmlNewNode(0, BAD_CAST "record");
702 *root_ptr = record_ptr;
704 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
705 xmlSetNs(record_ptr, ns_record);
708 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
710 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
711 for (n = mt->nodes; n; n = n->next)
713 struct yaz_marc_subfield *s;
718 case YAZ_MARC_DATAFIELD:
719 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
720 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
721 if (n->u.datafield.indicator)
724 for (i = 0; n->u.datafield.indicator[i]; i++)
729 sprintf(ind_str, "ind%d", i+1);
730 ind_val[0] = n->u.datafield.indicator[i];
732 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
735 for (s = n->u.datafield.subfields; s; s = s->next)
737 xmlNode *ptr_subfield;
738 /* if identifier length is 2 (most MARCs),
739 the code is a single character .. However we've
740 seen multibyte codes, so see how big it really is */
741 size_t using_code_len =
742 (identifier_length != 2) ? identifier_length - 1
744 cdata_one_character(mt, s->code_data);
746 wrbuf_rewind(wr_cdata);
747 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
748 s->code_data + using_code_len);
750 ptr_subfield = xmlNewTextChild(
752 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
754 wrbuf_rewind(wr_cdata);
755 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
756 s->code_data, using_code_len);
757 xmlNewProp(ptr_subfield, BAD_CAST "code",
758 BAD_CAST wrbuf_cstr(wr_cdata));
761 case YAZ_MARC_CONTROLFIELD:
762 wrbuf_rewind(wr_cdata);
763 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
765 ptr = xmlNewTextChild(record_ptr, ns_record,
766 BAD_CAST "controlfield",
767 BAD_CAST wrbuf_cstr(wr_cdata));
769 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
771 case YAZ_MARC_COMMENT:
772 ptr = xmlNewComment(BAD_CAST n->u.comment);
773 xmlAddChild(record_ptr, ptr);
775 case YAZ_MARC_LEADER:
776 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
777 BAD_CAST n->u.leader);
781 wrbuf_destroy(wr_cdata);
788 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
790 struct yaz_marc_node *n;
791 int indicator_length;
792 int identifier_length;
793 int length_data_entry;
795 int length_implementation;
797 const char *leader = 0;
798 WRBUF wr_dir, wr_head, wr_data_tmp;
801 for (n = mt->nodes; n; n = n->next)
802 if (n->which == YAZ_MARC_LEADER)
803 leader = n->u.leader;
807 if (!atoi_n_check(leader+10, 1, &indicator_length))
809 if (!atoi_n_check(leader+11, 1, &identifier_length))
811 if (!atoi_n_check(leader+20, 1, &length_data_entry))
813 if (!atoi_n_check(leader+21, 1, &length_starting))
815 if (!atoi_n_check(leader+22, 1, &length_implementation))
818 wr_data_tmp = wrbuf_alloc();
819 wr_dir = wrbuf_alloc();
820 for (n = mt->nodes; n; n = n->next)
823 struct yaz_marc_subfield *s;
827 case YAZ_MARC_DATAFIELD:
828 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
829 data_length += indicator_length;
830 wrbuf_rewind(wr_data_tmp);
831 for (s = n->u.datafield.subfields; s; s = s->next)
833 /* write dummy IDFS + content */
834 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
835 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
837 /* write dummy FS (makes MARC-8 to become ASCII) */
838 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
839 data_length += wrbuf_len(wr_data_tmp);
841 case YAZ_MARC_CONTROLFIELD:
842 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
844 wrbuf_rewind(wr_data_tmp);
845 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
846 n->u.controlfield.data);
847 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
848 data_length += wrbuf_len(wr_data_tmp);
850 case YAZ_MARC_COMMENT:
852 case YAZ_MARC_LEADER:
857 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
858 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
859 data_offset += data_length;
862 /* mark end of directory */
863 wrbuf_putc(wr_dir, ISO2709_FS);
865 /* base address of data (comes after leader+directory) */
866 base_address = 24 + wrbuf_len(wr_dir);
868 wr_head = wrbuf_alloc();
870 /* write record length */
871 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
872 /* from "original" leader */
873 wrbuf_write(wr_head, leader+5, 7);
874 /* base address of data */
875 wrbuf_printf(wr_head, "%05d", base_address);
876 /* from "original" leader */
877 wrbuf_write(wr_head, leader+17, 7);
879 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
880 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
881 wrbuf_free(wr_head, 1);
882 wrbuf_free(wr_dir, 1);
883 wrbuf_free(wr_data_tmp, 1);
885 for (n = mt->nodes; n; n = n->next)
887 struct yaz_marc_subfield *s;
891 case YAZ_MARC_DATAFIELD:
892 wrbuf_printf(wr, "%.*s", indicator_length,
893 n->u.datafield.indicator);
894 for (s = n->u.datafield.subfields; s; s = s->next)
896 wrbuf_putc(wr, ISO2709_IDFS);
897 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
898 /* write dummy blank - makes MARC-8 to become ASCII */
899 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
902 wrbuf_putc(wr, ISO2709_FS);
904 case YAZ_MARC_CONTROLFIELD:
905 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
906 /* write dummy blank - makes MARC-8 to become ASCII */
907 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
909 wrbuf_putc(wr, ISO2709_FS);
911 case YAZ_MARC_COMMENT:
913 case YAZ_MARC_LEADER:
917 wrbuf_printf(wr, "%c", ISO2709_RS);
922 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
924 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
927 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
929 return -1; /* error */
930 return r; /* OK, return length > 0 */
933 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
934 char **result, int *rsize)
938 wrbuf_rewind(mt->m_wr);
939 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
941 *result = wrbuf_buf(mt->m_wr);
943 *rsize = wrbuf_len(mt->m_wr);
947 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
953 void yaz_marc_debug(yaz_marc_t mt, int level)
959 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
964 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
966 struct yaz_marc_node *n;
968 for (n = mt->nodes; n; n = n->next)
969 if (n->which == YAZ_MARC_LEADER)
971 leader = n->u.leader;
972 memcpy(leader+off, str, strlen(str));
978 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
980 yaz_marc_t mt = yaz_marc_create();
985 r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
986 yaz_marc_destroy(mt);
991 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
993 return yaz_marc_decode(buf, wr, debug, bsize, 0);
997 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
999 yaz_marc_t mt = yaz_marc_create();
1003 r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
1007 fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
1008 yaz_marc_destroy(mt);
1013 int marc_display_ex (const char *buf, FILE *outf, int debug)
1015 return marc_display_exl (buf, outf, debug, -1);
1019 int marc_display (const char *buf, FILE *outf)
1021 return marc_display_ex (buf, outf, 0);
1024 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
1026 xfree(mt->leader_spec);
1027 mt->leader_spec = 0;
1030 char dummy_leader[24];
1031 if (marc_exec_leader(leader_spec, dummy_leader, 24))
1033 mt->leader_spec = xstrdup(leader_spec);
1038 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1040 const char *cp = leader_spec;
1045 int no_read = 0, no = 0;
1047 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1048 if (no < 2 || no_read < 3)
1050 if (pos < 0 || pos >= size)
1055 const char *vp = strchr(val+1, '\'');
1061 if (len + pos > size)
1063 memcpy(leader + pos, val+1, len);
1065 else if (*val >= '0' && *val <= '9')
1081 int yaz_marc_decode_formatstr(const char *arg)
1084 if (!strcmp(arg, "marc"))
1085 mode = YAZ_MARC_ISO2709;
1086 if (!strcmp(arg, "marcxml"))
1087 mode = YAZ_MARC_MARCXML;
1088 if (!strcmp(arg, "marcxchange"))
1089 mode = YAZ_MARC_XCHANGE;
1090 if (!strcmp(arg, "line"))
1091 mode = YAZ_MARC_LINE;
1095 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1097 mt->write_using_libxml2 = enable;
1103 * indent-tabs-mode: nil
1105 * vim: shiftwidth=4 tabstop=8 expandtab