2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.48 2007-03-19 14:40:07 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)
134 size_t outbytesleft = sizeof(outbuf);
136 size_t r = yaz_iconv(mt->iconv_cd, 0, 0, &outp, &outbytesleft);
137 if (r != (size_t) (-1))
138 wrbuf_write(wr, outbuf, outp - outbuf);
142 static int marc_exec_leader(const char *leader_spec, char *leader,
146 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
148 struct yaz_marc_node *n = nmem_malloc(mt->nmem, sizeof(*n));
151 mt->nodes_pp = &n->next;
156 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
157 const xmlNode *ptr_data)
159 struct yaz_marc_node *n = yaz_marc_add_node(mt);
160 n->which = YAZ_MARC_CONTROLFIELD;
161 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
162 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
167 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
169 struct yaz_marc_node *n = yaz_marc_add_node(mt);
170 n->which = YAZ_MARC_COMMENT;
171 n->u.comment = nmem_strdup(mt->nmem, comment);
174 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
180 yaz_vsnprintf(buf, sizeof(buf)-1, fmt, ap);
181 yaz_marc_add_comment(mt, buf);
185 int yaz_marc_get_debug(yaz_marc_t mt)
190 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
192 struct yaz_marc_node *n = yaz_marc_add_node(mt);
193 n->which = YAZ_MARC_LEADER;
194 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
195 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
198 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
199 const char *data, size_t data_len)
201 struct yaz_marc_node *n = yaz_marc_add_node(mt);
202 n->which = YAZ_MARC_CONTROLFIELD;
203 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
204 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
210 sprintf(msg, "controlfield:");
211 for (i = 0; i < 16 && i < data_len; i++)
212 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
214 sprintf(msg + strlen(msg), " ..");
215 yaz_marc_add_comment(mt, msg);
219 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
220 const char *indicator, size_t indicator_len)
222 struct yaz_marc_node *n = yaz_marc_add_node(mt);
223 n->which = YAZ_MARC_DATAFIELD;
224 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
225 n->u.datafield.indicator =
226 nmem_strdupn(mt->nmem, indicator, indicator_len);
227 n->u.datafield.subfields = 0;
229 /* make subfield_pp the current (last one) */
230 mt->subfield_pp = &n->u.datafield.subfields;
234 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
235 const char *indicator, size_t indicator_len)
237 struct yaz_marc_node *n = yaz_marc_add_node(mt);
238 n->which = YAZ_MARC_DATAFIELD;
239 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
240 n->u.datafield.indicator =
241 nmem_strdupn(mt->nmem, indicator, indicator_len);
242 n->u.datafield.subfields = 0;
244 /* make subfield_pp the current (last one) */
245 mt->subfield_pp = &n->u.datafield.subfields;
249 void yaz_marc_add_subfield(yaz_marc_t mt,
250 const char *code_data, size_t code_data_len)
257 sprintf(msg, "subfield:");
258 for (i = 0; i < 16 && i < code_data_len; i++)
259 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
260 if (i < code_data_len)
261 sprintf(msg + strlen(msg), " ..");
262 yaz_marc_add_comment(mt, msg);
267 struct yaz_marc_subfield *n = nmem_malloc(mt->nmem, sizeof(*n));
268 n->code_data = nmem_strdupn(mt->nmem, code_data, code_data_len);
270 /* mark subfield_pp to point to this one, so we append here next */
271 *mt->subfield_pp = n;
272 mt->subfield_pp = &n->next;
276 int atoi_n_check(const char *buf, int size, int *val)
279 for (i = 0; i < size; i++)
280 if (!isdigit(i[(const unsigned char *) buf]))
282 *val = atoi_n(buf, size);
286 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
287 int *indicator_length,
288 int *identifier_length,
290 int *length_data_entry,
291 int *length_starting,
292 int *length_implementation)
296 memcpy(leader, leader_c, 24);
298 if (!atoi_n_check(leader+10, 1, indicator_length))
301 "Indicator length at offset 10 should hold a digit."
304 *indicator_length = 2;
306 if (!atoi_n_check(leader+11, 1, identifier_length))
309 "Identifier length at offset 11 should hold a digit."
312 *identifier_length = 2;
314 if (!atoi_n_check(leader+12, 5, base_address))
317 "Base address at offsets 12..16 should hold a number."
321 if (!atoi_n_check(leader+20, 1, length_data_entry))
324 "Length data entry at offset 20 should hold a digit."
326 *length_data_entry = 4;
329 if (!atoi_n_check(leader+21, 1, length_starting))
332 "Length starting at offset 21 should hold a digit."
334 *length_starting = 5;
337 if (!atoi_n_check(leader+22, 1, length_implementation))
340 "Length implementation at offset 22 should hold a digit."
342 *length_implementation = 0;
348 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
349 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
350 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
351 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
352 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
353 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
355 yaz_marc_add_leader(mt, leader, 24);
358 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
360 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
361 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
364 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
366 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
367 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
370 /* try to guess how many bytes the identifier really is! */
371 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
376 for (i = 1; i<5; i++)
379 size_t outbytesleft = sizeof(outbuf);
381 const char *inp = buf;
383 size_t inbytesleft = i;
384 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
385 &outp, &outbytesleft);
386 if (r != (size_t) (-1))
387 return i; /* got a complete sequence */
389 return 1; /* giving up */
391 return 1; /* we don't know */
394 void yaz_marc_reset(yaz_marc_t mt)
396 nmem_reset(mt->nmem);
398 mt->nodes_pp = &mt->nodes;
402 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
404 struct yaz_marc_node *n;
405 int identifier_length;
406 const char *leader = 0;
408 for (n = mt->nodes; n; n = n->next)
409 if (n->which == YAZ_MARC_LEADER)
411 leader = n->u.leader;
417 if (!atoi_n_check(leader+11, 1, &identifier_length))
420 for (n = mt->nodes; n; n = n->next)
424 case YAZ_MARC_COMMENT:
425 wrbuf_iconv_write(wr, mt->iconv_cd,
426 n->u.comment, strlen(n->u.comment));
427 wrbuf_puts(wr, ")\n");
437 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
439 struct yaz_marc_node *n;
440 int identifier_length;
441 const char *leader = 0;
443 for (n = mt->nodes; n; n = n->next)
444 if (n->which == YAZ_MARC_LEADER)
446 leader = n->u.leader;
452 if (!atoi_n_check(leader+11, 1, &identifier_length))
455 for (n = mt->nodes; n; n = n->next)
457 struct yaz_marc_subfield *s;
460 case YAZ_MARC_DATAFIELD:
461 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
462 n->u.datafield.indicator);
463 for (s = n->u.datafield.subfields; s; s = s->next)
465 /* if identifier length is 2 (most MARCs),
466 the code is a single character .. However we've
467 seen multibyte codes, so see how big it really is */
468 size_t using_code_len =
469 (identifier_length != 2) ? identifier_length - 1
471 cdata_one_character(mt, s->code_data);
473 wrbuf_puts (wr, mt->subfield_str);
474 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
476 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
477 wrbuf_iconv_puts(wr, mt->iconv_cd,
478 s->code_data + using_code_len);
479 marc_iconv_reset(mt, wr);
481 wrbuf_puts (wr, mt->endline_str);
483 case YAZ_MARC_CONTROLFIELD:
484 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
485 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
486 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
487 marc_iconv_reset(mt, wr);
488 wrbuf_puts (wr, mt->endline_str);
490 case YAZ_MARC_COMMENT:
492 wrbuf_iconv_write(wr, mt->iconv_cd,
493 n->u.comment, strlen(n->u.comment));
494 wrbuf_puts(wr, ")\n");
496 case YAZ_MARC_LEADER:
497 wrbuf_printf(wr, "%s\n", n->u.leader);
500 wrbuf_puts(wr, "\n");
504 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
509 return yaz_marc_write_line(mt, wr);
510 case YAZ_MARC_MARCXML:
511 return yaz_marc_write_marcxml(mt, wr);
512 case YAZ_MARC_XCHANGE:
513 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
514 case YAZ_MARC_ISO2709:
515 return yaz_marc_write_iso2709(mt, wr);
517 return yaz_marc_write_check(mt, wr);
522 /** \brief common MARC XML/Xchange writer
524 \param wr WRBUF output
525 \param ns XMLNS for the elements
526 \param format record format (e.g. "MARC21")
527 \param type record type (e.g. "Bibliographic")
529 static int yaz_marc_write_marcxml_ns1(yaz_marc_t mt, WRBUF wr,
534 struct yaz_marc_node *n;
535 int identifier_length;
536 const char *leader = 0;
538 for (n = mt->nodes; n; n = n->next)
539 if (n->which == YAZ_MARC_LEADER)
541 leader = n->u.leader;
547 if (!atoi_n_check(leader+11, 1, &identifier_length))
550 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
552 wrbuf_printf(wr, " format=\"%.80s\"", format);
554 wrbuf_printf(wr, " type=\"%.80s\"", type);
555 wrbuf_printf(wr, ">\n");
556 for (n = mt->nodes; n; n = n->next)
558 struct yaz_marc_subfield *s;
562 case YAZ_MARC_DATAFIELD:
563 wrbuf_printf(wr, " <datafield tag=\"");
564 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
565 strlen(n->u.datafield.tag));
566 wrbuf_printf(wr, "\"");
567 if (n->u.datafield.indicator)
570 for (i = 0; n->u.datafield.indicator[i]; i++)
572 wrbuf_printf(wr, " ind%d=\"", i+1);
573 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
574 n->u.datafield.indicator+i, 1);
575 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
578 wrbuf_printf(wr, ">\n");
579 for (s = n->u.datafield.subfields; s; s = s->next)
581 /* if identifier length is 2 (most MARCs),
582 the code is a single character .. However we've
583 seen multibyte codes, so see how big it really is */
584 size_t using_code_len =
585 (identifier_length != 2) ? identifier_length - 1
587 cdata_one_character(mt, s->code_data);
589 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
590 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
591 s->code_data, using_code_len);
592 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
593 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
594 s->code_data + using_code_len,
595 strlen(s->code_data + using_code_len));
596 marc_iconv_reset(mt, wr);
597 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
598 wrbuf_puts(wr, "\n");
600 wrbuf_printf(wr, " </datafield>\n");
602 case YAZ_MARC_CONTROLFIELD:
603 wrbuf_printf(wr, " <controlfield tag=\"");
604 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
605 strlen(n->u.controlfield.tag));
606 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
607 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
609 marc_iconv_reset(mt, wr);
610 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
611 wrbuf_puts(wr, "\n");
613 case YAZ_MARC_COMMENT:
614 wrbuf_printf(wr, "<!-- ");
615 wrbuf_puts(wr, n->u.comment);
616 wrbuf_printf(wr, " -->\n");
618 case YAZ_MARC_LEADER:
619 wrbuf_printf(wr, " <leader>");
620 wrbuf_iconv_write_cdata(wr,
621 0 /* no charset conversion for leader */,
622 n->u.leader, strlen(n->u.leader));
623 wrbuf_printf(wr, "</leader>\n");
626 wrbuf_puts(wr, "</record>\n");
630 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
635 if (mt->write_using_libxml2)
641 ret = yaz_marc_write_xml(mt, &root_ptr, ns, format, type);
645 xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
648 xmlDocSetRootElement(doc, root_ptr);
649 xmlDocDumpMemory(doc, &buf_out, &len_out);
651 wrbuf_write(wr, (const char *) buf_out, len_out);
662 return yaz_marc_write_marcxml_ns1(mt, wr, ns, format, type);
665 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
667 if (!mt->leader_spec)
668 yaz_marc_modify_leader(mt, 9, "a");
669 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
673 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
677 return yaz_marc_write_marcxml_ns(mt, wr,
678 "http://www.bs.dk/standards/MarcXchange",
683 int yaz_marc_write_xml(yaz_marc_t mt, xmlNode **root_ptr,
689 struct yaz_marc_node *n;
690 int identifier_length;
691 const char *leader = 0;
696 for (n = mt->nodes; n; n = n->next)
697 if (n->which == YAZ_MARC_LEADER)
699 leader = n->u.leader;
705 if (!atoi_n_check(leader+11, 1, &identifier_length))
708 wr_cdata = wrbuf_alloc();
710 record_ptr = xmlNewNode(0, BAD_CAST "record");
711 *root_ptr = record_ptr;
713 ns_record = xmlNewNs(record_ptr, BAD_CAST ns, 0);
714 xmlSetNs(record_ptr, ns_record);
717 xmlNewProp(record_ptr, BAD_CAST "format", BAD_CAST format);
719 xmlNewProp(record_ptr, BAD_CAST "type", BAD_CAST type);
720 for (n = mt->nodes; n; n = n->next)
722 struct yaz_marc_subfield *s;
727 case YAZ_MARC_DATAFIELD:
728 ptr = xmlNewChild(record_ptr, ns_record, BAD_CAST "datafield", 0);
729 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.datafield.tag);
730 if (n->u.datafield.indicator)
733 for (i = 0; n->u.datafield.indicator[i]; i++)
738 sprintf(ind_str, "ind%d", i+1);
739 ind_val[0] = n->u.datafield.indicator[i];
741 xmlNewProp(ptr, BAD_CAST ind_str, BAD_CAST ind_val);
744 for (s = n->u.datafield.subfields; s; s = s->next)
746 xmlNode *ptr_subfield;
747 /* if identifier length is 2 (most MARCs),
748 the code is a single character .. However we've
749 seen multibyte codes, so see how big it really is */
750 size_t using_code_len =
751 (identifier_length != 2) ? identifier_length - 1
753 cdata_one_character(mt, s->code_data);
755 wrbuf_rewind(wr_cdata);
756 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd,
757 s->code_data + using_code_len);
758 marc_iconv_reset(mt, wr_cdata);
759 ptr_subfield = xmlNewTextChild(
761 BAD_CAST "subfield", BAD_CAST wrbuf_cstr(wr_cdata));
763 wrbuf_rewind(wr_cdata);
764 wrbuf_iconv_write(wr_cdata, mt->iconv_cd,
765 s->code_data, using_code_len);
766 xmlNewProp(ptr_subfield, BAD_CAST "code",
767 BAD_CAST wrbuf_cstr(wr_cdata));
770 case YAZ_MARC_CONTROLFIELD:
771 wrbuf_rewind(wr_cdata);
772 wrbuf_iconv_puts(wr_cdata, mt->iconv_cd, n->u.controlfield.data);
773 marc_iconv_reset(mt, wr_cdata);
775 ptr = xmlNewTextChild(record_ptr, ns_record,
776 BAD_CAST "controlfield",
777 BAD_CAST wrbuf_cstr(wr_cdata));
779 xmlNewProp(ptr, BAD_CAST "tag", BAD_CAST n->u.controlfield.tag);
781 case YAZ_MARC_COMMENT:
782 ptr = xmlNewComment(BAD_CAST n->u.comment);
783 xmlAddChild(record_ptr, ptr);
785 case YAZ_MARC_LEADER:
786 xmlNewTextChild(record_ptr, ns_record, BAD_CAST "leader",
787 BAD_CAST n->u.leader);
791 wrbuf_destroy(wr_cdata);
798 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
800 struct yaz_marc_node *n;
801 int indicator_length;
802 int identifier_length;
803 int length_data_entry;
805 int length_implementation;
807 const char *leader = 0;
808 WRBUF wr_dir, wr_head, wr_data_tmp;
811 for (n = mt->nodes; n; n = n->next)
812 if (n->which == YAZ_MARC_LEADER)
813 leader = n->u.leader;
817 if (!atoi_n_check(leader+10, 1, &indicator_length))
819 if (!atoi_n_check(leader+11, 1, &identifier_length))
821 if (!atoi_n_check(leader+20, 1, &length_data_entry))
823 if (!atoi_n_check(leader+21, 1, &length_starting))
825 if (!atoi_n_check(leader+22, 1, &length_implementation))
828 wr_data_tmp = wrbuf_alloc();
829 wr_dir = wrbuf_alloc();
830 for (n = mt->nodes; n; n = n->next)
833 struct yaz_marc_subfield *s;
837 case YAZ_MARC_DATAFIELD:
838 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
839 data_length += indicator_length;
840 wrbuf_rewind(wr_data_tmp);
841 for (s = n->u.datafield.subfields; s; s = s->next)
843 /* write dummy IDFS + content */
844 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
845 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
846 marc_iconv_reset(mt, wr_data_tmp);
848 /* write dummy FS (makes MARC-8 to become ASCII) */
849 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
850 data_length += wrbuf_len(wr_data_tmp);
852 case YAZ_MARC_CONTROLFIELD:
853 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
855 wrbuf_rewind(wr_data_tmp);
856 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
857 n->u.controlfield.data);
858 marc_iconv_reset(mt, wr_data_tmp);
859 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
860 data_length += wrbuf_len(wr_data_tmp);
862 case YAZ_MARC_COMMENT:
864 case YAZ_MARC_LEADER:
869 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
870 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
871 data_offset += data_length;
874 /* mark end of directory */
875 wrbuf_putc(wr_dir, ISO2709_FS);
877 /* base address of data (comes after leader+directory) */
878 base_address = 24 + wrbuf_len(wr_dir);
880 wr_head = wrbuf_alloc();
882 /* write record length */
883 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
884 /* from "original" leader */
885 wrbuf_write(wr_head, leader+5, 7);
886 /* base address of data */
887 wrbuf_printf(wr_head, "%05d", base_address);
888 /* from "original" leader */
889 wrbuf_write(wr_head, leader+17, 7);
891 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
892 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
893 wrbuf_destroy(wr_head);
894 wrbuf_destroy(wr_dir);
895 wrbuf_destroy(wr_data_tmp);
897 for (n = mt->nodes; n; n = n->next)
899 struct yaz_marc_subfield *s;
903 case YAZ_MARC_DATAFIELD:
904 wrbuf_printf(wr, "%.*s", indicator_length,
905 n->u.datafield.indicator);
906 for (s = n->u.datafield.subfields; s; s = s->next)
908 wrbuf_putc(wr, ISO2709_IDFS);
909 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
910 marc_iconv_reset(mt, wr);
912 wrbuf_putc(wr, ISO2709_FS);
914 case YAZ_MARC_CONTROLFIELD:
915 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
916 marc_iconv_reset(mt, wr);
917 wrbuf_putc(wr, ISO2709_FS);
919 case YAZ_MARC_COMMENT:
921 case YAZ_MARC_LEADER:
925 wrbuf_printf(wr, "%c", ISO2709_RS);
930 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
932 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
935 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
937 return -1; /* error */
938 return r; /* OK, return length > 0 */
941 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
942 const char **result, size_t *rsize)
946 wrbuf_rewind(mt->m_wr);
947 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
949 *result = wrbuf_cstr(mt->m_wr);
951 *rsize = wrbuf_len(mt->m_wr);
955 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
961 void yaz_marc_debug(yaz_marc_t mt, int level)
967 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
972 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
974 struct yaz_marc_node *n;
976 for (n = mt->nodes; n; n = n->next)
977 if (n->which == YAZ_MARC_LEADER)
979 leader = n->u.leader;
980 memcpy(leader+off, str, strlen(str));
985 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
987 xfree(mt->leader_spec);
991 char dummy_leader[24];
992 if (marc_exec_leader(leader_spec, dummy_leader, 24))
994 mt->leader_spec = xstrdup(leader_spec);
999 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
1001 const char *cp = leader_spec;
1006 int no_read = 0, no = 0;
1008 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
1009 if (no < 2 || no_read < 3)
1011 if (pos < 0 || pos >= size)
1016 const char *vp = strchr(val+1, '\'');
1022 if (len + pos > size)
1024 memcpy(leader + pos, val+1, len);
1026 else if (*val >= '0' && *val <= '9')
1042 int yaz_marc_decode_formatstr(const char *arg)
1045 if (!strcmp(arg, "marc"))
1046 mode = YAZ_MARC_ISO2709;
1047 if (!strcmp(arg, "marcxml"))
1048 mode = YAZ_MARC_MARCXML;
1049 if (!strcmp(arg, "marcxchange"))
1050 mode = YAZ_MARC_XCHANGE;
1051 if (!strcmp(arg, "line"))
1052 mode = YAZ_MARC_LINE;
1056 void yaz_marc_write_using_libxml2(yaz_marc_t mt, int enable)
1058 mt->write_using_libxml2 = enable;
1064 * indent-tabs-mode: nil
1066 * vim: shiftwidth=4 tabstop=8 expandtab