2 * Copyright (C) 1995-2006, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marcdisp.c,v 1.38 2006-12-15 12:37:18 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 */
90 struct yaz_marc_node *nodes;
91 struct yaz_marc_node **nodes_pp;
92 struct yaz_marc_subfield **subfield_pp;
95 yaz_marc_t yaz_marc_create(void)
97 yaz_marc_t mt = (yaz_marc_t) xmalloc(sizeof(*mt));
98 mt->xml = YAZ_MARC_LINE;
100 mt->m_wr = wrbuf_alloc();
103 strcpy(mt->subfield_str, " $");
104 strcpy(mt->endline_str, "\n");
106 mt->nmem = nmem_create();
111 void yaz_marc_destroy(yaz_marc_t mt)
115 nmem_destroy(mt->nmem);
116 wrbuf_free(mt->m_wr, 1);
117 xfree(mt->leader_spec);
121 NMEM yaz_marc_get_nmem(yaz_marc_t mt)
126 static int marc_exec_leader(const char *leader_spec, char *leader,
130 static struct yaz_marc_node *yaz_marc_add_node(yaz_marc_t mt)
132 struct yaz_marc_node *n = nmem_malloc(mt->nmem, sizeof(*n));
135 mt->nodes_pp = &n->next;
140 void yaz_marc_add_controlfield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
141 const xmlNode *ptr_data)
143 struct yaz_marc_node *n = yaz_marc_add_node(mt);
144 n->which = YAZ_MARC_CONTROLFIELD;
145 n->u.controlfield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
146 n->u.controlfield.data = nmem_text_node_cdata(ptr_data, mt->nmem);
151 void yaz_marc_add_comment(yaz_marc_t mt, char *comment)
153 struct yaz_marc_node *n = yaz_marc_add_node(mt);
154 n->which = YAZ_MARC_COMMENT;
155 n->u.comment = nmem_strdup(mt->nmem, comment);
158 void yaz_marc_cprintf(yaz_marc_t mt, const char *fmt, ...)
165 _vsnprintf(buf, sizeof(buf)-1, fmt, ap);
169 vsnprintf(buf, sizeof(buf), fmt, ap);
171 vsprintf(buf, fmt, ap);
175 yaz_marc_add_comment(mt, buf);
179 int yaz_marc_get_debug(yaz_marc_t mt)
184 void yaz_marc_add_leader(yaz_marc_t mt, const char *leader, size_t leader_len)
186 struct yaz_marc_node *n = yaz_marc_add_node(mt);
187 n->which = YAZ_MARC_LEADER;
188 n->u.leader = nmem_strdupn(mt->nmem, leader, leader_len);
189 marc_exec_leader(mt->leader_spec, n->u.leader, leader_len);
192 void yaz_marc_add_controlfield(yaz_marc_t mt, const char *tag,
193 const char *data, size_t data_len)
195 struct yaz_marc_node *n = yaz_marc_add_node(mt);
196 n->which = YAZ_MARC_CONTROLFIELD;
197 n->u.controlfield.tag = nmem_strdup(mt->nmem, tag);
198 n->u.controlfield.data = nmem_strdupn(mt->nmem, data, data_len);
204 sprintf(msg, "controlfield:");
205 for (i = 0; i < 16 && i < data_len; i++)
206 sprintf(msg + strlen(msg), " %02X", data[i] & 0xff);
208 sprintf(msg + strlen(msg), " ..");
209 yaz_marc_add_comment(mt, msg);
213 void yaz_marc_add_datafield(yaz_marc_t mt, const char *tag,
214 const char *indicator, size_t indicator_len)
216 struct yaz_marc_node *n = yaz_marc_add_node(mt);
217 n->which = YAZ_MARC_DATAFIELD;
218 n->u.datafield.tag = nmem_strdup(mt->nmem, tag);
219 n->u.datafield.indicator =
220 nmem_strdupn(mt->nmem, indicator, indicator_len);
221 n->u.datafield.subfields = 0;
223 /* make subfield_pp the current (last one) */
224 mt->subfield_pp = &n->u.datafield.subfields;
228 void yaz_marc_add_datafield_xml(yaz_marc_t mt, const xmlNode *ptr_tag,
229 const char *indicator, size_t indicator_len)
231 struct yaz_marc_node *n = yaz_marc_add_node(mt);
232 n->which = YAZ_MARC_DATAFIELD;
233 n->u.datafield.tag = nmem_text_node_cdata(ptr_tag, mt->nmem);
234 n->u.datafield.indicator =
235 nmem_strdupn(mt->nmem, indicator, indicator_len);
236 n->u.datafield.subfields = 0;
238 /* make subfield_pp the current (last one) */
239 mt->subfield_pp = &n->u.datafield.subfields;
243 void yaz_marc_add_subfield(yaz_marc_t mt,
244 const char *code_data, size_t code_data_len)
251 sprintf(msg, "subfield:");
252 for (i = 0; i < 16 && i < code_data_len; i++)
253 sprintf(msg + strlen(msg), " %02X", code_data[i] & 0xff);
254 if (i < code_data_len)
255 sprintf(msg + strlen(msg), " ..");
256 yaz_marc_add_comment(mt, msg);
261 struct yaz_marc_subfield *n = 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 static int atoi_n_check(const char *buf, int size, int *val)
272 if (!isdigit(*(const unsigned char *) buf))
274 *val = atoi_n(buf, size);
278 void yaz_marc_set_leader(yaz_marc_t mt, const char *leader_c,
279 int *indicator_length,
280 int *identifier_length,
282 int *length_data_entry,
283 int *length_starting,
284 int *length_implementation)
288 memcpy(leader, leader_c, 24);
290 if (!atoi_n_check(leader+10, 1, indicator_length))
293 "Indicator length at offset 10 should hold a digit."
296 *indicator_length = 2;
298 if (!atoi_n_check(leader+11, 1, identifier_length))
301 "Identifier length at offset 11 should hold a digit."
304 *identifier_length = 2;
306 if (!atoi_n_check(leader+12, 5, base_address))
309 "Base address at offsets 12..16 should hold a number."
313 if (!atoi_n_check(leader+20, 1, length_data_entry))
316 "Length data entry at offset 20 should hold a digit."
318 *length_data_entry = 4;
321 if (!atoi_n_check(leader+21, 1, length_starting))
324 "Length starting at offset 21 should hold a digit."
326 *length_starting = 5;
329 if (!atoi_n_check(leader+22, 1, length_implementation))
332 "Length implementation at offset 22 should hold a digit."
334 *length_implementation = 0;
340 yaz_marc_cprintf(mt, "Indicator length %5d", *indicator_length);
341 yaz_marc_cprintf(mt, "Identifier length %5d", *identifier_length);
342 yaz_marc_cprintf(mt, "Base address %5d", *base_address);
343 yaz_marc_cprintf(mt, "Length data entry %5d", *length_data_entry);
344 yaz_marc_cprintf(mt, "Length starting %5d", *length_starting);
345 yaz_marc_cprintf(mt, "Length implementation %5d", *length_implementation);
347 yaz_marc_add_leader(mt, leader, 24);
350 void yaz_marc_subfield_str(yaz_marc_t mt, const char *s)
352 strncpy(mt->subfield_str, s, sizeof(mt->subfield_str)-1);
353 mt->subfield_str[sizeof(mt->subfield_str)-1] = '\0';
356 void yaz_marc_endline_str(yaz_marc_t mt, const char *s)
358 strncpy(mt->endline_str, s, sizeof(mt->endline_str)-1);
359 mt->endline_str[sizeof(mt->endline_str)-1] = '\0';
362 /* try to guess how many bytes the identifier really is! */
363 static size_t cdata_one_character(yaz_marc_t mt, const char *buf)
368 for (i = 1; i<5; i++)
371 size_t outbytesleft = sizeof(outbuf);
373 const char *inp = buf;
375 size_t inbytesleft = i;
376 size_t r = yaz_iconv(mt->iconv_cd, (char**) &inp, &inbytesleft,
377 &outp, &outbytesleft);
378 if (r != (size_t) (-1))
379 return i; /* got a complete sequence */
381 return 1; /* giving up */
383 return 1; /* we don't know */
386 void yaz_marc_reset(yaz_marc_t mt)
388 nmem_reset(mt->nmem);
390 mt->nodes_pp = &mt->nodes;
394 int yaz_marc_write_check(yaz_marc_t mt, WRBUF wr)
396 struct yaz_marc_node *n;
397 int identifier_length;
398 const char *leader = 0;
400 for (n = mt->nodes; n; n = n->next)
401 if (n->which == YAZ_MARC_LEADER)
403 leader = n->u.leader;
409 if (!atoi_n_check(leader+11, 1, &identifier_length))
412 for (n = mt->nodes; n; n = n->next)
416 case YAZ_MARC_COMMENT:
417 wrbuf_iconv_write(wr, mt->iconv_cd,
418 n->u.comment, strlen(n->u.comment));
419 wrbuf_puts(wr, ")\n");
429 int yaz_marc_write_line(yaz_marc_t mt, WRBUF wr)
431 struct yaz_marc_node *n;
432 int identifier_length;
433 const char *leader = 0;
435 for (n = mt->nodes; n; n = n->next)
436 if (n->which == YAZ_MARC_LEADER)
438 leader = n->u.leader;
444 if (!atoi_n_check(leader+11, 1, &identifier_length))
447 for (n = mt->nodes; n; n = n->next)
449 struct yaz_marc_subfield *s;
452 case YAZ_MARC_DATAFIELD:
453 wrbuf_printf(wr, "%s %s", n->u.datafield.tag,
454 n->u.datafield.indicator);
455 for (s = n->u.datafield.subfields; s; s = s->next)
457 /* if identifier length is 2 (most MARCs),
458 the code is a single character .. However we've
459 seen multibyte codes, so see how big it really is */
460 size_t using_code_len =
461 (identifier_length != 2) ? identifier_length - 1
463 cdata_one_character(mt, s->code_data);
465 wrbuf_puts (wr, mt->subfield_str);
466 wrbuf_iconv_write(wr, mt->iconv_cd, s->code_data,
468 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
469 wrbuf_iconv_puts(wr, mt->iconv_cd,
470 s->code_data + using_code_len);
471 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
474 wrbuf_puts (wr, mt->endline_str);
476 case YAZ_MARC_CONTROLFIELD:
477 wrbuf_printf(wr, "%s", n->u.controlfield.tag);
478 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
479 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
480 wrbuf_iconv_puts(wr, mt->iconv_cd, " ");
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 wrbuf_puts(wr, ")\n");
490 case YAZ_MARC_LEADER:
491 wrbuf_printf(wr, "%s\n", n->u.leader);
497 int yaz_marc_write_mode(yaz_marc_t mt, WRBUF wr)
502 return yaz_marc_write_line(mt, wr);
503 case YAZ_MARC_MARCXML:
504 return yaz_marc_write_marcxml(mt, wr);
505 case YAZ_MARC_XCHANGE:
506 return yaz_marc_write_marcxchange(mt, wr, 0, 0); /* no format, type */
507 case YAZ_MARC_ISO2709:
508 return yaz_marc_write_iso2709(mt, wr);
510 return yaz_marc_write_check(mt, wr);
515 /** \brief common MARC XML/Xchange writer
517 \param wr WRBUF output
518 \param ns XMLNS for the elements
519 \param format record format (e.g. "MARC21")
520 \param type record type (e.g. "Bibliographic")
522 static int yaz_marc_write_marcxml_ns(yaz_marc_t mt, WRBUF wr,
527 struct yaz_marc_node *n;
528 int identifier_length;
529 const char *leader = 0;
531 for (n = mt->nodes; n; n = n->next)
532 if (n->which == YAZ_MARC_LEADER)
534 leader = n->u.leader;
540 if (!atoi_n_check(leader+11, 1, &identifier_length))
543 wrbuf_printf(wr, "<record xmlns=\"%s\"", ns);
545 wrbuf_printf(wr, " format=\"%.80s\"", format);
547 wrbuf_printf(wr, " type=\"%.80s\"", type);
548 wrbuf_printf(wr, ">\n");
549 for (n = mt->nodes; n; n = n->next)
551 struct yaz_marc_subfield *s;
555 case YAZ_MARC_DATAFIELD:
556 wrbuf_printf(wr, " <datafield tag=\"");
557 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.datafield.tag,
558 strlen(n->u.datafield.tag));
559 wrbuf_printf(wr, "\"");
560 if (n->u.datafield.indicator)
563 for (i = 0; n->u.datafield.indicator[i]; i++)
565 wrbuf_printf(wr, " ind%d=\"", i+1);
566 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
567 n->u.datafield.indicator+i, 1);
568 wrbuf_iconv_puts(wr, mt->iconv_cd, "\"");
571 wrbuf_printf(wr, ">\n");
572 for (s = n->u.datafield.subfields; s; s = s->next)
574 /* if identifier length is 2 (most MARCs),
575 the code is a single character .. However we've
576 seen multibyte codes, so see how big it really is */
577 size_t using_code_len =
578 (identifier_length != 2) ? identifier_length - 1
580 cdata_one_character(mt, s->code_data);
582 wrbuf_iconv_puts(wr, mt->iconv_cd, " <subfield code=\"");
583 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
584 s->code_data, using_code_len);
585 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
586 wrbuf_iconv_write_cdata(wr, mt->iconv_cd,
587 s->code_data + using_code_len,
588 strlen(s->code_data + using_code_len));
589 wrbuf_iconv_puts(wr, mt->iconv_cd, "</subfield>");
590 wrbuf_puts(wr, "\n");
592 wrbuf_printf(wr, " </datafield>\n");
594 case YAZ_MARC_CONTROLFIELD:
595 wrbuf_printf(wr, " <controlfield tag=\"");
596 wrbuf_iconv_write_cdata(wr, mt->iconv_cd, n->u.controlfield.tag,
597 strlen(n->u.controlfield.tag));
598 wrbuf_iconv_puts(wr, mt->iconv_cd, "\">");
599 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
600 wrbuf_iconv_puts(wr, mt->iconv_cd, "</controlfield>");
601 wrbuf_puts(wr, "\n");
603 case YAZ_MARC_COMMENT:
604 wrbuf_printf(wr, "<!-- ");
605 wrbuf_puts(wr, n->u.comment);
606 wrbuf_printf(wr, " -->\n");
608 case YAZ_MARC_LEADER:
609 wrbuf_printf(wr, " <leader>");
610 wrbuf_iconv_write_cdata(wr,
611 0 /* no charset conversion for leader */,
612 n->u.leader, strlen(n->u.leader));
613 wrbuf_printf(wr, "</leader>\n");
616 wrbuf_puts(wr, "</record>\n");
620 int yaz_marc_write_marcxml(yaz_marc_t mt, WRBUF wr)
622 if (!mt->leader_spec)
623 yaz_marc_modify_leader(mt, 9, "a");
624 return yaz_marc_write_marcxml_ns(mt, wr, "http://www.loc.gov/MARC21/slim",
628 int yaz_marc_write_marcxchange(yaz_marc_t mt, WRBUF wr,
632 return yaz_marc_write_marcxml_ns(mt, wr,
633 "http://www.bs.dk/standards/MarcXchange",
637 int yaz_marc_write_iso2709(yaz_marc_t mt, WRBUF wr)
639 struct yaz_marc_node *n;
640 int indicator_length;
641 int identifier_length;
642 int length_data_entry;
644 int length_implementation;
646 const char *leader = 0;
647 WRBUF wr_dir, wr_head, wr_data_tmp;
650 for (n = mt->nodes; n; n = n->next)
651 if (n->which == YAZ_MARC_LEADER)
652 leader = n->u.leader;
656 if (!atoi_n_check(leader+10, 1, &indicator_length))
658 if (!atoi_n_check(leader+11, 1, &identifier_length))
660 if (!atoi_n_check(leader+20, 1, &length_data_entry))
662 if (!atoi_n_check(leader+21, 1, &length_starting))
664 if (!atoi_n_check(leader+22, 1, &length_implementation))
667 wr_data_tmp = wrbuf_alloc();
668 wr_dir = wrbuf_alloc();
669 for (n = mt->nodes; n; n = n->next)
672 struct yaz_marc_subfield *s;
676 case YAZ_MARC_DATAFIELD:
677 wrbuf_printf(wr_dir, "%.3s", n->u.datafield.tag);
678 data_length += indicator_length;
679 wrbuf_rewind(wr_data_tmp);
680 for (s = n->u.datafield.subfields; s; s = s->next)
682 /* write dummy IDFS + content */
683 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
684 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd, s->code_data);
686 /* write dummy FS (makes MARC-8 to become ASCII) */
687 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');
688 data_length += wrbuf_len(wr_data_tmp);
690 case YAZ_MARC_CONTROLFIELD:
691 wrbuf_printf(wr_dir, "%.3s", n->u.controlfield.tag);
693 wrbuf_rewind(wr_data_tmp);
694 wrbuf_iconv_puts(wr_data_tmp, mt->iconv_cd,
695 n->u.controlfield.data);
696 wrbuf_iconv_putchar(wr_data_tmp, mt->iconv_cd, ' ');/* field sep */
697 data_length += wrbuf_len(wr_data_tmp);
699 case YAZ_MARC_COMMENT:
701 case YAZ_MARC_LEADER:
706 wrbuf_printf(wr_dir, "%0*d", length_data_entry, data_length);
707 wrbuf_printf(wr_dir, "%0*d", length_starting, data_offset);
708 data_offset += data_length;
711 /* mark end of directory */
712 wrbuf_putc(wr_dir, ISO2709_FS);
714 /* base address of data (comes after leader+directory) */
715 base_address = 24 + wrbuf_len(wr_dir);
717 wr_head = wrbuf_alloc();
719 /* write record length */
720 wrbuf_printf(wr_head, "%05d", base_address + data_offset + 1);
721 /* from "original" leader */
722 wrbuf_write(wr_head, leader+5, 7);
723 /* base address of data */
724 wrbuf_printf(wr_head, "%05d", base_address);
725 /* from "original" leader */
726 wrbuf_write(wr_head, leader+17, 7);
728 wrbuf_write(wr, wrbuf_buf(wr_head), 24);
729 wrbuf_write(wr, wrbuf_buf(wr_dir), wrbuf_len(wr_dir));
730 wrbuf_free(wr_head, 1);
731 wrbuf_free(wr_dir, 1);
732 wrbuf_free(wr_data_tmp, 1);
734 for (n = mt->nodes; n; n = n->next)
736 struct yaz_marc_subfield *s;
740 case YAZ_MARC_DATAFIELD:
741 wrbuf_printf(wr, "%.*s", indicator_length,
742 n->u.datafield.indicator);
743 for (s = n->u.datafield.subfields; s; s = s->next)
745 wrbuf_putc(wr, ISO2709_IDFS);
746 wrbuf_iconv_puts(wr, mt->iconv_cd, s->code_data);
747 /* write dummy blank - makes MARC-8 to become ASCII */
748 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
751 wrbuf_putc(wr, ISO2709_FS);
753 case YAZ_MARC_CONTROLFIELD:
754 wrbuf_iconv_puts(wr, mt->iconv_cd, n->u.controlfield.data);
755 /* write dummy blank - makes MARC-8 to become ASCII */
756 wrbuf_iconv_putchar(wr, mt->iconv_cd, ' ');
758 wrbuf_putc(wr, ISO2709_FS);
760 case YAZ_MARC_COMMENT:
762 case YAZ_MARC_LEADER:
766 wrbuf_printf(wr, "%c", ISO2709_RS);
771 int yaz_marc_decode_wrbuf(yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
773 int s, r = yaz_marc_read_iso2709(mt, buf, bsize);
776 s = yaz_marc_write_mode(mt, wr); /* returns 0 for OK, -1 otherwise */
778 return -1; /* error */
779 return r; /* OK, return length > 0 */
782 int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
783 char **result, int *rsize)
787 wrbuf_rewind(mt->m_wr);
788 r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
790 *result = wrbuf_buf(mt->m_wr);
792 *rsize = wrbuf_len(mt->m_wr);
796 void yaz_marc_xml(yaz_marc_t mt, int xmlmode)
802 void yaz_marc_debug(yaz_marc_t mt, int level)
808 void yaz_marc_iconv(yaz_marc_t mt, yaz_iconv_t cd)
813 void yaz_marc_modify_leader(yaz_marc_t mt, size_t off, const char *str)
815 struct yaz_marc_node *n;
817 for (n = mt->nodes; n; n = n->next)
818 if (n->which == YAZ_MARC_LEADER)
820 leader = n->u.leader;
821 memcpy(leader+off, str, strlen(str));
827 int yaz_marc_decode(const char *buf, WRBUF wr, int debug, int bsize, int xml)
829 yaz_marc_t mt = yaz_marc_create();
834 r = yaz_marc_decode_wrbuf(mt, buf, bsize, wr);
835 yaz_marc_destroy(mt);
840 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug, int bsize)
842 return yaz_marc_decode(buf, wr, debug, bsize, 0);
846 int marc_display_exl (const char *buf, FILE *outf, int debug, int bsize)
848 yaz_marc_t mt = yaz_marc_create();
852 r = yaz_marc_decode_wrbuf (mt, buf, bsize, mt->m_wr);
856 fwrite (wrbuf_buf(mt->m_wr), 1, wrbuf_len(mt->m_wr), outf);
857 yaz_marc_destroy(mt);
862 int marc_display_ex (const char *buf, FILE *outf, int debug)
864 return marc_display_exl (buf, outf, debug, -1);
868 int marc_display (const char *buf, FILE *outf)
870 return marc_display_ex (buf, outf, 0);
873 int yaz_marc_leader_spec(yaz_marc_t mt, const char *leader_spec)
875 xfree(mt->leader_spec);
879 char dummy_leader[24];
880 if (marc_exec_leader(leader_spec, dummy_leader, 24))
882 mt->leader_spec = xstrdup(leader_spec);
887 static int marc_exec_leader(const char *leader_spec, char *leader, size_t size)
889 const char *cp = leader_spec;
894 int no_read = 0, no = 0;
896 no = sscanf(cp, "%d=%20[^,]%n", &pos, val, &no_read);
897 if (no < 2 || no_read < 3)
899 if (pos < 0 || pos >= size)
904 const char *vp = strchr(val+1, '\'');
910 if (len + pos > size)
912 memcpy(leader + pos, val+1, len);
914 else if (*val >= '0' && *val <= '9')
933 * indent-tabs-mode: nil
935 * vim: shiftwidth=4 tabstop=8 expandtab